コード例 #1
0
ファイル: empathy-avatar-image.c プロジェクト: GNOME/empathy
static gboolean
avatar_image_button_press_event (GtkWidget *widget, GdkEventButton *event)
{
	EmpathyAvatarImagePriv *priv;
	GtkWidget             *popup;
	GtkWidget             *frame;
	GtkWidget             *image;
	gint                   x, y;
	gint                   popup_width, popup_height;
	gint                   width, height;
	GdkPixbuf             *pixbuf;
	GtkAllocation          allocation;

	priv = GET_PRIV (widget);

	if (priv->popup) {
		gtk_widget_destroy (priv->popup);
		priv->popup = NULL;
	}

	if (event->button != 1 || event->type != GDK_BUTTON_PRESS || !priv->pixbuf) {
		return FALSE;
	}

	popup_width = gdk_pixbuf_get_width (priv->pixbuf);
	popup_height = gdk_pixbuf_get_height (priv->pixbuf);

	gtk_widget_get_allocation (priv->image, &allocation);
	width = allocation.width;
	height = allocation.height;

	/* Don't show a popup if the popup is smaller then the currently avatar
	 * image.
	 */
	if (popup_height <= height && popup_width <= width) {
		return TRUE;
	}

	pixbuf = tpaw_pixbuf_scale_down_if_necessary (priv->pixbuf, MAX_LARGE);
	popup_width = gdk_pixbuf_get_width (pixbuf);
	popup_height = gdk_pixbuf_get_height (pixbuf);

	popup = gtk_window_new (GTK_WINDOW_POPUP);

	frame = gtk_frame_new (NULL);
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);

	gtk_container_add (GTK_CONTAINER (popup), frame);

	image = gtk_image_new ();
	gtk_container_add (GTK_CONTAINER (frame), image);

	gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
	g_object_unref (pixbuf);

	gdk_window_get_origin (gtk_widget_get_window (priv->image), &x, &y);

	x = x - (popup_width - width) / 2;
	y = y - (popup_height - height) / 2;

	gtk_window_move (GTK_WINDOW (popup), x, y);

	priv->popup = popup;

	gtk_widget_show_all (popup);

	return TRUE;
}
コード例 #2
0
ファイル: pixbuf-utils.c プロジェクト: sudkannan/gthumb_old
void
_gdk_pixbuf_horizontal_gradient (GdkPixbuf *pixbuf,
				 guint32    color1,
				 guint32    color2)
{
	guchar   *pixels;
	guint32   r1, g1, b1, a1;
	guint32   r2, g2, b2, a2;
	double    r, g, b, a;
	double    rd, gd, bd, ad;
	guint32   ri, gi, bi, ai;
	guchar   *p;
	guint     width, height;
	guint     w, h;
	int       n_channels, rowstride;

	g_return_if_fail (GDK_IS_PIXBUF (pixbuf));

	width = gdk_pixbuf_get_width (pixbuf);
	height = gdk_pixbuf_get_height (pixbuf);

	if (width == 0 || height == 0)
		return;

	pixels = gdk_pixbuf_get_pixels (pixbuf);

	r1 = (color1 & 0xff000000) >> 24;
	g1 = (color1 & 0x00ff0000) >> 16;
	b1 = (color1 & 0x0000ff00) >> 8;
	a1 = (color1 & 0x000000ff);

	r2 = (color2 & 0xff000000) >> 24;
	g2 = (color2 & 0x00ff0000) >> 16;
	b2 = (color2 & 0x0000ff00) >> 8;
	a2 = (color2 & 0x000000ff);

	rd = ((double) (r2) - r1) / width;
	gd = ((double) (g2) - g1) / width;
	bd = ((double) (b2) - b1) / width;
	ad = ((double) (a2) - a1) / width;

	n_channels = gdk_pixbuf_get_n_channels (pixbuf);
	rowstride = gdk_pixbuf_get_rowstride (pixbuf);

	r = r1;
	g = g1;
	b = b1;
	a = a1;

	for (w = 0; w < width; w++) {
		h = height;
		p = pixels;

		ri = (int) rint (r);
		gi = (int) rint (g);
		bi = (int) rint (b);
		ai = (int) rint (a);

		switch (n_channels) {
		case 3:
			while (h--) {
				p[0] = ri;
				p[1] = gi;
				p[2] = bi;
				p += rowstride;
                        }
			break;
		case 4:
			while (h--) {
				p[0] = ri;
				p[1] = gi;
				p[2] = bi;
				p[3] = ai;
				p += rowstride;
			}
			break;
		default:
			break;
		}

		r += rd;
		g += gd;
		b += bd;
		a += ad;

		pixels += n_channels;
	}
}
コード例 #3
0
ファイル: pixbuf-utils.c プロジェクト: sudkannan/gthumb_old
static gboolean
_gdk_pixbuf_save_as_jpeg (GdkPixbuf     *pixbuf,
			  const char    *filename,
			  char         **keys,
			  char         **values,
			  GError       **error)
{
	struct jpeg_compress_struct cinfo;
	struct error_handler_data jerr;
	FILE              *file;
	guchar            *buf = NULL;
	guchar            *ptr;
	guchar            *pixels = NULL;
	volatile int       quality = 85; /* default; must be between 0 and 100 */
	volatile int       smoothing = 0;
	volatile gboolean  optimize = FALSE;
	volatile gboolean  progressive = FALSE;
	int                i, j;
	int                w, h = 0;
	int                rowstride = 0;
	volatile int       bpp;

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

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

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

			++kiter;
			++viter;
		}
	}

	file = fopen (filename, "wb");

	if (file == NULL) {
		g_set_error (error,
			     GDK_PIXBUF_ERROR,
			     GDK_PIXBUF_ERROR_FAILED,
			     "Can't write image to file '%s'",
			     filename);
		return FALSE;
	}

	rowstride = gdk_pixbuf_get_rowstride (pixbuf);

	w = gdk_pixbuf_get_width (pixbuf);
	h = gdk_pixbuf_get_height (pixbuf);

	if (gdk_pixbuf_get_has_alpha (pixbuf))
		bpp = 4;
	else
		bpp = 3;

	/* no image data? abort */
	pixels = gdk_pixbuf_get_pixels (pixbuf);
	g_return_val_if_fail (pixels != NULL, FALSE);

	/* allocate a small buffer to convert image data */
	buf = g_try_malloc (w * bpp * 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_stdio_dest (&cinfo, file);
	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);
	/* get the start pointer */
	ptr = pixels;
	/* go one scanline at a time... and save */
	i = 0;
	while (cinfo.next_scanline < cinfo.image_height) {
		JSAMPROW *jbuf;

		/* convert scanline from ARGB to RGB packed */
		for (j = 0; j < w; j++)
			memcpy (&(buf[j * 3]),
				&(ptr[i * rowstride + j * bpp]),
				3);

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

	/* finish off */
	jpeg_finish_compress (&cinfo);
	fclose (file);

	jpeg_destroy_compress(&cinfo);
	g_free (buf);

	return TRUE;
}
コード例 #4
0
static int
x_tile_load(TileTab *t, NhGtkProgressWindow *w)
{
    int fh, nb;
    long len, done = 0;
    char buf[1024];
    GdkPixbufLoader *loader;
    GError *err = NULL;
    Tile = t;
    tile_pixbuf = NULL;
    fh = nh_dlbh_fopen("tileset", t->file, "rb");
    if (fh < 0) {
	pline("Cannot open tile file %s!", t->file);
	return 0;
    }
    loader = gdk_pixbuf_loader_new();
    if (!nh_dlbh_fseek(fh, 0, SEEK_END)) {
	len = nh_dlbh_ftell(fh);
	nh_dlbh_fseek(fh, 0, SEEK_SET);
    } else
	len = -1;
    while (nb = nh_dlbh_fread(buf, 1, sizeof(buf), fh), nb > 0) {
	if (!gdk_pixbuf_loader_write(loader, buf, nb, &err)) {
	    pline("Error loading %s: %s", t->file, err->message);
	    g_error_free(err);
	    err = NULL;
	    break;
	}
	done += nb;
	if (len < 0)
	    nh_gtk_progress_window_stage_pulse(w);
	else
	    nh_gtk_progress_window_stage_set_fraction(w, (done * 0.9) / len);
    }
    if (nb < 0) {
	pline("Read error from tile file %s!", t->file);
	(void)gdk_pixbuf_loader_close(loader, NULL);
    } else if (!nb) {
	if (!gdk_pixbuf_loader_close(loader, &err)) {
	    pline("Error loading %s: %s", t->file, err->message);
	    g_error_free(err);
	    err = NULL;
	} else {
	    if (len < 0)
		nh_gtk_progress_window_stage_pulse(w);
	    else
		nh_gtk_progress_window_stage_set_fraction(w, 1.0);
	    tile_pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
	    if (!tile_pixbuf)
		pline("No image found in tile file %s!", t->file);
	    else
		g_object_ref(tile_pixbuf);
	}
    } else
	(void)gdk_pixbuf_loader_close(loader, NULL);
    nh_dlbh_fclose(fh);
    g_object_unref(loader);
    if (!tile_pixbuf)
	return 0;
    t->tilemap_width = gdk_pixbuf_get_width(tile_pixbuf);
    t->tilemap_height = gdk_pixbuf_get_height(tile_pixbuf);
    t->unit_width = t->tilemap_width / tiles_per_row;
    t->unit_height = t->tilemap_height / tiles_per_col;
    if (t->spread) {
	t->ofsetx_3d = t->unit_width / 3;
	t->ofsety_3d = t->unit_height / 2;
    } else {
	t->ofsetx_3d = 0;
	t->ofsety_3d = 0;
    }
    return 1;
}
コード例 #5
0
ファイル: nsp-feed.c プロジェクト: Michael-Z/Nowspide
int
nsp_feed_update_icon(NspFeed *feed)
{
	NspNetData *data;
	char *icon_url = NULL;
	char *icon_path = NULL;
	GRegex *regex;
	GMatchInfo *match_info;
	CURL *curl;
	CURLcode result;
	GdkPixbufLoader *loader = NULL;
	GError *error = NULL;
	char *feed_id_string = NULL;
	
	/* Download web page */
	data = nsp_net_new();
	if ( nsp_net_load_url(feed->site_url, data) ) {
		g_warning("ERROR: %s\n", data->error);
		nsp_net_free(data);
		return 1;
	}
	
	/* Find <link> tag reffering to the icon */
	regex = g_regex_new ("<link[^>]*?rel=[\"'](icon|shortcut icon)[\"'][^>]*?href=[\"'](?<href>.*?)[\"'][^>]*?>", 0, 0, NULL);
	g_regex_match (regex, data->content, 0, &match_info);
	
	while (g_match_info_matches (match_info)) {
		gchar *word = g_match_info_fetch_named (match_info, "href");
		if ( !g_str_has_prefix(word, "http") ) {
			icon_url = g_strdup_printf("%s/%s", feed->site_url, word);
			g_free(word);
			break;
		}
		g_free (word);
		g_match_info_next (match_info, NULL);
	}
	g_match_info_free (match_info);
	g_regex_unref (regex);
	nsp_net_free(data);
	
	/* If no image is found - use home url + /favicon.ico */
	if ( icon_url == NULL ) {
		regex = g_regex_new ("^(?<hostname>https?://[^/]*)", 0, 0, NULL);
		g_regex_match (regex, feed->site_url, 0, &match_info);
		
		if (g_match_info_matches (match_info)) {
			gchar *word = g_match_info_fetch_named (match_info, "hostname");
			icon_url = g_strdup_printf("%s/favicon.ico", word);
			g_free (word);
		}
		
		g_match_info_free (match_info);
		g_regex_unref (regex);
	}
	
	/* Store the image to a GtkPixbufLoader */
	loader = gdk_pixbuf_loader_new();
	curl = curl_easy_init();
	curl_easy_setopt (curl, CURLOPT_URL, icon_url);
	curl_easy_setopt (curl, CURLOPT_HEADER, 0);
	curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, nsp_feed_download_icon_cb );
	curl_easy_setopt (curl, CURLOPT_WRITEDATA, loader);
	curl_easy_setopt (curl, CURLOPT_TIMEOUT, 60);
	curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1);
	
	result = curl_easy_perform (curl);
	curl_easy_cleanup(curl);
	g_free(icon_url);
	
	if ( result != 0) {
		return 1;
	}
	
	gdk_pixbuf_loader_close (loader, NULL);
	feed->icon = gdk_pixbuf_loader_get_pixbuf (loader);
	
	if ( !GDK_IS_PIXBUF(feed->icon) ) {
		feed->icon = NULL;
		return 1;
	}
	
	/* Resize and save the image */
	if (gdk_pixbuf_get_width (feed->icon) != 16 || gdk_pixbuf_get_height (feed->icon) != 16) {
		GdkPixbuf *old = feed->icon;
		feed->icon = gdk_pixbuf_scale_simple (old, 16, 16, GDK_INTERP_BILINEAR);
		g_object_unref (G_OBJECT (old));
	}
	
	feed_id_string = malloc(sizeof(char)*9);
	g_snprintf (feed_id_string, 9, "%i", feed->id);
	
	icon_path = g_build_filename( g_get_user_data_dir(), PACKAGE, "/icons", NULL);
	g_mkdir_with_parents(icon_path, 0700);
	
	icon_path = g_build_filename( icon_path, "/", feed_id_string, NULL);
	gdk_pixbuf_save(feed->icon, icon_path, "png", &error, NULL);
	
	if ( error != NULL ) {
		g_warning("ERROR: %s\n", error->message);
		g_error_free(error);
	}
	g_free(icon_path);
	free(feed_id_string);
	
	return 0;
}
コード例 #6
0
/**
 * as_image_load_filename_full:
 * @image: a #AsImage instance.
 * @filename: filename to read from
 * @dest_size: The size of the constructed pixbuf, or 0 for the native size
 * @src_size_min: The smallest source size allowed, or 0 for none
 * @flags: a #AsImageLoadFlags, e.g. %AS_IMAGE_LOAD_FLAG_NONE
 * @error: A #GError or %NULL.
 *
 * Reads an image from a file.
 *
 * Returns: %TRUE for success
 *
 * Since: 0.5.6
 **/
gboolean
as_image_load_filename_full (AsImage *image,
			     const gchar *filename,
			     guint dest_size,
			     guint src_size_min,
			     AsImageLoadFlags flags,
			     GError **error)
{
	AsImagePrivate *priv = GET_PRIVATE (image);
	guint pixbuf_height;
	guint pixbuf_width;
	guint tmp_height;
	guint tmp_width;
	g_autoptr(GdkPixbuf) pixbuf = NULL;
	g_autoptr(GdkPixbuf) pixbuf_src = NULL;
	g_autoptr(GdkPixbuf) pixbuf_tmp = NULL;

	/* only support non-deprecated types */
	if (flags & AS_IMAGE_LOAD_FLAG_ONLY_SUPPORTED) {
		GdkPixbufFormat *fmt;
		fmt = gdk_pixbuf_get_file_info (filename, NULL, NULL);
		if (fmt == NULL) {
			g_set_error_literal (error,
					     AS_UTILS_ERROR,
					     AS_UTILS_ERROR_FAILED,
					     "image format was not recognized");
			return FALSE;
		}
		if (g_strcmp0 (gdk_pixbuf_format_get_name (fmt), "png") != 0 &&
		    g_strcmp0 (gdk_pixbuf_format_get_name (fmt), "jpeg") != 0 &&
		    g_strcmp0 (gdk_pixbuf_format_get_name (fmt), "xpm") != 0 &&
		    g_strcmp0 (gdk_pixbuf_format_get_name (fmt), "svg") != 0) {
			g_set_error (error,
				     AS_UTILS_ERROR,
				     AS_UTILS_ERROR_FAILED,
				     "image format %s is not supported",
				     gdk_pixbuf_format_get_name (fmt));
			return FALSE;
		}
	}

	/* update basename */
	if (flags & AS_IMAGE_LOAD_FLAG_SET_BASENAME) {
		g_autofree gchar *basename = NULL;
		basename = g_path_get_basename (filename);
		as_image_set_basename (image, basename);
	}

	/* update checksum */
	if (flags & AS_IMAGE_LOAD_FLAG_SET_CHECKSUM) {
		gsize len;
		g_autofree gchar *data = NULL;
		g_autofree gchar *md5_tmp = NULL;

		/* get the contents so we can hash the predictable file data,
		 * rather than the unpredicatable (for JPEG) pixel data */
		if (!g_file_get_contents (filename, &data, &len, error))
			return FALSE;
		md5_tmp = g_compute_checksum_for_data (G_CHECKSUM_MD5,
						       (guchar * )data, len);
		as_ref_string_assign_safe (&priv->md5, md5_tmp);
	}

	/* load the image of the native size */
	if (dest_size == 0) {
		pixbuf = gdk_pixbuf_new_from_file (filename, error);
		if (pixbuf == NULL)
			return FALSE;
		as_image_set_pixbuf (image, pixbuf);
		return TRUE;
	}

	/* open file in native size */
	if (g_str_has_suffix (filename, ".svg")) {
		pixbuf_src = gdk_pixbuf_new_from_file_at_scale (filename,
								(gint) dest_size,
								(gint) dest_size,
								TRUE, error);
	} else {
		pixbuf_src = gdk_pixbuf_new_from_file (filename, error);
	}
	if (pixbuf_src == NULL)
		return FALSE;

	/* check size */
	if (gdk_pixbuf_get_width (pixbuf_src) < (gint) src_size_min &&
	    gdk_pixbuf_get_height (pixbuf_src) < (gint) src_size_min) {
		g_set_error (error,
			     AS_UTILS_ERROR,
			     AS_UTILS_ERROR_FAILED,
			     "icon was too small %ix%i",
			     gdk_pixbuf_get_width (pixbuf_src),
			     gdk_pixbuf_get_height (pixbuf_src));
		return FALSE;
	}

	/* don't do anything to an icon with the perfect size */
	pixbuf_width = (guint) gdk_pixbuf_get_width (pixbuf_src);
	pixbuf_height = (guint) gdk_pixbuf_get_height (pixbuf_src);
	if (pixbuf_width == dest_size && pixbuf_height == dest_size) {
		as_image_set_pixbuf (image, pixbuf_src);
		return TRUE;
	}

	/* never scale up, just pad */
	if (pixbuf_width < dest_size && pixbuf_height < dest_size) {
		g_debug ("icon padded to %ux%u as size %ux%u",
			 dest_size, dest_size,
			 pixbuf_width, pixbuf_height);
		pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
					 (gint) dest_size, (gint) dest_size);
		gdk_pixbuf_fill (pixbuf, 0x00000000);
		gdk_pixbuf_copy_area (pixbuf_src,
				      0, 0, /* of src */
				      (gint) pixbuf_width,
				      (gint) pixbuf_height,
				      pixbuf,
				      (gint) (dest_size - pixbuf_width) / 2,
				      (gint) (dest_size - pixbuf_height) / 2);
		as_image_set_pixbuf (image, pixbuf);
		return TRUE;
	}

	/* is the aspect ratio perfectly square */
	if (pixbuf_width == pixbuf_height) {
		pixbuf = gdk_pixbuf_scale_simple (pixbuf_src,
						  (gint) dest_size,
						  (gint) dest_size,
						  GDK_INTERP_HYPER);
		as_image_set_pixbuf (image, pixbuf);
		return TRUE;
	}

	/* create new square pixbuf with alpha padding */
	pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
				 (gint) dest_size, (gint) dest_size);
	gdk_pixbuf_fill (pixbuf, 0x00000000);
	if (pixbuf_width > pixbuf_height) {
		tmp_width = dest_size;
		tmp_height = dest_size * pixbuf_height / pixbuf_width;
	} else {
		tmp_width = dest_size * pixbuf_width / pixbuf_height;
		tmp_height = dest_size;
	}
	pixbuf_tmp = gdk_pixbuf_scale_simple (pixbuf_src,
					      (gint) tmp_width,
					      (gint) tmp_height,
					      GDK_INTERP_HYPER);
	if (flags & AS_IMAGE_LOAD_FLAG_SHARPEN)
		as_pixbuf_sharpen (pixbuf_tmp, 1, -0.5);
	gdk_pixbuf_copy_area (pixbuf_tmp,
			      0, 0, /* of src */
			      (gint) tmp_width, (gint) tmp_height,
			      pixbuf,
			      (gint) (dest_size - tmp_width) / 2,
			      (gint) (dest_size - tmp_height) / 2);
	as_image_set_pixbuf (image, pixbuf);
	return TRUE;
}
コード例 #7
0
/**
 * as_image_get_alpha_flags: (skip)
 * @image: a #AsImage instance.
 *
 * Gets the alpha flags for the image. The following image would have all flags
 * set, where 'x' is alpha and '@' is non-alpha.
 *
 * xxxxxxxxxxxxxxxxxxxxxxxxxxxx
 * xx@@@@@@@@@@@@@@@@@@@@@@@@xx
 * xx@@@@@@@xxxxxx@@@@@@@@@@@xx
 * xx@@@@@@@xxxxxx@@@@@@@@@@@xx
 * xx@@@@@@@@@@@@@@@@@@@@@@@@xx
 * xxxxxxxxxxxxxxxxxxxxxxxxxxxx
 *
 * Returns: #AsImageAlphaFlags, e.g. %AS_IMAGE_ALPHA_FLAG_LEFT
 *
 * Since: 0.2.2
 **/
AsImageAlphaFlags
as_image_get_alpha_flags (AsImage *image)
{
	AsImageAlphaFlags flags = AS_IMAGE_ALPHA_FLAG_TOP |
				  AS_IMAGE_ALPHA_FLAG_BOTTOM |
				  AS_IMAGE_ALPHA_FLAG_LEFT |
				  AS_IMAGE_ALPHA_FLAG_RIGHT;
	AsImageAlphaMode mode_h;
	AsImageAlphaMode mode_v = AS_IMAGE_ALPHA_MODE_START;
	AsImagePrivate *priv = GET_PRIVATE (image);
	gboolean complete_line_of_alpha;
	gboolean is_alpha;
	guint width, height;
	guint x, y;
	guint cnt_content_to_alpha_h;
	guint cnt_content_to_alpha_v = 0;

	if (!gdk_pixbuf_get_has_alpha (priv->pixbuf))
		return AS_IMAGE_ALPHA_FLAG_NONE;

	width = (guint) gdk_pixbuf_get_width (priv->pixbuf);
	height = (guint) gdk_pixbuf_get_height (priv->pixbuf);
	for (y = 0; y < height; y++) {
		mode_h = AS_IMAGE_ALPHA_MODE_START;
		complete_line_of_alpha = TRUE;
		cnt_content_to_alpha_h = 0;
		for (x = 0; x < width; x++) {
			is_alpha = is_pixel_alpha (priv->pixbuf, x, y);
			/* use the frame */
			if (!is_alpha) {
				if (x == 0)
					flags &= ~AS_IMAGE_ALPHA_FLAG_LEFT;
				if (x == width - 1)
					flags &= ~AS_IMAGE_ALPHA_FLAG_RIGHT;
				if (y == 0)
					flags &= ~AS_IMAGE_ALPHA_FLAG_TOP;
				if (y == height - 1)
					flags &= ~AS_IMAGE_ALPHA_FLAG_BOTTOM;
				complete_line_of_alpha = FALSE;
			}

			/* use line state machine */
			switch (mode_h) {
			case AS_IMAGE_ALPHA_MODE_START:
				mode_h = is_alpha ? AS_IMAGE_ALPHA_MODE_PADDING :
						    AS_IMAGE_ALPHA_MODE_CONTENT;
				break;
			case AS_IMAGE_ALPHA_MODE_PADDING:
				if (!is_alpha)
					mode_h = AS_IMAGE_ALPHA_MODE_CONTENT;
				break;
			case AS_IMAGE_ALPHA_MODE_CONTENT:
				if (is_alpha) {
					mode_h = AS_IMAGE_ALPHA_MODE_PADDING;
					cnt_content_to_alpha_h++;
				}
				break;
			default:
				g_assert_not_reached ();
			}
		}

		/* use column state machine */
		switch (mode_v) {
		case AS_IMAGE_ALPHA_MODE_START:
			if (complete_line_of_alpha) {
				mode_v = AS_IMAGE_ALPHA_MODE_PADDING;
			} else {
				mode_v = AS_IMAGE_ALPHA_MODE_CONTENT;
			}
			break;
		case AS_IMAGE_ALPHA_MODE_PADDING:
			if (!complete_line_of_alpha)
				mode_v = AS_IMAGE_ALPHA_MODE_CONTENT;
			break;
		case AS_IMAGE_ALPHA_MODE_CONTENT:
			if (complete_line_of_alpha) {
				mode_v = AS_IMAGE_ALPHA_MODE_PADDING;
				cnt_content_to_alpha_v++;
			}
			break;
		default:
			g_assert_not_reached ();
		}

		/* detect internal alpha */
		if (mode_h == AS_IMAGE_ALPHA_MODE_PADDING) {
			if (cnt_content_to_alpha_h >= 2)
				flags |= AS_IMAGE_ALPHA_FLAG_INTERNAL;
		} else if (mode_h == AS_IMAGE_ALPHA_MODE_CONTENT) {
			if (cnt_content_to_alpha_h >= 1)
				flags |= AS_IMAGE_ALPHA_FLAG_INTERNAL;
		}
	}

	/* detect internal alpha */
	if (mode_v == AS_IMAGE_ALPHA_MODE_PADDING) {
		if (cnt_content_to_alpha_v >= 2)
			flags |= AS_IMAGE_ALPHA_FLAG_INTERNAL;
	} else if (mode_v == AS_IMAGE_ALPHA_MODE_CONTENT) {
		if (cnt_content_to_alpha_v >= 1)
			flags |= AS_IMAGE_ALPHA_FLAG_INTERNAL;
	}
	return flags;
}
コード例 #8
0
static gboolean
update_icon_idle (ButtonData *button_data)
{
        int width, height;
        GdkPixbuf *icon;
        GdkPixbuf *scaled;
        int        icon_size;
        GError    *error;
        int        xrequest, yrequest;
        GtkRequisition empty_button_request;

        /* FIXME this function could do a lot more short-circuiting and maybe
         * save some effort
         */
        g_debug("Updating icon, allocated size=%d", button_data->size);
        
        if (!button_data->icon_theme)
                goto done;

        gtk_image_clear (GTK_IMAGE (button_data->image));
        
        gtk_widget_set_size_request (button_data->image, 10, 10); /* we undo this later, it's just in case the button special-cases 0x0 contents */
        gtk_widget_size_request (GTK_WIDGET(button_data->button), &empty_button_request);
        empty_button_request.width -= 10;
        empty_button_request.height -= 10;
        
        icon_size = 0;
        xrequest = -1;
        yrequest = -1;
        switch (button_data->orient) {
        case GTK_ORIENTATION_HORIZONTAL:
                xrequest = button_data->size - empty_button_request.width;
                if (xrequest < 0)
                        xrequest = 0;
                yrequest = 12;
                icon_size = xrequest;
                break;
        case GTK_ORIENTATION_VERTICAL:
                xrequest = 12;
                yrequest = button_data->size - empty_button_request.height;
                if (yrequest < 0)
                        yrequest = 0;
                icon_size = yrequest;
                break;
        }

        /* clamp icon size to a max of 60 which is the native server-side size
         */
        if (icon_size < 22)
                icon_size = 16;
        else if (icon_size < 32)
                icon_size = 22;
        else if (icon_size < 48)
                icon_size = 32;
        else if (icon_size < 60)
                icon_size = 48;
        else
                icon_size = 60;

        g_debug("Settled on icon size %d, and image widget request %dx%d, based on empty button request %dx%d",
                icon_size, xrequest, yrequest, empty_button_request.width, empty_button_request.height);
        
        if (button_data->user_photo) {
                icon = button_data->user_photo;
                g_object_ref(icon);
        } else {
                error = NULL;
                icon = gtk_icon_theme_load_icon (button_data->icon_theme,
                                                 ICON_NAME,
                                                 icon_size, 0, &error);
        }

        if (icon == NULL) {
                g_printerr (_("Failed to load %s: %s\n"), ICON_NAME,
                            error ? error->message : _("Icon not found"));
                if (error) {
                        g_error_free (error);
                        error = NULL;
                }

                icon = gdk_pixbuf_new_from_file (DATADIR "/pixmaps/nobody.png", NULL);
                if (icon == NULL) {
                        gtk_image_set_from_stock (GTK_IMAGE (button_data->image),
                                                  GTK_STOCK_MISSING_IMAGE,
                                                  GTK_ICON_SIZE_SMALL_TOOLBAR);
                        goto done;
                }
        }

        width = gdk_pixbuf_get_width (icon);
        height = gdk_pixbuf_get_height (icon);

        scaled = NULL;

        /* Make it fit on the given panel */
        switch (button_data->orient) {
        case GTK_ORIENTATION_HORIZONTAL:
                width = (icon_size * width) / (double) height;
                height = icon_size;
                break;
        case GTK_ORIENTATION_VERTICAL:
                height = (icon_size * height) / (double) width;
                width = icon_size;
                break;
        }

        scaled = gdk_pixbuf_scale_simple (icon,
                                          width, height,
                                          GDK_INTERP_BILINEAR);

        if (scaled != NULL) {
                gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image),
                                           scaled);
                g_object_unref (scaled);
        } else {
                gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image),
                                           icon);
        }

        /* don't put much size request on the image, since we are scaling
         * to the allocation, if we didn't do this we could a) never be resized
         * smaller and b) get infinite request/alloc loops
         */
        gtk_widget_set_size_request(button_data->image, xrequest, yrequest);

        g_object_unref (icon);

#ifdef GUI_LOG
        {
                GtkRequisition with_image_request;
                gtk_widget_size_request(button_data->button, &with_image_request);
                g_debug("Entire button will request %dx%d", with_image_request.width, with_image_request.height);
        }
#endif
        
done:
        button_data->update_icon_idle = 0;
        return FALSE;
}
コード例 #9
0
ファイル: pixbuf-util.c プロジェクト: DroiDev/glabels
GdkPixbuf *
gl_pixbuf_util_create_shadow_pixbuf (const GdkPixbuf *pixbuf,
                                     guint            shadow_color,
                                     gdouble          shadow_opacity)
{
        gint             bits_per_sample, channels;
        gboolean         src_has_alpha;
        gint             width, height, src_rowstride, dest_rowstride;
        GdkPixbuf       *dest_pixbuf;
        guchar          *buf_src, *buf_dest;
        guchar          *p_src, *p_dest;
        gint             ix, iy;
        guchar           shadow_r, shadow_g, shadow_b;

        g_return_val_if_fail (pixbuf && GDK_IS_PIXBUF (pixbuf), NULL);

        shadow_r = GL_COLOR_F_RED   (shadow_color) * 255.0;
        shadow_g = GL_COLOR_F_GREEN (shadow_color) * 255.0;
        shadow_b = GL_COLOR_F_BLUE  (shadow_color) * 255.0;

        /* extract pixels and parameters from source pixbuf. */
        buf_src         = gdk_pixbuf_get_pixels (pixbuf);
        bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
        channels        = gdk_pixbuf_get_n_channels (pixbuf);
        src_has_alpha   = gdk_pixbuf_get_has_alpha (pixbuf);
        width           = gdk_pixbuf_get_width (pixbuf);
        height          = gdk_pixbuf_get_height (pixbuf);
        src_rowstride   = gdk_pixbuf_get_rowstride (pixbuf);

        /* validate assumptions about source pixbuf. */
        g_return_val_if_fail (buf_src, NULL);
        g_return_val_if_fail (bits_per_sample == 8, NULL);
        g_return_val_if_fail ((channels >= 3) && (channels <= 4), NULL);
        g_return_val_if_fail (width > 0, NULL);
        g_return_val_if_fail (height > 0, NULL);
        g_return_val_if_fail (src_rowstride > 0, NULL);

        /* Allocate a destination pixbuf */
        dest_pixbuf    = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, bits_per_sample, width, height);
        dest_rowstride = gdk_pixbuf_get_rowstride (dest_pixbuf);
        buf_dest       = gdk_pixbuf_get_pixels (dest_pixbuf);
        if (!buf_dest) {
                return NULL;
        }

        /* Process pixels: set rgb components and composite alpha with shadow_opacity. */
        p_src  = buf_src;
        p_dest = buf_dest;
        for ( iy=0; iy < height; iy++ )
        {
        
                p_src  = buf_src + iy*src_rowstride;
                p_dest = buf_dest + iy*dest_rowstride;

                for ( ix=0; ix < width; ix++ )
                {

                        p_src += 3; /* skip RGB */

                        *p_dest++ = shadow_r;
                        *p_dest++ = shadow_g;
                        *p_dest++ = shadow_b;

                        if ( src_has_alpha )
                        {
                                *p_dest++ = *p_src++ * shadow_opacity;
                        }
                        else
                        {
                                *p_dest++ = shadow_opacity * 255.0;
                        }


                }

        }

        return dest_pixbuf;
}
コード例 #10
0
ファイル: vtegl.c プロジェクト: Cordia/vte
static void
_vte_gl_clear(struct _vte_draw *draw, gint x, gint y, gint width, gint height)
{
	struct _vte_gl_data *data;
	long xstop, ystop, i, j;
	int pixbufw, pixbufh, w, h, channels, stride;
	GLenum format = 0;
	guchar *pixels;

	data = (struct _vte_gl_data*) draw->impl_data;

	glXMakeCurrent(data->display, data->glwindow, data->context);

	if (data->bgpixbuf != NULL) {
		pixbufw = gdk_pixbuf_get_width(data->bgpixbuf);
		pixbufh = gdk_pixbuf_get_height(data->bgpixbuf);
	} else {
		pixbufw = pixbufh = 0;
	}

	if ((pixbufw == 0) || (pixbufh == 0)) {
		glColor4us(data->color.red,
			   data->color.green,
			   data->color.blue,
			   0xffff);
		glBegin(GL_POLYGON);
		glVertex2d(x, y);
		glVertex2d(x + width, y);
		glVertex2d(x + width, y + height - 1);
		glVertex2d(x, y + height - 1);
		glEnd();
		return;
	}

	/* Flood fill. */
	xstop = x + width;
	ystop = y + height;

	pixels = gdk_pixbuf_get_pixels(data->bgpixbuf);
	channels = gdk_pixbuf_get_n_channels(data->bgpixbuf);
	stride = gdk_pixbuf_get_rowstride(data->bgpixbuf);

	switch (channels) {
	case 3:
		format = GL_RGB;
		break;
	case 4:
		format = GL_RGBA;
		break;
	default:
		g_assert_not_reached();
		break;
	}

	y = ystop - height;
	j = (data->scrolly + y) % pixbufh;
	while (y < ystop) {
		x = xstop - width;
		i = (data->scrollx + x) % pixbufw;

		/* h = MIN(pixbufh - (j % pixbufh), ystop - y); */
		h = 1;
		while (x < xstop) {
			w = MIN(pixbufw - (i % pixbufw), xstop - x);

			glRasterPos2i(x, y);
			glDrawPixels(w, h,
				     format, GL_UNSIGNED_BYTE,
				     pixels + stride * j + channels * i);
			x += w;
			i = 0;
		}
		y += h;
		j = (data->scrolly + y) % pixbufh;
	}
	glFlush();
}
コード例 #11
0
static gboolean
real_save_jpeg (GdkPixbuf          *pixbuf,
		gchar             **keys,
		gchar             **values,
		GError            **error,
		gboolean            to_callback,
		FILE               *f,
		GdkPixbufSaveFunc   save_func,
		gpointer            user_data)
{
        /* FIXME error handling is broken */
        
       struct jpeg_compress_struct cinfo;
       guchar *buf = NULL;
       guchar *ptr;
       guchar *pixels = NULL;
       JSAMPROW *jbuf;
       int y = 0;
       volatile int quality = 75; /* default; must be between 0 and 100 */
       int i, j;
       int w, h = 0;
       int rowstride = 0;
       int n_channels;
       struct error_handler_data jerr;
       ToFunctionDestinationManager to_callback_destmgr;
       gchar *icc_profile = NULL;
       gchar *data;
       gint retval = TRUE;
       gsize icc_profile_size = 0;

       to_callback_destmgr.buffer = NULL;

       if (keys && *keys) {
               gchar **kiter = keys;
               gchar **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);

                                       retval = FALSE;
                                       goto cleanup;
                               }
                               
                               if (quality < 0 ||
                                   quality > 100) {
                                       /* This is a user-visible error;
                                        * lets people skip the range-checking
                                        * in their app.
                                        */
                                       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);

                                       retval = FALSE;
                                       goto cleanup;
                               }
                       } else if (strcmp (*kiter, "icc-profile") == 0) {
                               /* decode from base64 */
                               icc_profile = (gchar*) g_base64_decode (*viter, &icc_profile_size);
                               if (icc_profile_size < 127) {
                                       /* This is a user-visible error */
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("Color profile has invalid length '%u'."),
                                                    (guint) icc_profile_size);
                                       retval = FALSE;
                                       goto cleanup;
                               }
                       } else {
                               g_warning ("Unrecognized parameter (%s) passed to JPEG saver.", *kiter);
                       }
               
                       ++kiter;
                       ++viter;
               }
       }
       
       rowstride = gdk_pixbuf_get_rowstride (pixbuf);
       n_channels = gdk_pixbuf_get_n_channels (pixbuf);

       w = gdk_pixbuf_get_width (pixbuf);
       h = gdk_pixbuf_get_height (pixbuf);
       pixels = gdk_pixbuf_get_pixels (pixbuf);

       /* Allocate a small buffer to convert image data,
	* and a larger buffer if doing to_callback save.
	*/
       buf = g_try_malloc (w * 3 * sizeof (guchar));
       if (!buf) {
	       g_set_error_literal (error,
                                    GDK_PIXBUF_ERROR,
                                    GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                    _("Couldn't allocate memory for loading JPEG file"));
	       retval = FALSE;
	       goto cleanup;
       }
       if (to_callback) {
	       to_callback_destmgr.buffer = g_try_malloc (TO_FUNCTION_BUF_SIZE);
	       if (!to_callback_destmgr.buffer) {
		       g_set_error_literal (error,
                                            GDK_PIXBUF_ERROR,
                                            GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                            _("Couldn't allocate memory for loading JPEG file"));
		       retval = FALSE;
		       goto cleanup;
	       }
       }

       /* 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);
	       retval = FALSE;
	       goto cleanup;
       }

       /* setup compress params */
       jpeg_create_compress (&cinfo);
       if (to_callback) {
	       to_callback_destmgr.pub.init_destination    = to_callback_init;
	       to_callback_destmgr.pub.empty_output_buffer = to_callback_empty_output_buffer;
	       to_callback_destmgr.pub.term_destination    = to_callback_terminate;
	       to_callback_destmgr.error = error;
	       to_callback_destmgr.save_func = save_func;
	       to_callback_destmgr.user_data = user_data;
	       cinfo.dest = (struct jpeg_destination_mgr*) &to_callback_destmgr;
       } else {
	       jpeg_stdio_dest (&cinfo, f);
       }
       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);

       jpeg_start_compress (&cinfo, TRUE);

	/* write ICC profile data */
	if (icc_profile != NULL) {
		/* optimise for the common case where only one APP2 segment is required */
		if (icc_profile_size < 0xffef) {
			data = g_new (gchar, icc_profile_size + 14);
			memcpy (data, "ICC_PROFILE\000\001\001", 14);
			memcpy (data + 14, icc_profile, icc_profile_size);
			jpeg_write_marker (&cinfo, JPEG_APP0+2, (const JOCTET *) data, icc_profile_size + 14);
			g_free (data);
		} else {
			guint segments;
			guint size = 0xffef;
			guint offset;

			segments = (guint) ceilf ((gfloat) icc_profile_size / (gfloat) 0xffef);
			data = g_new (gchar, 0xffff);
			memcpy (data, "ICC_PROFILE\000", 12);
			data[13] = segments;
			for (i=0; i<=segments; i++) {
				data[12] = i;
				offset = 0xffef * i;

				/* last segment */
				if (i == segments)
					size = icc_profile_size % 0xffef;

				memcpy (data + 14, icc_profile + offset, size);
				jpeg_write_marker (&cinfo, JPEG_APP0+2, (const JOCTET *) data, size + 14);
			}
			g_free (data);
		}
	}

       /* get the start pointer */
       ptr = pixels;
       /* go one scanline at a time... and save */
       i = 0;
       while (cinfo.next_scanline < cinfo.image_height) {
               /* convert scanline from ARGB to RGB packed */
               for (j = 0; j < w; j++)
                       memcpy (&(buf[j*3]), &(ptr[i*rowstride + j*n_channels]), 3);

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

       }

       /* finish off */
       jpeg_finish_compress (&cinfo);
       jpeg_destroy_compress(&cinfo);
cleanup:
	g_free (buf);
	g_free (to_callback_destmgr.buffer);
	g_free (icc_profile);
	return retval;
}
コード例 #12
0
ファイル: fm-thumbnail.c プロジェクト: engla/libfm
void generate_thumbnails_with_gdk_pixbuf(ThumbnailTask* task)
{
    /* FIXME: only formats supported by GdkPixbuf should be handled this way. */
    GFile* gf = fm_path_to_gfile(task->fi->path);
    GFileInputStream* ins;
    GdkPixbuf* normal_pix = NULL;
    GdkPixbuf* large_pix = NULL;

    DEBUG("generate thumbnail for %s", task->fi->path->name);

    if( ins = g_file_read(gf, generator_cancellable, NULL) )
    {
        GdkPixbuf* ori_pix;
        gssize len;
        ori_pix = gdk_pixbuf_new_from_stream(G_INPUT_STREAM(ins), generator_cancellable, NULL);
        if(ori_pix) /* if the original image is successfully loaded */
        {
            const char* orientation_str = gdk_pixbuf_get_option(ori_pix, "orientation");
            int width = gdk_pixbuf_get_width(ori_pix);
            int height = gdk_pixbuf_get_height(ori_pix);
            gboolean need_save;

            if(task->flags & GENERATE_NORMAL)
            {
                /* don't create thumbnails for images which are too small */
                if(width <=128 && height <= 128)
                {
                    normal_pix = (GdkPixbuf*)g_object_ref(ori_pix);
                    need_save = FALSE;
                }
                else
                {
                    normal_pix = scale_pix(ori_pix, 128);
                    need_save = TRUE;
                }
                if(orientation_str)
                {
                    GdkPixbuf* rotated;
                    gdk_pixbuf_set_option(normal_pix, "orientation", orientation_str);
                    rotated = gdk_pixbuf_apply_embedded_orientation(normal_pix);
                    g_object_unref(normal_pix);
                    normal_pix = rotated;
                }
                if(need_save)
                    save_thumbnail_to_disk(task, normal_pix, task->normal_path);
            }

            if(task->flags & GENERATE_LARGE)
            {
                /* don't create thumbnails for images which are too small */
                if(width <=256 && height <= 256)
                {
                    large_pix = (GdkPixbuf*)g_object_ref(ori_pix);
                    need_save = FALSE;
                }
                else
                {
                    large_pix = scale_pix(ori_pix, 256);
                    need_save = TRUE;
                }
                if(orientation_str)
                {
                    GdkPixbuf* rotated;
                    gdk_pixbuf_set_option(large_pix, "orientation", orientation_str);
                    rotated = gdk_pixbuf_apply_embedded_orientation(large_pix);
                    g_object_unref(large_pix);
                    large_pix = rotated;
                }
                if(need_save)
                    save_thumbnail_to_disk(task, large_pix, task->large_path);
            }
            g_object_unref(ori_pix);
        }
        g_input_stream_close(G_INPUT_STREAM(ins), NULL, NULL);
    }

    G_LOCK(queue);
    thumbnail_task_finish(task, normal_pix, large_pix);
    cur_generating = NULL;
    G_UNLOCK(queue);

    if(normal_pix)
        g_object_unref(normal_pix);
    if(large_pix)
        g_object_unref(large_pix);

    g_object_unref(gf);
}
コード例 #13
0
ファイル: io-png.c プロジェクト: dieterv/gdk-pixbuf
static gboolean real_save_png (GdkPixbuf        *pixbuf, 
                               gchar           **keys,
                               gchar           **values,
                               GError          **error,
                               gboolean          to_callback,
                               FILE             *f,
                               GdkPixbufSaveFunc save_func,
                               gpointer          user_data)
{
       png_structp png_ptr = NULL;
       png_infop info_ptr;
       png_textp text_ptr = NULL;
       guchar *ptr;
       guchar *pixels;
       int y;
       int i;
       png_bytep row_ptr;
       png_color_8 sig_bit;
       int w, h, rowstride;
       int has_alpha;
       int bpc;
       int num_keys;
       int compression = -1;
       gboolean success = TRUE;
       guchar *icc_profile = NULL;
       gsize icc_profile_size = 0;
       SaveToFunctionIoPtr to_callback_ioptr;

       num_keys = 0;

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

               while (*kiter) {
                       if (strncmp (*kiter, "tEXt::", 6) == 0) {
                               gchar  *key = *kiter + 6;
                               int     len = strlen (key);
                               if (len <= 1 || len > 79) {
                                       g_set_error_literal (error,
                                                            GDK_PIXBUF_ERROR,
                                                            GDK_PIXBUF_ERROR_BAD_OPTION,
                                                            _("Keys for PNG text chunks must have at least 1 and at most 79 characters."));
                                       success = FALSE;
                                       goto cleanup;
                               }
                               for (i = 0; i < len; i++) {
                                       if ((guchar) key[i] > 127) {
                                               g_set_error_literal (error,
                                                                    GDK_PIXBUF_ERROR,
                                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                                    _("Keys for PNG text chunks must be ASCII characters."));
                                               success = FALSE;
                                               goto cleanup;
                                       }
                               }
                               num_keys++;
                       } else if (strcmp (*kiter, "icc-profile") == 0) {
                               /* decode from base64 */
                               icc_profile = g_base64_decode (*viter, &icc_profile_size);
                               if (icc_profile_size < 127) {
                                       /* This is a user-visible error */
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("Color profile has invalid length %d."),
                                                    (gint)icc_profile_size);
                                       success = FALSE;
                                       goto cleanup;
                               }
                       } else if (strcmp (*kiter, "compression") == 0) {
                               char *endptr = NULL;
                               compression = strtol (*viter, &endptr, 10);

                               if (endptr == *viter) {
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("PNG compression level must be a value between 0 and 9; value '%s' could not be parsed."),
                                                    *viter);
                                       success = FALSE;
                                       goto cleanup;
                               }
                               if (compression < 0 || compression > 9) {
                                       /* This is a user-visible error;
                                        * lets people skip the range-checking
                                        * in their app.
                                        */
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("PNG compression level must be a value between 0 and 9; value '%d' is not allowed."),
                                                    compression);
                                       success = FALSE;
                                       goto cleanup;
                               }
                       } else {
                               g_warning ("Unrecognized parameter (%s) passed to PNG saver.", *kiter);
                       }

                       ++kiter;
                       ++viter;
               }
       }

       if (num_keys > 0) {
               text_ptr = g_new0 (png_text, num_keys);
               for (i = 0; i < num_keys; i++) {
                       text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE;
                       text_ptr[i].key  = keys[i] + 6;
                       text_ptr[i].text = g_convert (values[i], -1, 
                                                     "ISO-8859-1", "UTF-8", 
                                                     NULL, &text_ptr[i].text_length, 
                                                     NULL);

#ifdef PNG_iTXt_SUPPORTED 
                       if (!text_ptr[i].text) {
                               text_ptr[i].compression = PNG_ITXT_COMPRESSION_NONE;
                               text_ptr[i].text = g_strdup (values[i]);
                               text_ptr[i].text_length = 0;
                               text_ptr[i].itxt_length = strlen (text_ptr[i].text);
                               text_ptr[i].lang = NULL;
                               text_ptr[i].lang_key = NULL;
                       }
#endif

                       if (!text_ptr[i].text) {
                               g_set_error (error,
                                            GDK_PIXBUF_ERROR,
                                            GDK_PIXBUF_ERROR_BAD_OPTION,
                                            _("Value for PNG text chunk %s cannot be converted to ISO-8859-1 encoding."), keys[i] + 6);
                               num_keys = i;
                               for (i = 0; i < num_keys; i++)
                                       g_free (text_ptr[i].text);
                               g_free (text_ptr);
                               return FALSE;
                       }
               }
       }

       bpc = gdk_pixbuf_get_bits_per_sample (pixbuf);
       w = gdk_pixbuf_get_width (pixbuf);
       h = gdk_pixbuf_get_height (pixbuf);
       rowstride = gdk_pixbuf_get_rowstride (pixbuf);
       has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
       pixels = gdk_pixbuf_get_pixels (pixbuf);

       png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
                                          error,
                                          png_simple_error_callback,
                                          png_simple_warning_callback);
       if (png_ptr == NULL) {
	       success = FALSE;
	       goto cleanup;
       }

       info_ptr = png_create_info_struct (png_ptr);
       if (info_ptr == NULL) {
	       success = FALSE;
	       goto cleanup;
       }
       if (setjmp (png_jmpbuf(png_ptr))) {
	       success = FALSE;
	       goto cleanup;
       }

       if (num_keys > 0) {
               png_set_text (png_ptr, info_ptr, text_ptr, num_keys);
       }

       if (to_callback) {
               to_callback_ioptr.save_func = save_func;
               to_callback_ioptr.user_data = user_data;
               to_callback_ioptr.error = error;
               png_set_write_fn (png_ptr, &to_callback_ioptr,
                                 png_save_to_callback_write_func,
                                 png_save_to_callback_flush_func);
       } else {
               png_init_io (png_ptr, f);
       }

       if (compression >= 0)
               png_set_compression_level (png_ptr, compression);

#if defined(PNG_iCCP_SUPPORTED)
        /* the proper ICC profile title is encoded in the profile */
        if (icc_profile != NULL) {
                png_set_iCCP (png_ptr, info_ptr,
                              "ICC profile", PNG_COMPRESSION_TYPE_BASE,
                              (gchar*) icc_profile, icc_profile_size);
        }
#endif

       if (has_alpha) {
               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
                             PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
       } else {
               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
                             PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
       }
       sig_bit.red = bpc;
       sig_bit.green = bpc;
       sig_bit.blue = bpc;
       sig_bit.alpha = bpc;
       png_set_sBIT (png_ptr, info_ptr, &sig_bit);
       png_write_info (png_ptr, info_ptr);
       png_set_shift (png_ptr, &sig_bit);
       png_set_packing (png_ptr);

       ptr = pixels;
       for (y = 0; y < h; y++) {
               row_ptr = (png_bytep)ptr;
               png_write_rows (png_ptr, &row_ptr, 1);
               ptr += rowstride;
       }

       png_write_end (png_ptr, info_ptr);

cleanup:
        if (png_ptr != NULL)
                png_destroy_write_struct (&png_ptr, &info_ptr);

        g_free (icc_profile);

        if (text_ptr != NULL) {
                for (i = 0; i < num_keys; i++)
                        g_free (text_ptr[i].text);
                g_free (text_ptr);
        }

       return success;
}
コード例 #14
0
ファイル: picture.c プロジェクト: mat-raynard/easytag
void PictureEntry_Update (Picture *pic, gboolean select_it)
{
    GdkPixbufLoader *loader = 0;
    GError *error = NULL;
    
    g_return_if_fail (pic != NULL || PictureEntryView != NULL);

    if (!pic->data)
    {
        PictureEntry_Clear();
        return;
    }

    loader = gdk_pixbuf_loader_new();
    if (loader)
    {
        if (gdk_pixbuf_loader_write(loader, pic->data, pic->size, &error))
        {
            GtkTreeSelection *selection;
            GdkPixbuf *pixbuf;

            if (!gdk_pixbuf_loader_close(loader, &error))
            {
                Log_Print(LOG_ERROR,_("Error with 'loader_close': %s"), error->message);
                g_error_free(error);
            }

            selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));

            pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
            if (pixbuf)
            {
                GtkListStore *picture_store;
                GtkTreeIter iter1;
                GdkPixbuf *scaled_pixbuf;
                gint scaled_pixbuf_width;
                gint scaled_pixbuf_height;
                gchar *pic_info;

                g_object_ref(pixbuf);
                g_object_unref(loader);
                
                // Keep aspect ratio of the picture
                pic->width  = gdk_pixbuf_get_width(pixbuf);
                pic->height = gdk_pixbuf_get_height(pixbuf);
                if (pic->width > pic->height)
                {
                    scaled_pixbuf_width  = 96;
                    scaled_pixbuf_height = 96 * pic->height / pic->width;
                }else
                {
                    scaled_pixbuf_width = 96 * pic->width / pic->height;
                    scaled_pixbuf_height = 96;
                }

                scaled_pixbuf = gdk_pixbuf_scale_simple(pixbuf,
                                    scaled_pixbuf_width, scaled_pixbuf_height,
                                    //GDK_INTERP_NEAREST); // Lower quality but better speed
                                    GDK_INTERP_BILINEAR);
                g_object_unref(pixbuf);

                picture_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView)));
                pic_info = Picture_Info(pic);
                gtk_list_store_insert_with_values (picture_store, &iter1,
                                                   G_MAXINT,
                                                   PICTURE_COLUMN_PIC,
                                                   scaled_pixbuf,
                                                   PICTURE_COLUMN_TEXT,
                                                   pic_info,
                                                   PICTURE_COLUMN_DATA,
                                                   Picture_Copy_One (pic), -1);
                g_free(pic_info);

                if (select_it)
                    gtk_tree_selection_select_iter(selection, &iter1);
                g_object_unref(scaled_pixbuf);
            }else
            {
                GtkWidget *msgdialog;
                
                g_object_unref(loader);
                
                Log_Print (LOG_ERROR, "%s",
                           _("Cannot display the image because not enough data has been read to determine how to create the image buffer."));

                msgdialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow),
                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                                   GTK_MESSAGE_ERROR,
                                                   GTK_BUTTONS_CLOSE,
                                                   "%s",
                                                   _("Cannot display the image"));
                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdialog),
                                                          _("Not enough data has been read to determine how to create the image buffer."));
                gtk_window_set_title (GTK_WINDOW (msgdialog),
                                      _("Load Image File"));
                gtk_dialog_run(GTK_DIALOG(msgdialog));
                gtk_widget_destroy(msgdialog);
            }
        }else
        {
            Log_Print(LOG_ERROR,_("Error with 'loader_write': %s"), error->message);
            g_error_free(error);
        }
    }

    // Do also for next picture
    if (pic->next)
        PictureEntry_Update(pic->next, select_it);

    return;
}
コード例 #15
0
ファイル: live_view.c プロジェクト: CarVac/darktable
/*
    This file is part of darktable,
    copyright (c) 2009--2011 johannes hanika.
    copyright (c) 2012 tobias ellinghaus.
    copyright (c) 2014 henrik andersson.

    darktable is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    darktable is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with darktable.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "bauhaus/bauhaus.h"
#include "common/camera_control.h"
#include "common/darktable.h"
#include "common/image_cache.h"
#include "common/mipmap_cache.h"
#include "control/conf.h"
#include "control/control.h"
#include "control/jobs.h"
#include "dtgtk/button.h"
#include "gui/accelerators.h"
#include "gui/gtk.h"
#include "gui/guides.h"
#include "libs/lib.h"
#include "libs/lib_api.h"
#include <gdk/gdkkeysyms.h>

typedef enum dt_lib_live_view_flip_t
{
  FLAG_FLIP_NONE = 0,
  FLAG_FLIP_HORIZONTAL = 1<<0,
  FLAG_FLIP_VERTICAL = 1<<1,
  FLAG_FLIP_BOTH = FLAG_FLIP_HORIZONTAL|FLAG_FLIP_VERTICAL
} dt_lib_live_view_flip_t;

typedef enum dt_lib_live_view_overlay_t
{
  OVERLAY_NONE = 0,
  OVERLAY_SELECTED,
  OVERLAY_ID
} dt_lib_live_view_overlay_t;

#define HANDLE_SIZE 0.02

static const cairo_operator_t _overlay_modes[] = {
  CAIRO_OPERATOR_OVER, CAIRO_OPERATOR_XOR, CAIRO_OPERATOR_ADD, CAIRO_OPERATOR_SATURATE
#if(CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0))
  ,
  CAIRO_OPERATOR_MULTIPLY, CAIRO_OPERATOR_SCREEN, CAIRO_OPERATOR_OVERLAY, CAIRO_OPERATOR_DARKEN,
  CAIRO_OPERATOR_LIGHTEN, CAIRO_OPERATOR_COLOR_DODGE, CAIRO_OPERATOR_COLOR_BURN, CAIRO_OPERATOR_HARD_LIGHT,
  CAIRO_OPERATOR_SOFT_LIGHT, CAIRO_OPERATOR_DIFFERENCE, CAIRO_OPERATOR_EXCLUSION, CAIRO_OPERATOR_HSL_HUE,
  CAIRO_OPERATOR_HSL_SATURATION, CAIRO_OPERATOR_HSL_COLOR, CAIRO_OPERATOR_HSL_LUMINOSITY
#endif
};

DT_MODULE(1)

typedef struct dt_lib_live_view_t
{
  int imgid;
  int splitline_rotation;
  double overlay_x0, overlay_x1, overlay_y0, overlay_y1;
  double splitline_x, splitline_y; // 0..1
  gboolean splitline_dragging;

  GtkWidget *live_view, *live_view_zoom, *rotate_ccw, *rotate_cw, *flip;
  GtkWidget *focus_out_small, *focus_out_big, *focus_in_small, *focus_in_big;
  GtkWidget *guide_selector, *flip_guides, *guides_widgets;
  GList *guides_widgets_list;
  GtkWidget *overlay, *overlay_id_box, *overlay_id, *overlay_mode, *overlay_splitline;
} dt_lib_live_view_t;

static void guides_presets_set_visibility(dt_lib_live_view_t *lib, int which)
{
  if(which == 0)
  {
    gtk_widget_set_no_show_all(lib->guides_widgets, TRUE);
    gtk_widget_hide(lib->guides_widgets);
    gtk_widget_set_no_show_all(lib->flip_guides, TRUE);
    gtk_widget_hide(lib->flip_guides);
  }
  else
  {
    GtkWidget *widget = g_list_nth_data(lib->guides_widgets_list, which - 1);
    if(widget)
    {
      gtk_widget_set_no_show_all(lib->guides_widgets, FALSE);
      gtk_widget_show_all(lib->guides_widgets);
      gtk_stack_set_visible_child(GTK_STACK(lib->guides_widgets), widget);
    }
    else
    {
      gtk_widget_set_no_show_all(lib->guides_widgets, TRUE);
      gtk_widget_hide(lib->guides_widgets);
    }
    gtk_widget_set_no_show_all(lib->flip_guides, FALSE);
    gtk_widget_show_all(lib->flip_guides);
  }

  // TODO: add a support_flip flag to guides to hide the flip gui?
}

static void guides_presets_changed(GtkWidget *combo, dt_lib_live_view_t *lib)
{
  int which = dt_bauhaus_combobox_get(combo);
  guides_presets_set_visibility(lib, which);
}

static void overlay_changed(GtkWidget *combo, dt_lib_live_view_t *lib)
{
  int which = dt_bauhaus_combobox_get(combo);
  if(which == OVERLAY_NONE)
  {
    gtk_widget_set_visible(GTK_WIDGET(lib->overlay_mode), FALSE);
    gtk_widget_set_visible(GTK_WIDGET(lib->overlay_splitline), FALSE);
  }
  else
  {
    gtk_widget_set_visible(GTK_WIDGET(lib->overlay_mode), TRUE);
    gtk_widget_set_visible(GTK_WIDGET(lib->overlay_splitline), TRUE);
  }

  if(which == OVERLAY_ID)
    gtk_widget_set_visible(GTK_WIDGET(lib->overlay_id_box), TRUE);
  else
    gtk_widget_set_visible(GTK_WIDGET(lib->overlay_id_box), FALSE);
}


const char *name(dt_lib_module_t *self)
{
  return _("live view");
}

uint32_t views(dt_lib_module_t *self)
{
  return DT_VIEW_TETHERING;
}

uint32_t container(dt_lib_module_t *self)
{
  return DT_UI_CONTAINER_PANEL_RIGHT_CENTER;
}


void gui_reset(dt_lib_module_t *self)
{
}

int position()
{
  return 998;
}

void init_key_accels(dt_lib_module_t *self)
{
  dt_accel_register_lib(self, NC_("accel", "toggle live view"), GDK_KEY_v, 0);
  dt_accel_register_lib(self, NC_("accel", "zoom live view"), GDK_KEY_z, 0);
  dt_accel_register_lib(self, NC_("accel", "rotate 90 degrees CCW"), 0, 0);
  dt_accel_register_lib(self, NC_("accel", "rotate 90 degrees CW"), 0, 0);
  dt_accel_register_lib(self, NC_("accel", "flip horizontally"), 0, 0);
  dt_accel_register_lib(self, NC_("accel", "move focus point in (big steps)"), 0, 0);
  dt_accel_register_lib(self, NC_("accel", "move focus point in (small steps)"), 0, 0);
  dt_accel_register_lib(self, NC_("accel", "move focus point out (small steps)"), 0, 0);
  dt_accel_register_lib(self, NC_("accel", "move focus point out (big steps)"), 0, 0);
}

void connect_key_accels(dt_lib_module_t *self)
{
  dt_lib_live_view_t *lib = (dt_lib_live_view_t *)self->data;

  dt_accel_connect_button_lib(self, "toggle live view", GTK_WIDGET(lib->live_view));
  dt_accel_connect_button_lib(self, "zoom live view", GTK_WIDGET(lib->live_view_zoom));
  dt_accel_connect_button_lib(self, "rotate 90 degrees CCW", GTK_WIDGET(lib->rotate_ccw));
  dt_accel_connect_button_lib(self, "rotate 90 degrees CW", GTK_WIDGET(lib->rotate_cw));
  dt_accel_connect_button_lib(self, "flip horizontally", GTK_WIDGET(lib->flip));
  dt_accel_connect_button_lib(self, "move focus point in (big steps)", GTK_WIDGET(lib->focus_in_big));
  dt_accel_connect_button_lib(self, "move focus point in (small steps)", GTK_WIDGET(lib->focus_in_small));
  dt_accel_connect_button_lib(self, "move focus point out (small steps)", GTK_WIDGET(lib->focus_out_small));
  dt_accel_connect_button_lib(self, "move focus point out (big steps)", GTK_WIDGET(lib->focus_out_big));
}

static void _rotate_ccw(GtkWidget *widget, gpointer user_data)
{
  dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera;
  cam->live_view_rotation = (cam->live_view_rotation + 1) % 4; // 0 -> 1 -> 2 -> 3 -> 0 -> ...
}

static void _rotate_cw(GtkWidget *widget, gpointer user_data)
{
  dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera;
  cam->live_view_rotation = (cam->live_view_rotation + 3) % 4; // 0 -> 3 -> 2 -> 1 -> 0 -> ...
}

// Congratulations to Simon for being the first one recognizing live view in a screen shot ^^
static void _toggle_live_view_clicked(GtkWidget *widget, gpointer user_data)
{
  if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE)
  {
    if(dt_camctl_camera_start_live_view(darktable.camctl) == FALSE)
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE);
  }
  else
  {
    dt_camctl_camera_stop_live_view(darktable.camctl);
  }
}

// TODO: using a toggle button would be better, but this setting can also be changed by right clicking on the
// canvas (src/views/capture.c).
//       maybe using a signal would work? i have no idea.
static void _zoom_live_view_clicked(GtkWidget *widget, gpointer user_data)
{
  dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera;
  if(cam->is_live_viewing)
  {
    cam->live_view_zoom = !cam->live_view_zoom;
    if(cam->live_view_zoom == TRUE)
      dt_camctl_camera_set_property_string(darktable.camctl, NULL, "eoszoom", "5");
    else
      dt_camctl_camera_set_property_string(darktable.camctl, NULL, "eoszoom", "1");
  }
}

static void _focus_button_clicked(GtkWidget *widget, gpointer user_data)
{
  int focus = GPOINTER_TO_INT(user_data);
  dt_camctl_camera_set_property_choice(darktable.camctl, NULL, "manualfocusdrive", focus);
}

static void _toggle_flip_clicked(GtkWidget *widget, gpointer user_data)
{
  dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera;
  cam->live_view_flip = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}

static void _overlay_id_changed(GtkWidget *widget, gpointer user_data)
{
  dt_lib_live_view_t *lib = (dt_lib_live_view_t *)user_data;
  lib->imgid = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
  dt_conf_set_int("plugins/lighttable/live_view/overlay_imgid", lib->imgid);
}

static void _overlay_mode_changed(GtkWidget *combo, gpointer user_data)
{
  dt_conf_set_int("plugins/lighttable/live_view/overlay_mode", dt_bauhaus_combobox_get(combo));
}

static void _overlay_splitline_changed(GtkWidget *combo, gpointer user_data)
{
  dt_conf_set_int("plugins/lighttable/live_view/splitline", dt_bauhaus_combobox_get(combo));
}

void gui_init(dt_lib_module_t *self)
{
  self->data = calloc(1, sizeof(dt_lib_live_view_t));

  // Setup lib data
  dt_lib_live_view_t *lib = self->data;
  lib->splitline_x = lib->splitline_y = 0.5;

  // Setup gui
  self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
  GtkWidget *box;

  box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
  gtk_box_pack_start(GTK_BOX(self->widget), box, TRUE, TRUE, 0);
  lib->live_view = dtgtk_togglebutton_new(dtgtk_cairo_paint_eye, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER);
  lib->live_view_zoom = dtgtk_button_new(
      dtgtk_cairo_paint_zoom, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER); // TODO: see _zoom_live_view_clicked
  lib->rotate_ccw = dtgtk_button_new(dtgtk_cairo_paint_refresh, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER);
  lib->rotate_cw = dtgtk_button_new(dtgtk_cairo_paint_refresh,
                                    CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_UP);
  lib->flip = dtgtk_togglebutton_new(dtgtk_cairo_paint_flip,
                                     CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_UP);

  gtk_box_pack_start(GTK_BOX(box), lib->live_view, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(box), lib->live_view_zoom, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(box), lib->rotate_ccw, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(box), lib->rotate_cw, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(box), lib->flip, TRUE, TRUE, 0);

  gtk_widget_set_tooltip_text(lib->live_view, _("toggle live view"));
  gtk_widget_set_tooltip_text(lib->live_view_zoom, _("zoom live view"));
  gtk_widget_set_tooltip_text(lib->rotate_ccw, _("rotate 90 degrees ccw"));
  gtk_widget_set_tooltip_text(lib->rotate_cw, _("rotate 90 degrees cw"));
  gtk_widget_set_tooltip_text(lib->flip, _("flip live view horizontally"));

  g_signal_connect(G_OBJECT(lib->live_view), "clicked", G_CALLBACK(_toggle_live_view_clicked), lib);
  g_signal_connect(G_OBJECT(lib->live_view_zoom), "clicked", G_CALLBACK(_zoom_live_view_clicked), lib);
  g_signal_connect(G_OBJECT(lib->rotate_ccw), "clicked", G_CALLBACK(_rotate_ccw), lib);
  g_signal_connect(G_OBJECT(lib->rotate_cw), "clicked", G_CALLBACK(_rotate_cw), lib);
  g_signal_connect(G_OBJECT(lib->flip), "clicked", G_CALLBACK(_toggle_flip_clicked), lib);

  // focus buttons
  box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
  gtk_box_pack_start(GTK_BOX(self->widget), box, TRUE, TRUE, 0);
  lib->focus_in_big = dtgtk_button_new(dtgtk_cairo_paint_solid_triangle,
                                       CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_LEFT);
  lib->focus_in_small
      = dtgtk_button_new(dtgtk_cairo_paint_arrow, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER
                                                  | CPF_DIRECTION_LEFT); // TODO icon not centered
  lib->focus_out_small = dtgtk_button_new(dtgtk_cairo_paint_arrow, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER
                                                                   | CPF_DIRECTION_RIGHT); // TODO same here
  lib->focus_out_big = dtgtk_button_new(dtgtk_cairo_paint_solid_triangle,
                                        CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_RIGHT);

  gtk_box_pack_start(GTK_BOX(box), lib->focus_in_big, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(box), lib->focus_in_small, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(box), lib->focus_out_small, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(box), lib->focus_out_big, TRUE, TRUE, 0);

  gtk_widget_set_tooltip_text(lib->focus_in_big, _("move focus point in (big steps)"));
  gtk_widget_set_tooltip_text(lib->focus_in_small, _("move focus point in (small steps)"));
  gtk_widget_set_tooltip_text(lib->focus_out_small, _("move focus point out (small steps)"));
  gtk_widget_set_tooltip_text(lib->focus_out_big, _("move focus point out (big steps)"));

  // Near 3
  g_signal_connect(G_OBJECT(lib->focus_in_big), "clicked", G_CALLBACK(_focus_button_clicked),
                   GINT_TO_POINTER(2));
  // Near 1
  g_signal_connect(G_OBJECT(lib->focus_in_small), "clicked", G_CALLBACK(_focus_button_clicked),
                   GINT_TO_POINTER(0));
  // Far 1
  g_signal_connect(G_OBJECT(lib->focus_out_small), "clicked", G_CALLBACK(_focus_button_clicked),
                   GINT_TO_POINTER(4));
  // Far 3
  g_signal_connect(G_OBJECT(lib->focus_out_big), "clicked", G_CALLBACK(_focus_button_clicked),
                   GINT_TO_POINTER(6));

  // Guides
  lib->guide_selector = dt_bauhaus_combobox_new(NULL);
  dt_bauhaus_widget_set_label(lib->guide_selector, NULL, _("guides"));
  gtk_box_pack_start(GTK_BOX(self->widget), lib->guide_selector, TRUE, TRUE, 0);

  lib->guides_widgets = gtk_stack_new();
  gtk_stack_set_homogeneous(GTK_STACK(lib->guides_widgets), FALSE);
  gtk_box_pack_start(GTK_BOX(self->widget), lib->guides_widgets, TRUE, TRUE, 0);

  dt_bauhaus_combobox_add(lib->guide_selector, _("none"));
  int i = 0;
  for(GList *iter = darktable.guides; iter; iter = g_list_next(iter), i++)
  {
    GtkWidget *widget = NULL;
    dt_guides_t *guide = (dt_guides_t *)iter->data;
    dt_bauhaus_combobox_add(lib->guide_selector, _(guide->name));
    if(guide->widget)
    {
      // generate some unique name so that we can have the same name several times
      char name[5];
      snprintf(name, sizeof(name), "%d", i);
      widget = guide->widget(NULL, guide->user_data);
      gtk_widget_show_all(widget);
      gtk_stack_add_named(GTK_STACK(lib->guides_widgets), widget, name);
    }
    lib->guides_widgets_list = g_list_append(lib->guides_widgets_list, widget);
  }
  gtk_widget_set_no_show_all(lib->guides_widgets, TRUE);

  gtk_widget_set_tooltip_text(lib->guide_selector, _("display guide lines to help compose your photograph"));
  g_signal_connect(G_OBJECT(lib->guide_selector), "value-changed", G_CALLBACK(guides_presets_changed), lib);

  lib->flip_guides = dt_bauhaus_combobox_new(NULL);
  dt_bauhaus_widget_set_label(lib->flip_guides, NULL, _("flip"));
  dt_bauhaus_combobox_add(lib->flip_guides, _("none"));
  dt_bauhaus_combobox_add(lib->flip_guides, _("horizontally"));
  dt_bauhaus_combobox_add(lib->flip_guides, _("vertically"));
  dt_bauhaus_combobox_add(lib->flip_guides, _("both"));
  gtk_widget_set_tooltip_text(lib->flip_guides, _("flip guides"));
  gtk_box_pack_start(GTK_BOX(self->widget), lib->flip_guides, TRUE, TRUE, 0);

  lib->overlay = dt_bauhaus_combobox_new(NULL);
  dt_bauhaus_widget_set_label(lib->overlay, NULL, _("overlay"));
  dt_bauhaus_combobox_add(lib->overlay, _("none"));
  dt_bauhaus_combobox_add(lib->overlay, _("selected image"));
  dt_bauhaus_combobox_add(lib->overlay, _("id"));
  gtk_widget_set_tooltip_text(lib->overlay, _("overlay another image over the live view"));
  g_signal_connect(G_OBJECT(lib->overlay), "value-changed", G_CALLBACK(overlay_changed), lib);
  gtk_box_pack_start(GTK_BOX(self->widget), lib->overlay, TRUE, TRUE, 0);

  lib->overlay_id_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
  GtkWidget *label = gtk_label_new(_("image id"));
  gtk_widget_set_halign(label, GTK_ALIGN_START);
  lib->overlay_id = gtk_spin_button_new_with_range(0, 1000000000, 1);
  gtk_spin_button_set_digits(GTK_SPIN_BUTTON(lib->overlay_id), 0);
  gtk_widget_set_tooltip_text(lib->overlay_id, _("enter image id of the overlay manually"));
  g_signal_connect(G_OBJECT(lib->overlay_id), "value-changed", G_CALLBACK(_overlay_id_changed), lib);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(lib->overlay_id),
                            dt_conf_get_int("plugins/lighttable/live_view/overlay_imgid"));
  gtk_box_pack_start(GTK_BOX(lib->overlay_id_box), label, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(lib->overlay_id_box), lib->overlay_id, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(self->widget), lib->overlay_id_box, TRUE, TRUE, 0);
  gtk_widget_show(lib->overlay_id);
  gtk_widget_show(label);

  lib->overlay_mode = dt_bauhaus_combobox_new(NULL);
  dt_bauhaus_widget_set_label(lib->overlay_mode, NULL, _("overlay mode"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "normal"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "xor"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "add"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "saturate"));
#if(CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0))
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "multiply"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "screen"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "overlay"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "darken"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "lighten"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "color dodge"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "color burn"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "hard light"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "soft light"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "difference"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "exclusion"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "HSL hue"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "HSL saturation"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "HSL color"));
  dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "HSL luminosity"));
#endif
  gtk_widget_set_tooltip_text(lib->overlay_mode, _("mode of the overlay"));
  dt_bauhaus_combobox_set(lib->overlay_mode, dt_conf_get_int("plugins/lighttable/live_view/overlay_mode"));
  g_signal_connect(G_OBJECT(lib->overlay_mode), "value-changed", G_CALLBACK(_overlay_mode_changed), lib);
  gtk_box_pack_start(GTK_BOX(self->widget), lib->overlay_mode, TRUE, TRUE, 0);

  lib->overlay_splitline = dt_bauhaus_combobox_new(NULL);
  dt_bauhaus_widget_set_label(lib->overlay_splitline, NULL, _("split line"));
  dt_bauhaus_combobox_add(lib->overlay_splitline, _("off"));
  dt_bauhaus_combobox_add(lib->overlay_splitline, _("on"));
  gtk_widget_set_tooltip_text(lib->overlay_splitline, _("only draw part of the overlay"));
  dt_bauhaus_combobox_set(lib->overlay_splitline, dt_conf_get_int("plugins/lighttable/live_view/splitline"));
  g_signal_connect(G_OBJECT(lib->overlay_splitline), "value-changed", G_CALLBACK(_overlay_splitline_changed),
                   lib);
  gtk_box_pack_start(GTK_BOX(self->widget), lib->overlay_splitline, TRUE, TRUE, 0);

  gtk_widget_set_visible(GTK_WIDGET(lib->overlay_mode), FALSE);
  gtk_widget_set_visible(GTK_WIDGET(lib->overlay_id_box), FALSE);
  gtk_widget_set_visible(GTK_WIDGET(lib->overlay_splitline), FALSE);

  gtk_widget_set_no_show_all(GTK_WIDGET(lib->overlay_mode), TRUE);
  gtk_widget_set_no_show_all(GTK_WIDGET(lib->overlay_id_box), TRUE);
  gtk_widget_set_no_show_all(GTK_WIDGET(lib->overlay_splitline), TRUE);

  guides_presets_set_visibility(lib, 0);
}

void gui_cleanup(dt_lib_module_t *self)
{
  // dt_lib_live_view_t *lib = self->data;

  // g_list_free(lib->guides_widgets_list);
  // INTENTIONAL. it's supposed to be leaky until lua is fixed.

  free(self->data);
  self->data = NULL;
}

void view_enter(struct dt_lib_module_t *self,struct dt_view_t *old_view,struct dt_view_t *new_view)
{
  // disable buttons that won't work with this camera
  // TODO: initialize tethering mode outside of libs/camera.s so we can use darktable.camctl->active_camera
  // here
  dt_lib_live_view_t *lib = self->data;
  const dt_camera_t *cam = darktable.camctl->active_camera;
  if(cam == NULL) cam = darktable.camctl->wanted_camera;

  gboolean sensitive = cam && cam->can_live_view_advanced;

  gtk_widget_set_sensitive(lib->live_view_zoom, sensitive);
  gtk_widget_set_sensitive(lib->focus_in_big, sensitive);
  gtk_widget_set_sensitive(lib->focus_in_small, sensitive);
  gtk_widget_set_sensitive(lib->focus_out_big, sensitive);
  gtk_widget_set_sensitive(lib->focus_out_small, sensitive);
}

// TODO: find out where the zoom window is and draw overlay + grid accordingly
#define MARGIN 20
#define BAR_HEIGHT 18 /* see libs/camera.c */
void gui_post_expose(dt_lib_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx,
                     int32_t pointery)
{
  dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera;
  dt_lib_live_view_t *lib = self->data;

  if(cam->is_live_viewing == FALSE || cam->live_view_zoom == TRUE) return;

  dt_pthread_mutex_lock(&cam->live_view_pixbuf_mutex);
  if(GDK_IS_PIXBUF(cam->live_view_pixbuf) == FALSE)
  {
    dt_pthread_mutex_unlock(&cam->live_view_pixbuf_mutex);
    return;
  }
  double w = width - (MARGIN * 2.0f);
  double h = height - (MARGIN * 2.0f) - BAR_HEIGHT;
  gint pw = gdk_pixbuf_get_width(cam->live_view_pixbuf);
  gint ph = gdk_pixbuf_get_height(cam->live_view_pixbuf);
  lib->overlay_x0 = lib->overlay_x1 = lib->overlay_y0 = lib->overlay_y1 = 0.0;

  gboolean use_splitline = (dt_bauhaus_combobox_get(lib->overlay_splitline) == 1);

  // OVERLAY
  int imgid = 0;
  switch(dt_bauhaus_combobox_get(lib->overlay))
  {
    case OVERLAY_SELECTED:
      imgid = dt_view_tethering_get_selected_imgid(darktable.view_manager);
      break;
    case OVERLAY_ID:
      imgid = lib->imgid;
      break;
  }
  if(imgid > 0)
  {
    cairo_save(cr);
    const dt_image_t *img = dt_image_cache_testget(darktable.image_cache, imgid, 'r');
    // if the user points at this image, we really want it:
    if(!img) img = dt_image_cache_get(darktable.image_cache, imgid, 'r');

    int zoom = 1;
    float imgwd = 0.90f;
    if(zoom == 1)
    {
      imgwd = .97f;
    }

    dt_mipmap_buffer_t buf;
    dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, imgwd * w, imgwd * h);
    dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, mip, 0, 'r');

    float scale = 1.0;
    cairo_surface_t *surface = NULL;
    if(buf.buf)
    {
      const int32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, buf.width);
      surface = cairo_image_surface_create_for_data(buf.buf, CAIRO_FORMAT_RGB24, buf.width,
                                                    buf.height, stride);
      if(zoom == 1)
      {
        scale = fminf(fminf(w, pw) / (float)buf.width, fminf(h, ph) / (float)buf.height);
      }
      else
        scale = fminf(w * imgwd / (float)buf.width, h * imgwd / (float)buf.height);
    }

    // draw centered and fitted:
    cairo_translate(cr, width / 2.0, (height + BAR_HEIGHT) / 2.0f);
    cairo_scale(cr, scale, scale);

    if(buf.buf)
    {
      cairo_translate(cr, -.5f * buf.width, -.5f * buf.height);

      if(use_splitline)
      {
        double x0, y0, x1, y1;
        switch(lib->splitline_rotation)
        {
          case 0:
            x0 = 0.0;
            y0 = 0.0;
            x1 = buf.width * lib->splitline_x;
            y1 = buf.height;
            break;
          case 1:
            x0 = 0.0;
            y0 = 0.0;
            x1 = buf.width;
            y1 = buf.height * lib->splitline_y;
            break;
          case 2:
            x0 = buf.width * lib->splitline_x;
            y0 = 0.0;
            x1 = buf.width;
            y1 = buf.height;
            break;
          case 3:
            x0 = 0.0;
            y0 = buf.height * lib->splitline_y;
            x1 = buf.width;
            y1 = buf.height;
            break;
          default:
            fprintf(stderr, "OMFG, the world will collapse, this shouldn't be reachable!\n");
            return;
        }

        cairo_rectangle(cr, x0, y0, x1, y1);
        cairo_clip(cr);
      }

      cairo_set_source_surface(cr, surface, 0, 0);
      // set filter no nearest:
      // in skull mode, we want to see big pixels.
      // in 1 iir mode for the right mip, we want to see exactly what the pipe gave us, 1:1 pixel for pixel.
      // in between, filtering just makes stuff go unsharp.
      if((buf.width <= 8 && buf.height <= 8) || fabsf(scale - 1.0f) < 0.01f)
        cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
      cairo_rectangle(cr, 0, 0, buf.width, buf.height);
      int overlay_modes_index = dt_bauhaus_combobox_get(lib->overlay_mode);
      if(overlay_modes_index >= 0)
      {
        cairo_operator_t mode = _overlay_modes[overlay_modes_index];
        cairo_set_operator(cr, mode);
      }
      cairo_fill(cr);
      cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
      cairo_surface_destroy(surface);
    }
    cairo_restore(cr);
    if(buf.buf) dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
    if(img) dt_image_cache_read_release(darktable.image_cache, img);

    // ON CANVAS CONTROLS
    if(use_splitline)
    {
      float scale = fminf(1.0, fminf(w / pw, h / ph));

      // image coordinates
      lib->overlay_x0 = 0.5 * (width - pw * scale);
      lib->overlay_y0 = 0.5 * (height - ph * scale + BAR_HEIGHT);
      lib->overlay_x1 = lib->overlay_x0 + pw * scale;
      lib->overlay_y1 = lib->overlay_y0 + ph * scale;

      // splitline position to absolute coords:
      double sl_x = lib->overlay_x0 + lib->splitline_x * pw * scale;
      double sl_y = lib->overlay_y0 + lib->splitline_y * ph * scale;

      int x0 = sl_x, y0 = 0.0, x1 = x0, y1 = height;
      if(lib->splitline_rotation % 2 != 0)
      {
        x0 = 0.0;
        y0 = sl_y;
        x1 = width;
        y1 = y0;
      }
      gboolean mouse_over_control = (lib->splitline_rotation % 2 == 0) ? (fabs(sl_x - pointerx) < 5)
                                                                       : (fabs(sl_y - pointery) < 5);
      cairo_save(cr);
      cairo_set_source_rgb(cr, .7, .7, .7);
      cairo_set_line_width(cr, (mouse_over_control ? 2.0 : 0.5));

      cairo_move_to(cr, x0, y0);
      cairo_line_to(cr, x1, y1);
      cairo_stroke(cr);

      /* if mouse over control lets draw center rotate control, hide if split is dragged */
      if(!lib->splitline_dragging && mouse_over_control)
      {
        cairo_set_line_width(cr, 0.5);
        double s = width * HANDLE_SIZE;
        dtgtk_cairo_paint_refresh(cr, sl_x - (s * 0.5), sl_y - (s * 0.5), s, s, 1);
      }

      cairo_restore(cr);
    }
  }

  // GUIDES
  if(cam->live_view_rotation % 2 == 1)
  {
    gint tmp = pw;
    pw = ph;
    ph = tmp;
  }
  float scale = 1.0;
  //   if(cam->live_view_zoom == FALSE)
  //   {
  if(pw > w) scale = w / pw;
  if(ph > h) scale = fminf(scale, h / ph);
  //   }
  double sw = scale * pw;
  double sh = scale * ph;

  // draw guides
  int guide_flip = dt_bauhaus_combobox_get(lib->flip_guides);
  double left = (width - sw) * 0.5;
  double top = (height + BAR_HEIGHT - sh) * 0.5;

  double dashes = 5.0;

  cairo_save(cr);
  cairo_rectangle(cr, left, top, sw, sh);
  cairo_clip(cr);
  cairo_set_dash(cr, &dashes, 1, 0);

  // Move coordinates to local center selection.
  cairo_translate(cr, (sw / 2 + left), (sh / 2 + top));

  // Flip horizontal.
  if(guide_flip & FLAG_FLIP_HORIZONTAL) cairo_scale(cr, -1, 1);
  // Flip vertical.
  if(guide_flip & FLAG_FLIP_VERTICAL) cairo_scale(cr, 1, -1);

  int which = dt_bauhaus_combobox_get(lib->guide_selector);
  dt_guides_t *guide = (dt_guides_t *)g_list_nth_data(darktable.guides, which - 1);
  if(guide)
  {
    guide->draw(cr, -sw / 2, -sh / 2, sw, sh, 1.0, guide->user_data);
    cairo_stroke_preserve(cr);
    cairo_set_dash(cr, &dashes, 0, 0);
    cairo_set_source_rgba(cr, .3, .3, .3, .8);
    cairo_stroke(cr);
  }
  cairo_restore(cr);
  dt_pthread_mutex_unlock(&cam->live_view_pixbuf_mutex);
}
コード例 #16
0
ファイル: gap_pview_da.c プロジェクト: nhorman/gimp-gap
/* ------------------------------
 * gap_pview_render_f_from_pixbuf (slow)
 * ------------------------------
 * render drawing_area widget from src_pixbuf buffer
 * scaling and flattening against checkerboard background
 * is done implicite using GDK-pixbuf procedures
 *            
 * Thumbnails at size 128 rendered to Widget Size 256x256 pixels
 * at my Pentium IV 2600 MHZ
 * can be Played at Speed of  98 Frames/sec without dropping frames.
 *
 * The other Implementation without GDK-pixbuf procedures
 * is faster (at least on my machine), therefore GAP_PVIEW_USE_GDK_PIXBUF_RENDERING
 * is NOT defined per default.
 */
void
gap_pview_render_f_from_pixbuf (GapPView *pv_ptr
  , GdkPixbuf *src_pixbuf
  , gint32 flip_request
  , gint32 flip_status
  )
{
  static int l_checksize_tab[17] = { 2, 4, 8, 8, 16, 16, 16, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64 };
  int l_check_size;

  /* printf("gap_pview_render_f_from_pixbuf --- USE GDK-PIXBUF procedures\n"); */
  
  if(pv_ptr == NULL) { return; }
  if(pv_ptr->da_widget == NULL) { return; }
  if(pv_ptr->da_widget->window == NULL)
  { 
    if(gap_debug)
    {
      printf("gap_pview_render_f_from_pixbuf: drawing_area window pointer is NULL, cant render\n");
    }
    return ;
  }

  if(src_pixbuf == NULL)
  {
    if(gap_debug)
    {
      printf("gap_pview_render_f_from_pixbuf: src_pixbuf is NULL, cant render\n");
    }
    return ;
  }

  /* clear flag to let gap_pview_repaint procedure know
   * to use the pixbuf rather than pv_area_data or pixmap for refresh
   */
  pv_ptr->use_pixmap_repaint = FALSE;
  pv_ptr->use_pixbuf_repaint = TRUE;
  p_free_desaturated_area_data(pv_ptr);

  /* l_check_size must be a power of 2 (using fixed size for 1.st test) */
  l_check_size = l_checksize_tab[MIN((pv_ptr->pv_check_size >> 2), 8)];
  if(pv_ptr->pixbuf)
  {
    /* free old (refresh) pixbuf if there is one */
    g_object_unref(pv_ptr->pixbuf);
  }
  
  /* scale and flatten the pixbuf */
  pv_ptr->pixbuf = gdk_pixbuf_composite_color_simple(
                         src_pixbuf
                      , (int) pv_ptr->pv_width
                      , (int) pv_ptr->pv_height
                      , GDK_INTERP_NEAREST
                      , 255                          /* overall_alpha */
                      , (int)l_check_size            /* power of 2 required */
                      , PREVIEW_BG_GRAY1_GDK
                      , PREVIEW_BG_GRAY2_GDK
                      );
  if(gap_debug)
  {
    int nchannels;
    int rowstride;
    int width;
    int height;
    guchar *pix_data;
    gboolean has_alpha;

    width = gdk_pixbuf_get_width(pv_ptr->pixbuf);
    height = gdk_pixbuf_get_height(pv_ptr->pixbuf);
    nchannels = gdk_pixbuf_get_n_channels(pv_ptr->pixbuf);
    pix_data = gdk_pixbuf_get_pixels(pv_ptr->pixbuf);
    has_alpha = gdk_pixbuf_get_has_alpha(pv_ptr->pixbuf);
    rowstride = gdk_pixbuf_get_rowstride(pv_ptr->pixbuf);

    printf("gap_pview_render_f_from_pixbuf (AFTER SCALE/FLATTEN):\n");
    printf(" l_check_size: %d (%d)\n", (int)l_check_size, pv_ptr->pv_check_size);
    printf(" width: %d\n", (int)width );
    printf(" height: %d\n", (int)height );
    printf(" nchannels: %d\n", (int)nchannels );
    printf(" pix_data: %d\n", (int)pix_data );
    printf(" has_alpha: %d\n", (int)has_alpha );
    printf(" rowstride: %d\n", (int)rowstride );
  }

  {
    gint32 l_flip_to_perform;
  
    l_flip_to_perform = p_calculate_flip_request(pv_ptr, flip_request, flip_status);
    if(l_flip_to_perform != GAP_STB_FLIP_NONE)
    {
      p_replace_pixbuf_by_flipped_pixbuf(pv_ptr, l_flip_to_perform);
    }
  }

  gap_pview_repaint(pv_ptr);

}       /* end gap_pview_render_f_from_pixbuf */
コード例 #17
0
static nsresult
moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIURI* aURI,
                          nsIChannel** aChannel)
{
  int width = gdk_pixbuf_get_width(aPixbuf);
  int height = gdk_pixbuf_get_height(aPixbuf);
  NS_ENSURE_TRUE(height < 256 && width < 256 && height > 0 && width > 0 &&
                 gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB &&
                 gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 &&
                 gdk_pixbuf_get_has_alpha(aPixbuf) &&
                 gdk_pixbuf_get_n_channels(aPixbuf) == 4,
                 NS_ERROR_UNEXPECTED);

  const int n_channels = 4;
  gsize buf_size = 2 + n_channels * height * width;
  uint8_t* const buf = (uint8_t*)moz_xmalloc(buf_size);
  NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
  uint8_t* out = buf;

  *(out++) = width;
  *(out++) = height;

  const guchar* const pixels = gdk_pixbuf_get_pixels(aPixbuf);
  int rowextra = gdk_pixbuf_get_rowstride(aPixbuf) - width * n_channels;

  // encode the RGB data and the A data
  const guchar* in = pixels;
  for (int y = 0; y < height; ++y, in += rowextra) {
    for (int x = 0; x < width; ++x) {
      uint8_t r = *(in++);
      uint8_t g = *(in++);
      uint8_t b = *(in++);
      uint8_t a = *(in++);
#define DO_PREMULTIPLY(c_) uint8_t(uint16_t(c_) * uint16_t(a) / uint16_t(255))
#if MOZ_LITTLE_ENDIAN
      *(out++) = DO_PREMULTIPLY(b);
      *(out++) = DO_PREMULTIPLY(g);
      *(out++) = DO_PREMULTIPLY(r);
      *(out++) = a;
#else
      *(out++) = a;
      *(out++) = DO_PREMULTIPLY(r);
      *(out++) = DO_PREMULTIPLY(g);
      *(out++) = DO_PREMULTIPLY(b);
#endif
#undef DO_PREMULTIPLY
    }
  }

  NS_ASSERTION(out == buf + buf_size, "size miscalculation");

  nsresult rv;
  nsCOMPtr<nsIStringInputStream> stream =
    do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);

  // Prevent the leaking of buf
  if (NS_WARN_IF(NS_FAILED(rv))) {
    free(buf);
    return rv;
  }

  // stream takes ownership of buf and will free it on destruction.
  // This function cannot fail.
  rv = stream->AdoptData((char*)buf, buf_size);

  // If this no longer holds then re-examine buf's lifetime.
  MOZ_ASSERT(NS_SUCCEEDED(rv));
  NS_ENSURE_SUCCESS(rv, rv);

  // nsIconProtocolHandler::NewChannel2 will provide the correct loadInfo for
  // this iconChannel. Use the most restrictive security settings for the
  // temporary loadInfo to make sure the channel can not be openend.
  nsCOMPtr<nsIPrincipal> nullPrincipal = NullPrincipal::Create();
  return NS_NewInputStreamChannel(aChannel,
                                  aURI,
                                  stream,
                                  nullPrincipal,
                                  nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
                                  nsIContentPolicy::TYPE_INTERNAL_IMAGE,
                                  NS_LITERAL_CSTRING(IMAGE_ICON_MS));
}
コード例 #18
0
ファイル: nsIconChannel.cpp プロジェクト: Type-of-Tool/ExMail
static nsresult
moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIURI *aURI,
                          nsIChannel **aChannel)
{
  int width = gdk_pixbuf_get_width(aPixbuf);
  int height = gdk_pixbuf_get_height(aPixbuf);
  NS_ENSURE_TRUE(height < 256 && width < 256 && height > 0 && width > 0 &&
                 gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB &&
                 gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 &&
                 gdk_pixbuf_get_has_alpha(aPixbuf) &&
                 gdk_pixbuf_get_n_channels(aPixbuf) == 4,
                 NS_ERROR_UNEXPECTED);

  const int n_channels = 4;
  gsize buf_size = 2 + n_channels * height * width;
  uint8_t * const buf = (uint8_t*)NS_Alloc(buf_size);
  NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
  uint8_t *out = buf;

  *(out++) = width;
  *(out++) = height;

  const guchar * const pixels = gdk_pixbuf_get_pixels(aPixbuf);
  int rowextra = gdk_pixbuf_get_rowstride(aPixbuf) - width * n_channels;

  // encode the RGB data and the A data
  const guchar * in = pixels;
  for (int y = 0; y < height; ++y, in += rowextra) {
    for (int x = 0; x < width; ++x) {
      uint8_t r = *(in++);
      uint8_t g = *(in++);
      uint8_t b = *(in++);
      uint8_t a = *(in++);
#define DO_PREMULTIPLY(c_) uint8_t(uint16_t(c_) * uint16_t(a) / uint16_t(255))
#ifdef IS_LITTLE_ENDIAN
      *(out++) = DO_PREMULTIPLY(b);
      *(out++) = DO_PREMULTIPLY(g);
      *(out++) = DO_PREMULTIPLY(r);
      *(out++) = a;
#else
      *(out++) = a;
      *(out++) = DO_PREMULTIPLY(r);
      *(out++) = DO_PREMULTIPLY(g);
      *(out++) = DO_PREMULTIPLY(b);
#endif
#undef DO_PREMULTIPLY
    }
  }

  NS_ASSERTION(out == buf + buf_size, "size miscalculation");

  nsresult rv;
  nsCOMPtr<nsIStringInputStream> stream =
    do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = stream->AdoptData((char*)buf, buf_size);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = NS_NewInputStreamChannel(aChannel, aURI, stream,
                                NS_LITERAL_CSTRING("image/icon"));
  return rv;
}
コード例 #19
0
/**
 * as_image_save_pixbuf:
 * @image: a #AsImage instance.
 * @width: target width, or 0 for default
 * @height: target height, or 0 for default
 * @flags: some #AsImageSaveFlags values, e.g. %AS_IMAGE_SAVE_FLAG_PAD_16_9
 *
 * Resamples a pixbuf to a specific size.
 *
 * Returns: (transfer full): A #GdkPixbuf of the specified size
 *
 * Since: 0.1.6
 **/
GdkPixbuf *
as_image_save_pixbuf (AsImage *image,
		      guint width,
		      guint height,
		      AsImageSaveFlags flags)
{
	AsImagePrivate *priv = GET_PRIVATE (image);
	GdkPixbuf *pixbuf = NULL;
	guint tmp_height;
	guint tmp_width;
	guint pixbuf_height;
	guint pixbuf_width;
	g_autoptr(GdkPixbuf) pixbuf_tmp = NULL;

	/* never set */
	if (priv->pixbuf == NULL)
		return NULL;

	/* 0 means 'default' */
	if (width == 0)
		width = (guint) gdk_pixbuf_get_width (priv->pixbuf);
	if (height == 0)
		height = (guint) gdk_pixbuf_get_height (priv->pixbuf);

	/* don't do anything to an image with the correct size */
	pixbuf_width = (guint) gdk_pixbuf_get_width (priv->pixbuf);
	pixbuf_height = (guint) gdk_pixbuf_get_height (priv->pixbuf);
	if (width == pixbuf_width && height == pixbuf_height)
		return g_object_ref (priv->pixbuf);

	/* is the aspect ratio of the source perfectly 16:9 */
	if (flags == AS_IMAGE_SAVE_FLAG_NONE ||
	    (pixbuf_width / 16) * 9 == pixbuf_height) {
		pixbuf = gdk_pixbuf_scale_simple (priv->pixbuf,
						  (gint) width, (gint) height,
						  GDK_INTERP_HYPER);
		if ((flags & AS_IMAGE_SAVE_FLAG_SHARPEN) > 0)
			as_pixbuf_sharpen (pixbuf, 1, -0.5);
		if ((flags & AS_IMAGE_SAVE_FLAG_BLUR) > 0)
			as_pixbuf_blur (pixbuf, 5, 3);
		return pixbuf;
	}

	/* create new 16:9 pixbuf with alpha padding */
	pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
				 TRUE, 8,
				 (gint) width,
				 (gint) height);
	gdk_pixbuf_fill (pixbuf, 0x00000000);
	if ((pixbuf_width / 16) * 9 > pixbuf_height) {
		tmp_width = width;
		tmp_height = width * pixbuf_height / pixbuf_width;
	} else {
		tmp_width = height * pixbuf_width / pixbuf_height;
		tmp_height = height;
	}
	pixbuf_tmp = gdk_pixbuf_scale_simple (priv->pixbuf,
					      (gint) tmp_width,
					      (gint) tmp_height,
					      GDK_INTERP_HYPER);
	if ((flags & AS_IMAGE_SAVE_FLAG_SHARPEN) > 0)
		as_pixbuf_sharpen (pixbuf_tmp, 1, -0.5);
	if ((flags & AS_IMAGE_SAVE_FLAG_BLUR) > 0)
		as_pixbuf_blur (pixbuf_tmp, 5, 3);
	gdk_pixbuf_copy_area (pixbuf_tmp,
			      0, 0, /* of src */
			      (gint) tmp_width,
			      (gint) tmp_height,
			      pixbuf,
			      (gint) (width - tmp_width) / 2,
			      (gint) (height - tmp_height) / 2);
	return pixbuf;
}
コード例 #20
0
ファイル: gimpviewrenderer.c プロジェクト: ni1son/gimp
static void
gimp_view_renderer_real_draw (GimpViewRenderer *renderer,
                              GtkWidget        *widget,
                              cairo_t          *cr,
                              gint              available_width,
                              gint              available_height)
{
  if (renderer->needs_render)
    GIMP_VIEW_RENDERER_GET_CLASS (renderer)->render (renderer, widget);

  if (renderer->pixbuf)
    {
      gint  width  = gdk_pixbuf_get_width  (renderer->pixbuf);
      gint  height = gdk_pixbuf_get_height (renderer->pixbuf);
      gint  x, y;

      if (renderer->bg_icon_name)
        {
          if (! renderer->pattern)
            {
              renderer->pattern = gimp_view_renderer_create_background (renderer,
                                                                        widget);
            }

          cairo_set_source (cr, renderer->pattern);
          cairo_paint (cr);
        }

      x = (available_width  - width)  / 2;
      y = (available_height - height) / 2;

      gdk_cairo_set_source_pixbuf (cr, renderer->pixbuf, x, y);
      cairo_rectangle (cr, x, y, width, height);
      cairo_fill (cr);
    }
  else if (renderer->surface)
    {
      cairo_content_t content  = cairo_surface_get_content (renderer->surface);
      gint            width    = renderer->width;
      gint            height   = renderer->height;
      gint            offset_x = (available_width  - width)  / 2;
      gint            offset_y = (available_height - height) / 2;

      cairo_translate (cr, offset_x, offset_y);

      cairo_rectangle (cr, 0, 0, width, height);

      if (content == CAIRO_CONTENT_COLOR_ALPHA)
        {
          if (! renderer->pattern)
            renderer->pattern =
              gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM,
                                              gimp_render_light_check_color (),
                                              gimp_render_dark_check_color ());

          cairo_set_source (cr, renderer->pattern);
          cairo_fill_preserve (cr);
        }

      cairo_set_source_surface (cr, renderer->surface, 0, 0);
      cairo_fill (cr);

      cairo_translate (cr, - offset_x, - offset_y);
    }
}
コード例 #21
0
static gboolean _tristatebutton_expose(GtkWidget *widget, GdkEventExpose *event)
{
  g_return_val_if_fail(widget != NULL, FALSE);
  g_return_val_if_fail(DTGTK_IS_TRISTATEBUTTON(widget), FALSE);
  g_return_val_if_fail(event != NULL, FALSE);
  GtkStyle *style = gtk_widget_get_style(widget);
  int state = gtk_widget_get_state(widget);

  /* fix text style */
  for(int i = 0; i < 5; i++) style->text[i] = style->fg[i];

  /* fetch flags */
  int flags = DTGTK_TRISTATEBUTTON(widget)->icon_flags;

  /* set inner border */
  int border = DT_PIXEL_APPLY_DPI((flags & CPF_DO_NOT_USE_BORDER) ? 2 : 6);

  /* update active state paint flag */
  gboolean active = DTGTK_TRISTATEBUTTON(widget)->state > 0;
  if(active)
    flags |= CPF_ACTIVE;
  else
    flags &= ~(CPF_ACTIVE);


  /* begin cairo drawing */
  cairo_t *cr;
  cr = gdk_cairo_create(gtk_widget_get_window(widget));

  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  int x = allocation.x;
  int y = allocation.y;
  int width = allocation.width;
  int height = allocation.height;

  /* draw standard button background if not transparent nor flat styled */
  if((flags & CPF_STYLE_FLAT))
  {
    if(state != GTK_STATE_NORMAL)
    {
      cairo_rectangle(cr, x, y, width, height);
      cairo_set_source_rgba(cr, style->bg[state].red / 65535.0, style->bg[state].green / 65535.0,
                            style->bg[state].blue / 65535.0, 0.5);
      cairo_fill(cr);
    }
  }
  else if(!(flags & CPF_BG_TRANSPARENT))
  {
    cairo_rectangle(cr, x, y, width, height);
    float rs = 1.0, gs = 1.0, bs = 1.0;

    if(DTGTK_TRISTATEBUTTON(widget)->state == 1)
      rs = gs = bs = 3.0;
    else if(DTGTK_TRISTATEBUTTON(widget)->state == 2)
      rs = 3.0;

    cairo_set_source_rgba(cr, (style->bg[state].red / 65535.0) * rs, (style->bg[state].green / 65535.0) * gs,
                          (style->bg[state].blue / 65535.0) * bs, 0.5);
    cairo_fill(cr);
  }

  /* create pango text settings if label exists */
  PangoLayout *layout = NULL;
  int pw = 0, ph = 0;
  const gchar *text = gtk_button_get_label(GTK_BUTTON(widget));
  if(text)
  {
    layout = pango_cairo_create_layout(cr);
    pango_layout_set_font_description(layout, darktable.bauhaus->pango_font_desc);
    pango_cairo_context_set_resolution(pango_layout_get_context(layout), darktable.gui->dpi);
    pango_layout_set_text(layout, text, -1);
    pango_layout_get_pixel_size(layout, &pw, &ph);
  }

  cairo_set_source_rgb(cr, style->fg[state].red / 65535.0, style->fg[state].green / 65535.0,
                       style->fg[state].blue / 65535.0);

  /* draw button image if any */
  GtkWidget *image = gtk_button_get_image(GTK_BUTTON(widget));
  if(image)
  {
    GdkPixbuf *pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(image));

    if(pixbuf)
    {
      /* Draw the pixbuf */
      gint pbw = gdk_pixbuf_get_width(pixbuf);
      gint pbh = gdk_pixbuf_get_height(pixbuf);
      gdk_cairo_set_source_pixbuf(cr, pixbuf, allocation.x + ((allocation.width / 2) - (pbw / 2)),
                                  allocation.y + ((allocation.height / 2) - (pbh / 2)));
      cairo_paint(cr);
    }
  }


  /* draw icon */
  if(DTGTK_TRISTATEBUTTON(widget)->icon)
  {
    //     if (flags & CPF_IGNORE_FG_STATE)
    //       state = GTK_STATE_NORMAL;


    if(text)
      DTGTK_TRISTATEBUTTON(widget)
          ->icon(cr, x + border, y + border, height - (border * 2), height - (border * 2), flags);
    else
      DTGTK_TRISTATEBUTTON(widget)
          ->icon(cr, x + border, y + border, width - (border * 2), height - (border * 2), flags);
  }


  /* draw label */
  if(text)
  {
    int lx = x + DT_PIXEL_APPLY_DPI(2), ly = y + ((height / 2.0) - (ph / 2.0));
    cairo_translate(cr, lx, ly);
    pango_cairo_show_layout(cr, layout);
    g_object_unref(layout);
  }

  cairo_destroy(cr);

  return FALSE;
}
コード例 #22
0
ファイル: gd-utils.c プロジェクト: MegFord/gnome-documents
/**
 * gd_embed_image_in_frame: 
 * @source_image:
 * @frame_image_path:
 * @slice_width:
 * @border_width:
 *
 * Returns: (transfer full):
 */
GdkPixbuf *
gd_embed_image_in_frame (GdkPixbuf *source_image,
                         const gchar *frame_image_path,
                         GtkBorder *slice_width,
                         GtkBorder *border_width)
{
  cairo_surface_t *surface;
  cairo_t *cr;
  int source_width, source_height;
  int dest_width, dest_height;
  gchar *css_str;
  GtkCssProvider *provider;
  GtkStyleContext *context;
  GError *error = NULL;
  GdkPixbuf *retval;
  GtkWidgetPath *path;
 
  source_width = gdk_pixbuf_get_width (source_image);
  source_height = gdk_pixbuf_get_height (source_image);

  dest_width = source_width +  border_width->left + border_width->right;
  dest_height = source_height + border_width->top + border_width->bottom;

  css_str = g_strdup_printf (".embedded-image { border-image: url(\"%s\") %d %d %d %d / %dpx %dpx %dpx %dpx }",
                             frame_image_path, 
                             slice_width->top, slice_width->right, slice_width->bottom, slice_width->left,
                             border_width->top, border_width->right, border_width->bottom, border_width->left);
  provider = gtk_css_provider_new ();
  gtk_css_provider_load_from_data (provider, css_str, -1, &error);

  if (error != NULL) 
    {
      g_warning ("Unable to create the thumbnail frame image: %s", error->message);
      g_error_free (error);
      g_free (css_str);

      return g_object_ref (source_image);
    }

  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, dest_width, dest_height);
  cr = cairo_create (surface);

  context = gtk_style_context_new ();
  path = gtk_widget_path_new ();
  gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW);

  gtk_style_context_set_path (context, path);
  gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), 600);

  gtk_style_context_save (context);
  gtk_style_context_add_class (context, "embedded-image");

  gtk_render_frame (context, cr,
                    0, 0,
                    dest_width, dest_height);

  gtk_style_context_restore (context);

  gtk_render_icon (context, cr,
                   source_image,
                   border_width->left, border_width->top);

  retval = gdk_pixbuf_get_from_surface (surface,
                                        0, 0, dest_width, dest_height);

  cairo_surface_destroy (surface);
  cairo_destroy (cr);

  gtk_widget_path_unref (path);
  g_object_unref (provider);
  g_object_unref (context);
  g_free (css_str);

  return retval;
}
コード例 #23
0
ファイル: gtkcolorswatch.c プロジェクト: aswinas/gtk-
static gboolean
swatch_draw (GtkWidget *widget,
             cairo_t   *cr)
{
  GtkColorSwatch *swatch = (GtkColorSwatch*)widget;
  GtkThemingBackground background;
  gdouble width, height;
  GtkStyleContext *context;
  GtkStateFlags state;
  GtkIconTheme *theme;
  GtkIconInfo *icon_info = NULL;

  theme = gtk_icon_theme_get_default ();
  context = gtk_widget_get_style_context (widget);
  state = gtk_widget_get_state_flags (widget);
  width = gtk_widget_get_allocated_width (widget);
  height = gtk_widget_get_allocated_height (widget);

  cairo_save (cr);

  gtk_style_context_save (context);
  gtk_style_context_set_state (context, state);

  _gtk_theming_background_init_from_context (&background, context,
                                             0, 0, width, height,
                                             GTK_JUNCTION_NONE);

  if (swatch->priv->has_color)
    {
      cairo_pattern_t *pattern;
      cairo_matrix_t matrix;

      if (swatch->priv->use_alpha)
        {
          cairo_save (cr);

          _gtk_rounded_box_path (&background.padding_box, cr);
          cairo_clip_preserve (cr);

          cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
          cairo_fill_preserve (cr);

          pattern = _gtk_color_chooser_get_checkered_pattern ();
          cairo_matrix_init_scale (&matrix, 0.125, 0.125);
          cairo_pattern_set_matrix (pattern, &matrix);

          cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
          cairo_mask (cr, pattern);
          cairo_pattern_destroy (pattern);

          cairo_restore (cr);

          background.bg_color = swatch->priv->color;
        }
      else
        {
          background.bg_color = swatch->priv->color;
          background.bg_color.alpha = 1.0;
        }

      _gtk_theming_background_render (&background, cr);
    }
  else
    _gtk_theming_background_render (&background, cr);

  gtk_render_frame (context, cr,
                    0, 0, width, height);

  if (gtk_widget_has_visible_focus (widget))
    {
      cairo_set_line_width (cr, 2);
      if (swatch->priv->has_color && INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) < 0.5)
        cairo_set_source_rgba (cr, 1., 1., 1., 0.4);
      else
        cairo_set_source_rgba (cr, 0., 0., 0., 0.4);
        _gtk_rounded_box_shrink (&background.padding_box, 3, 3, 3, 3);
        _gtk_rounded_box_path (&background.padding_box, cr);
        cairo_stroke (cr);
    }

  if (swatch->priv->icon)
    {
      icon_info = gtk_icon_theme_lookup_icon (theme, swatch->priv->icon, 16,
                                              GTK_ICON_LOOKUP_GENERIC_FALLBACK
                                              | GTK_ICON_LOOKUP_USE_BUILTIN);
    }
  else if ((state & GTK_STATE_FLAG_SELECTED) != 0)
    {
      GdkRGBA bg, border;
      GtkBorder border_width;
      GIcon *gicon;

      gtk_style_context_add_class (context, "color-active-badge");
      _gtk_theming_background_init_from_context (&background, context,
                                                 (width - 2 * ACTIVE_BADGE_RADIUS) / 2, (height - 2 * ACTIVE_BADGE_RADIUS) / 2,
                                                 2 * ACTIVE_BADGE_RADIUS, 2* ACTIVE_BADGE_RADIUS,
                                                 GTK_JUNCTION_NONE);

      if (_gtk_theming_background_has_background_image (&background))
        {
          _gtk_theming_background_render (&background, cr);
        }
      else
        {
          gtk_style_context_get_background_color (context, state, &bg);
          gtk_style_context_get_border_color (context, state, &border);
          gtk_style_context_get_border (context, state, &border_width);

          cairo_new_sub_path (cr);
          cairo_arc (cr, width / 2, height / 2, ACTIVE_BADGE_RADIUS, 0, 2 * G_PI);
          cairo_close_path (cr);
          gdk_cairo_set_source_rgba (cr, &bg);
          cairo_fill_preserve (cr);

          gdk_cairo_set_source_rgba (cr, &border);
          cairo_set_line_width (cr, border_width.left);
          cairo_stroke (cr);

          gicon = g_themed_icon_new ("object-select-symbolic");
          /* fallback for themes that don't have object-select-symbolic */
          g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply");

          icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16,
                                                      GTK_ICON_LOOKUP_GENERIC_FALLBACK
                                                      | GTK_ICON_LOOKUP_USE_BUILTIN);
          g_object_unref (gicon);
        }
    }

  if (icon_info != NULL)
    {
      GdkPixbuf *pixbuf;

      pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, context,
                                                        NULL, NULL);

      if (pixbuf != NULL)
        {
          gtk_render_icon (context, cr, pixbuf,
                           (width - gdk_pixbuf_get_width (pixbuf)) / 2,
                           (height - gdk_pixbuf_get_height (pixbuf)) / 2);
          g_object_unref (pixbuf);
        }

      g_object_unref (icon_info);
    }

  cairo_restore (cr);
  gtk_style_context_restore (context);

  return FALSE;
}
コード例 #24
0
ファイル: gd-utils.c プロジェクト: MegFord/gnome-documents
/**
 * gd_create_collection_icon:
 * @base_size:
 * @pixbufs: (element-type GdkPixbuf):
 *
 * Returns: (transfer full):
 */
GIcon *
gd_create_collection_icon (gint base_size,
                           GList *pixbufs)
{
  cairo_surface_t *surface;
  GIcon *retval;
  cairo_t *cr;
  GtkStyleContext *context;
  GtkWidgetPath *path;
  gint padding, tile_size, scale_size;
  gint pix_width, pix_height;
  gint idx, cur_x, cur_y;
  GList *l;
  GdkPixbuf *pix;

  /* TODO: do not hardcode 4, but scale to another layout if more
   * pixbufs are provided.
   */

  padding = MAX (floor (base_size / 10), 4);
  tile_size = (base_size - (3 * padding)) / 2;

  context = gtk_style_context_new ();
  gtk_style_context_add_class (context, "documents-collection-icon");

  path = gtk_widget_path_new ();
  gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW);
  gtk_style_context_set_path (context, path);
  gtk_widget_path_unref (path);

  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, base_size, base_size);
  cr = cairo_create (surface);

  gtk_render_background (context, cr,
                         0, 0, base_size, base_size);

  l = pixbufs;
  idx = 0;
  cur_x = padding;
  cur_y = padding;

  while (l != NULL && idx < 4)
    {
      pix = l->data;
      pix_width = gdk_pixbuf_get_width (pix);
      pix_height = gdk_pixbuf_get_height (pix);

      scale_size = MIN (pix_width, pix_height);

      cairo_save (cr);

      cairo_translate (cr, cur_x, cur_y);

      cairo_rectangle (cr, 0, 0,
                       tile_size, tile_size);
      cairo_clip (cr);

      cairo_scale (cr, (gdouble) tile_size / (gdouble) scale_size, (gdouble) tile_size / (gdouble) scale_size);
      gdk_cairo_set_source_pixbuf (cr, pix, 0, 0);

      cairo_paint (cr);
      cairo_restore (cr);

      if ((idx % 2) == 0)
        {
          cur_x += tile_size + padding;
        }
      else
        {
          cur_x = padding;
          cur_y += tile_size + padding;
        }

      idx++;
      l = l->next;
    }

  retval = G_ICON (gdk_pixbuf_get_from_surface (surface, 0, 0, base_size, base_size));

  cairo_surface_destroy (surface);
  cairo_destroy (cr);
  g_object_unref (context);

  return retval;
}
コード例 #25
0
ファイル: pixbuf-utils.c プロジェクト: sudkannan/gthumb_old
static gboolean
_gdk_pixbuf_save_as_tga (GdkPixbuf   *pixbuf,
			 const char  *filename,
			 char       **keys,
			 char       **values,
			 GError     **error)
{
	FILE      *fp;
	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     = gdk_pixbuf_get_width (pixbuf);
	height    = gdk_pixbuf_get_height (pixbuf);
	alpha     = gdk_pixbuf_get_has_alpha (pixbuf);
	pixels    = gdk_pixbuf_get_pixels (pixbuf);
	rowstride = gdk_pixbuf_get_rowstride (pixbuf);

	if ((fp = fopen (filename, "wb")) == NULL) {
		g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_FAILED,
			     "Can't write image to file '%s'",
			     filename);
		return FALSE;
	}

	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 */
	}

	/* write header to front of file */
	fwrite (header, sizeof (header), 1, fp);

	/* allocate a small buffer to convert image data */
	buf = g_try_malloc (width * out_bpp * sizeof (guchar));
	if (! buf) {
		g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
			     "Couldn't allocate memory for writing TGA file '%s'",
			     filename);
		return FALSE;
	}

	ptr = pixels;

	for (row = 0; row < height; ++row) {
		bgr2rgb (buf, ptr, width, out_bpp, alpha);

		if (rle_compression)
			rle_write (fp, buf, width, out_bpp);
		else
			fwrite (buf, width * out_bpp, 1, fp);

		ptr += rowstride;
	}

	g_free (buf);

	/* footer must be the last thing written to file */
	memset (footer, 0, 8); /* No extensions, no developer directory */
	memcpy (footer + 8, magic, sizeof (magic)); /* magic signature */
	fwrite (footer, sizeof (footer), 1, fp);

	fclose (fp);

	return TRUE;
}
コード例 #26
0
ファイル: svg-draw.c プロジェクト: brion/librsvg
static gboolean
draw_gap_image(GtkStyle       *style,
	       GdkWindow      *window,
	       GdkRectangle   *area,
	       GtkWidget      *widget,
	       ThemeMatchData *match_data,
	       gboolean        draw_center,
	       gint            x,
	       gint            y,
	       gint            width,
	       gint            height,
	       GtkPositionType gap_side,
	       gint            gap_x,
	       gint            gap_width)
{
  ThemeImage *image;
  gboolean setbg = FALSE;
  
  if ((width == -1) && (height == -1))
    {
      gdk_drawable_get_size(window, &width, &height);
      setbg = TRUE;
    }
  else if (width == -1)
    gdk_drawable_get_size(window, &width, NULL);
  else if (height == -1)
    gdk_drawable_get_size(window, NULL, &height);

  if (!(match_data->flags & THEME_MATCH_ORIENTATION))
    {
      match_data->flags |= THEME_MATCH_ORIENTATION;
      
      if (height > width)
	match_data->orientation = GTK_ORIENTATION_VERTICAL;
      else
	match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
    }

  match_data->flags |= THEME_MATCH_GAP_SIDE;
  match_data->gap_side = gap_side;
    
  image = match_theme_image (style, match_data);
  if (image)
    {
      gint thickness;
      GdkRectangle r1 = {0,0,0,0}, r2 = {0,0,0,0}, r3 = {0,0,0,0};
      GdkPixbuf *pixbuf = NULL;
      guint components = COMPONENT_ALL;

      if (!draw_center)
	components |= COMPONENT_CENTER;

      if (image->gap_start)
	pixbuf = theme_pixbuf_get_pixbuf (image->gap_start, -1, -1);

      switch (gap_side)
	{
	case GTK_POS_TOP:
	  if (pixbuf)
	    thickness = gdk_pixbuf_get_height (pixbuf);
	  else
	    thickness = style->ythickness;
	  
	  if (!draw_center)
	    components |= COMPONENT_NORTH_WEST | COMPONENT_NORTH | COMPONENT_NORTH_EAST;

	  r1.x      = x;
	  r1.y      = y;
	  r1.width  = gap_x;
	  r1.height = thickness;
	  r2.x      = x + gap_x;
	  r2.y      = y;
	  r2.width  = gap_width;
	  r2.height = thickness;
	  r3.x      = x + gap_x + gap_width;
	  r3.y      = y;
	  r3.width  = width - (gap_x + gap_width);
	  r3.height = thickness;
	  break;
	  
	case GTK_POS_BOTTOM:
	  if (pixbuf)
	    thickness = gdk_pixbuf_get_height (pixbuf);
	  else
	    thickness = style->ythickness;

	  if (!draw_center)
	    components |= COMPONENT_SOUTH_WEST | COMPONENT_SOUTH | COMPONENT_SOUTH_EAST;

	  r1.x      = x;
	  r1.y      = y + height - thickness;
	  r1.width  = gap_x;
	  r1.height = thickness;
	  r2.x      = x + gap_x;
	  r2.y      = y + height - thickness;
	  r2.width  = gap_width;
	  r2.height = thickness;
	  r3.x      = x + gap_x + gap_width;
	  r3.y      = y + height - thickness;
	  r3.width  = width - (gap_x + gap_width);
	  r3.height = thickness;
	  break;
	  
	case GTK_POS_LEFT:
	  if (pixbuf)
	    thickness = gdk_pixbuf_get_width (pixbuf);
	  else
	    thickness = style->xthickness;

	  if (!draw_center)
	    components |= COMPONENT_NORTH_WEST | COMPONENT_WEST | COMPONENT_SOUTH_WEST;

	  r1.x      = x;
	  r1.y      = y;
	  r1.width  = thickness;
	  r1.height = gap_x;
	  r2.x      = x;
	  r2.y      = y + gap_x;
	  r2.width  = thickness;
	  r2.height = gap_width;
	  r3.x      = x;
	  r3.y      = y + gap_x + gap_width;
	  r3.width  = thickness;
	  r3.height = height - (gap_x + gap_width);
	  break;
	  
	case GTK_POS_RIGHT:
	  if (pixbuf)
	    thickness = gdk_pixbuf_get_width (pixbuf);
	  else
	    thickness = style->xthickness;

	  if (!draw_center)
	    components |= COMPONENT_NORTH_EAST | COMPONENT_EAST | COMPONENT_SOUTH_EAST;

	  r1.x      = x + width - thickness;
	  r1.y      = y;
	  r1.width  = thickness;
	  r1.height = gap_x;
	  r2.x      = x + width - thickness;
	  r2.y      = y + gap_x;
	  r2.width  = thickness;
	  r2.height = gap_width;
	  r3.x      = x + width - thickness;
	  r3.y      = y + gap_x + gap_width;
	  r3.width  = thickness;
	  r3.height = height - (gap_x + gap_width);
	  break;
	}

      if (image->background)
	theme_pixbuf_render (image->background,
			     window, NULL, area, components, FALSE,
			     x, y, width, height);
      if (image->gap_start)
	theme_pixbuf_render (image->gap_start,
			     window, NULL, area, COMPONENT_ALL, FALSE,
			     r1.x, r1.y, r1.width, r1.height);
      if (image->gap)
	theme_pixbuf_render (image->gap,
			     window, NULL, area, COMPONENT_ALL, FALSE,
			     r2.x, r2.y, r2.width, r2.height);
      if (image->gap_end)
	theme_pixbuf_render (image->gap_end,
			     window, NULL, area, COMPONENT_ALL, FALSE,
			     r3.x, r3.y, r3.width, r3.height);

      return TRUE;
    }
  else
    return FALSE;
}
コード例 #27
0
ファイル: pixbuf-utils.c プロジェクト: sudkannan/gthumb_old
void
_gdk_pixbuf_hv_gradient (GdkPixbuf *pixbuf,
			 guint32    hcolor1,
			 guint32    hcolor2,
			 guint32    vcolor1,
			 guint32    vcolor2)
{
	guchar   *pixels;
	guint32   hr1, hg1, hb1, ha1;
	guint32   hr2, hg2, hb2, ha2;
	guint32   vr1, vg1, vb1, va1;
	guint32   vr2, vg2, vb2, va2;
	double    r, g, b, a;
	guint32   ri, gi, bi, ai;
	guchar   *p;
	guint     width, height;
	guint     w, h;
	int       n_channels, rowstride;
	double    x, y;

	g_return_if_fail (GDK_IS_PIXBUF (pixbuf));

	width = gdk_pixbuf_get_width (pixbuf);
	height = gdk_pixbuf_get_height (pixbuf);

	if (width == 0 || height == 0)
		return;

	pixels = gdk_pixbuf_get_pixels (pixbuf);

	hr1 = (hcolor1 & 0xff000000) >> 24;
	hg1 = (hcolor1 & 0x00ff0000) >> 16;
	hb1 = (hcolor1 & 0x0000ff00) >> 8;
	ha1 = (hcolor1 & 0x000000ff);

	hr2 = (hcolor2 & 0xff000000) >> 24;
	hg2 = (hcolor2 & 0x00ff0000) >> 16;
	hb2 = (hcolor2 & 0x0000ff00) >> 8;
	ha2 = (hcolor2 & 0x000000ff);

	vr1 = (vcolor1 & 0xff000000) >> 24;
	vg1 = (vcolor1 & 0x00ff0000) >> 16;
	vb1 = (vcolor1 & 0x0000ff00) >> 8;
	va1 = (vcolor1 & 0x000000ff);

	vr2 = (vcolor2 & 0xff000000) >> 24;
	vg2 = (vcolor2 & 0x00ff0000) >> 16;
	vb2 = (vcolor2 & 0x0000ff00) >> 8;
	va2 = (vcolor2 & 0x000000ff);

	n_channels = gdk_pixbuf_get_n_channels (pixbuf);
	rowstride = gdk_pixbuf_get_rowstride (pixbuf);

	for (h = 0; h < height; h++) {
		p = pixels;

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

		for (w = 0; w < width; w++) {
			double x_y, x_1_y, y_1_x, _1_x_1_y;

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

			r = hr1 * x_y + hr2 * x_1_y + vr1 * y_1_x + vr2 * _1_x_1_y;
			g = hg1 * x_y + hg2 * x_1_y + vg1 * y_1_x + vg2 * _1_x_1_y;
			b = hb1 * x_y + hb2 * x_1_y + vb1 * y_1_x + vb2 * _1_x_1_y;
			a = ha1 * x_y + ha2 * x_1_y + va1 * y_1_x + va2 * _1_x_1_y;

			ri = (int) r;
			gi = (int) g;
			bi = (int) b;
			ai = (int) a;

			switch (n_channels) {
			case 3:
				p[0] = ri;
				p[1] = gi;
				p[2] = bi;
				p += 3;
				break;
			case 4:
				p[0] = ri;
				p[1] = gi;
				p[2] = bi;
				p[3] = ai;
				p += 4;
				break;
			default:
				break;
			}
		}

		pixels += rowstride;
	}
}
コード例 #28
0
ファイル: splash.c プロジェクト: MichaelMure/Gimp-Cage-Tool
/* This function chooses a gray value for the text color, based on
 * the average luminance of the text area of the splash image.
 */
static gboolean
splash_average_text_area (GimpSplash *splash,
                          GdkPixbuf  *pixbuf,
                          GdkColor   *color)
{
  const guchar *pixels;
  gint          rowstride;
  gint          channels;
  gint          luminance = 0;
  guint         sum[3]    = { 0, 0, 0 };
  GdkRectangle  image     = { 0, 0, 0, 0 };
  GdkRectangle  area      = { 0, 0, 0, 0 };

  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
  g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8, FALSE);

  image.width  = gdk_pixbuf_get_width (pixbuf);
  image.height = gdk_pixbuf_get_height (pixbuf);
  rowstride    = gdk_pixbuf_get_rowstride (pixbuf);
  channels     = gdk_pixbuf_get_n_channels (pixbuf);
  pixels       = gdk_pixbuf_get_pixels (pixbuf);

  splash_position_layouts (splash, "Short text", "Somewhat longer text", &area);
  splash_position_layouts (splash, "", "", NULL);

  if (gdk_rectangle_intersect (&image, &area, &area))
    {
      const gint count = area.width * area.height;
      gint       x, y;

      pixels += area.x * channels;
      pixels += area.y * rowstride;

      for (y = 0; y < area.height; y++)
        {
          const guchar *src = pixels;

          for (x = 0; x < area.width; x++)
            {
              sum[0] += src[0];
              sum[1] += src[1];
              sum[2] += src[2];

              src += channels;
            }

          pixels += rowstride;
        }

      luminance = GIMP_RGB_LUMINANCE (sum[0] / count,
                                      sum[1] / count,
                                      sum[2] / count);

      luminance = CLAMP0255 (luminance > 127 ?
                             luminance - 223 : luminance + 223);

    }

  color->red = color->green = color->blue = (luminance << 8 | luminance);

  return gdk_colormap_alloc_color (gtk_widget_get_colormap (splash->area),
                                   color, FALSE, TRUE);
}
コード例 #29
0
ファイル: pixbuf-utils.c プロジェクト: sudkannan/gthumb_old
static gboolean
_gdk_pixbuf_save_as_tiff (GdkPixbuf   *pixbuf,
			  const char  *filename,
			  char       **keys,
			  char       **values,
			  GError     **error)
{
	TIFF          *tif;
	int            cols, col, rows, row;
	glong          rowsperstrip;
	gushort        compression;
	/*gushort        extra_samples[1]; FIXME*/
	int            alpha;
	gshort         predictor;
	gshort         photometric;
	gshort         samplesperpixel;
	gshort         bitspersample;
	int            rowstride;
	guchar        *pixels, *buf, *ptr;
	int            success;
	int            horizontal_dpi = 72, vertical_dpi = 72;
	gboolean       save_resolution = FALSE;

	compression = COMPRESSION_DEFLATE;

	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)
					compression = COMPRESSION_NONE;
				else if (strcmp (*viter, "pack bits") == 0)
					compression = COMPRESSION_PACKBITS;
				else if (strcmp (*viter, "lzw") == 0)
					compression = COMPRESSION_LZW;
				else if (strcmp (*viter, "deflate") == 0)
					compression = COMPRESSION_DEFLATE;
				else if (strcmp (*viter, "jpeg") == 0)
					compression = COMPRESSION_JPEG;
				else {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "Unsupported compression type passed to the TIFF saver");
					return FALSE;
				}

			} else if (strcmp (*kiter, "vertical dpi") == 0) {
				char *endptr = NULL;
				vertical_dpi = strtol (*viter, &endptr, 10);
				save_resolution = TRUE;

				if (endptr == *viter) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "TIFF vertical dpi must be a value greater than 0; value '%s' could not be parsed.",
						     *viter);

					return FALSE;
				}

				if (vertical_dpi < 0) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "TIFF vertical dpi must be a value greater than 0; value '%d' is not allowed.",
						     vertical_dpi);

					return FALSE;
				}

			} else if (strcmp (*kiter, "horizontal dpi") == 0) {
				char *endptr = NULL;
				horizontal_dpi = strtol (*viter, &endptr, 10);
				save_resolution = TRUE;

				if (endptr == *viter) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "TIFF horizontal dpi must be a value greater than 0; value '%s' could not be parsed.",
						     *viter);

					return FALSE;
				}

				if (horizontal_dpi < 0) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "TIFF horizontal dpi must be a value greater than 0; value '%d' is not allowed.",
						     horizontal_dpi);

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

			++kiter;
			++viter;
		}
	}

	predictor    = 0;
	rowsperstrip = TILE_HEIGHT;

	tif = TIFFOpen (filename, "w");

	if (tif == NULL) {
		g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_FAILED,
			     "Can't write image to file '%s'",
			     filename);
		return FALSE;
	}

	cols      = gdk_pixbuf_get_width (pixbuf);
	rows      = gdk_pixbuf_get_height (pixbuf);
	alpha     = gdk_pixbuf_get_has_alpha (pixbuf);
	pixels    = gdk_pixbuf_get_pixels (pixbuf);
	rowstride = gdk_pixbuf_get_rowstride (pixbuf);

	predictor       = 2;
	bitspersample   = 8;
	photometric     = PHOTOMETRIC_RGB;

	if (alpha)
		samplesperpixel = 4;
	else
		samplesperpixel = 3;

	/* Set TIFF parameters. */

	TIFFSetField (tif, TIFFTAG_SUBFILETYPE,   0);
	TIFFSetField (tif, TIFFTAG_IMAGEWIDTH,    cols);
	TIFFSetField (tif, TIFFTAG_IMAGELENGTH,   rows);
	TIFFSetField (tif, TIFFTAG_BITSPERSAMPLE, bitspersample);
	TIFFSetField (tif, TIFFTAG_ORIENTATION,   ORIENTATION_TOPLEFT);
	TIFFSetField (tif, TIFFTAG_COMPRESSION,   compression);

	if ((compression == COMPRESSION_LZW
	     || compression == COMPRESSION_DEFLATE)
	    && (predictor != 0)) {
		TIFFSetField (tif, TIFFTAG_PREDICTOR, predictor);
	}

	/* FIXME: alpha in a TIFF ?
	if (alpha) {
		extra_samples [0] = EXTRASAMPLE_ASSOCALPHA;
		TIFFSetField (tif, TIFFTAG_EXTRASAMPLES, 1, extra_samples);
	}
	*/

	TIFFSetField (tif, TIFFTAG_PHOTOMETRIC,     photometric);
	TIFFSetField (tif, TIFFTAG_DOCUMENTNAME,    filename);
	TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL, 3 /*samplesperpixel*/);
	TIFFSetField (tif, TIFFTAG_ROWSPERSTRIP,    rowsperstrip);
	TIFFSetField (tif, TIFFTAG_PLANARCONFIG,    PLANARCONFIG_CONTIG);

	if (save_resolution) {
		TIFFSetField (tif, TIFFTAG_XRESOLUTION, (double) horizontal_dpi);
		TIFFSetField (tif, TIFFTAG_YRESOLUTION, (double) vertical_dpi);
		TIFFSetField (tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
	}

	/* allocate a small buffer to convert image data */
	buf = g_try_malloc (cols * 3 /*samplesperpixel*/ * sizeof (guchar));
	if (! buf) {
		g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
			     "Couldn't allocate memory for writing TIFF file '%s'",
			     filename);
		return FALSE;
	}

	ptr = pixels;

	/* Now write the TIFF data. */
	for (row = 0; row < rows; row++) {
		/* convert scanline from ARGB to RGB packed */
		for (col = 0; col < cols; col++)
			memcpy (&(buf[col * 3]), &(ptr[col * samplesperpixel /*3*/]), 3);

		success = TIFFWriteScanline (tif, buf, row, 0) >= 0;

		if (! success) {
			g_set_error (error,
				     GDK_PIXBUF_ERROR,
				     GDK_PIXBUF_ERROR_FAILED,
				     "TIFF Failed a scanline write on row %d",
				     row);
			return FALSE;
		}

		ptr += rowstride;
	}

	TIFFFlushData (tif);
	TIFFClose (tif);

	g_free (buf);

	return TRUE;
}
コード例 #30
0
static void
render_compact (EABContactFormatter *formatter,
                EContact *contact,
                GString *buffer)
{
	const gchar *str;
	gchar *html;
	EContactPhoto *photo;

	g_string_append (buffer, HTML_HEADER);
	g_string_append (buffer,"<body class=\"-e-web-view-background-color -e-web-view-text-color\">");

	if (contact == NULL) {
		g_string_append (buffer, "</body></html>");
		return;
	}

	g_string_append_printf (
		buffer,
		"<table><tr><td valign=\"top\">");

	photo = e_contact_get (contact, E_CONTACT_PHOTO);

	if (photo == NULL)
		photo = e_contact_get (contact, E_CONTACT_LOGO);

	if (photo != NULL) {
		gint calced_width = MAX_COMPACT_IMAGE_DIMENSION;
		gint calced_height = MAX_COMPACT_IMAGE_DIMENSION;
		GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
		GdkPixbuf *pixbuf;

		/* figure out if we need to downscale the
		 * image here.  we don't scale the pixbuf
		 * itself, just insert width/height tags in
		 * the html */
		if (photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
			gdk_pixbuf_loader_write (
				loader, photo->data.inlined.data,
				photo->data.inlined.length, NULL);
		} else if (photo->type == E_CONTACT_PHOTO_TYPE_URI &&
				photo->data.uri &&
				g_ascii_strncasecmp (photo->data.uri, "file://", 7) == 0) {
			gchar *filename, *contents = NULL;
			gsize length;

			filename = g_filename_from_uri (photo->data.uri, NULL, NULL);

			if (filename) {
				if (g_file_get_contents (filename, &contents, &length, NULL)) {
					gdk_pixbuf_loader_write (loader, (const guchar *) contents, length, NULL);
					g_free (contents);
				}

				g_free (filename);
			}
		}

		gdk_pixbuf_loader_close (loader, NULL);
		pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);

		if (pixbuf)
			g_object_ref (pixbuf);

		g_object_unref (loader);

		if (pixbuf) {
			gint max_dimension;

			calced_width = gdk_pixbuf_get_width (pixbuf);
			calced_height = gdk_pixbuf_get_height (pixbuf);

			max_dimension = calced_width;

			if (max_dimension < calced_height)
				max_dimension = calced_height;

			if (max_dimension > MAX_COMPACT_IMAGE_DIMENSION) {
				calced_width *= ((gfloat) MAX_COMPACT_IMAGE_DIMENSION / max_dimension);
				calced_height *= ((gfloat) MAX_COMPACT_IMAGE_DIMENSION / max_dimension);
			}

			g_object_unref (pixbuf);
		}

		if (photo->type == E_CONTACT_PHOTO_TYPE_URI &&
			photo->data.uri && *photo->data.uri) {
			gboolean is_local = g_str_has_prefix (photo->data.uri, "file://");
			const gchar *uri = photo->data.uri;
			/* WebKit 2.2.x doesn't re-escape URIs, thus do this for versions before and after this */
			#if !(WEBKIT_MAJOR_VERSION == 2 && WEBKIT_MINOR_VERSION == 2)
			gchar *unescaped = g_uri_unescape_string (uri, NULL);
			uri = unescaped;
			#endif
			g_string_append_printf (
				buffer,
				"<img id=\"__evo-contact-photo\" width=\"%dpx\" height=\"%dpx\" src=\"%s%s\">",
				calced_width, calced_height,
				is_local ? "evo-" : "", uri);
			#if !(WEBKIT_MAJOR_VERSION == 2 && WEBKIT_MINOR_VERSION == 2)
			g_free (unescaped);
			#endif
		} else {
			gchar *photo_data;

			photo_data = g_base64_encode (
					photo->data.inlined.data,
					photo->data.inlined.length);
			g_string_append_printf (
				buffer,
				"<img id=\"__evo-contact-photo\" border=\"1\" src=\"data:%s;base64,%s\" "
					"width=\"%dpx\" height=\"%dpx\">",
				photo->data.inlined.mime_type,
				photo_data,
				calced_width, calced_height);
				g_free (photo_data);
		}

		e_contact_photo_free (photo);
	}

	g_string_append (buffer, "</td><td width=\"5\"></td><td valign=\"top\">\n");

	str = e_contact_get_const (contact, E_CONTACT_FILE_AS);

	if (str) {
		html = e_text_to_html (str, 0);
		g_string_append_printf (buffer, "<b>%s</b>", html);
		g_free (html);
	} else {
		str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);

		if (str) {
			html = e_text_to_html (str, 0);
			g_string_append_printf (buffer, "<b>%s</b>", html);
			g_free (html);
		}
	}

	g_string_append (buffer, "<hr>");

	if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
		GList *email_list;
		GList *l;

		g_string_append (
			buffer,
			"<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
			"<tr><td valign=\"top\">");
		g_string_append_printf (
			buffer,
			"<b>%s:</b>&nbsp;<td>", _ ("List Members"));

		email_list = e_contact_get (contact, E_CONTACT_EMAIL);

		for (l = email_list; l; l = l->next) {
			if (l->data) {
				html = e_text_to_html (l->data, 0);
				g_string_append_printf (buffer, "%s, ", html);
				g_free (html);
			}
		}

		g_list_free_full (email_list, g_free);

		g_string_append (buffer, "</td></tr></table>");

	} else {

		gboolean comma = FALSE;
		str = e_contact_get_const (contact, E_CONTACT_TITLE);

		if (str) {
			html = e_text_to_html (str, 0);
			g_string_append_printf (buffer, "<b>%s:</b> %s<br>", _ ("Job Title"), str);
			g_free (html);
		}

		#define print_email() { \
			html = eab_parse_qp_email_to_html (str); \
 \
			if (!html) \
				html = e_text_to_html (str, 0); \
 \
			g_string_append_printf (buffer, "%s%s", comma ? ", " : "", html); \
			g_free (html); \
			comma = TRUE; \
		}

		g_string_append_printf (buffer, "<b>%s:</b> ", _ ("Email"));
		str = e_contact_get_const (contact, E_CONTACT_EMAIL_1);

		if (str)
			print_email ();

		str = e_contact_get_const (contact, E_CONTACT_EMAIL_2);

		if (str)
			print_email ();

		str = e_contact_get_const (contact, E_CONTACT_EMAIL_3);

		if (str)
			print_email ();

		g_string_append (buffer, "<br>");

		#undef print_email

		str = e_contact_get_const (contact, E_CONTACT_HOMEPAGE_URL);

		if (str) {
			html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS);
			g_string_append_printf (
				buffer, "<b>%s:</b> %s<br>",
				_ ("Home page"), html);
			g_free (html);
		}

		str = e_contact_get_const (contact, E_CONTACT_BLOG_URL);

		if (str) {
			html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS);
			g_string_append_printf (
				buffer, "<b>%s:</b> %s<br>",
				_ ("Blog"), html);
		}
	}

	g_string_append (buffer, "</td></tr></table>\n");

	g_string_append (buffer, "</body></html>\n");
}