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; }
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; } }
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; }
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; }
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; }
/** * 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; }
/** * 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; }
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; }
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; }
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(); }
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; }
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); }
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; }
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; }
/* 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); }
/* ------------------------------ * 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 */
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)); }
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; }
/** * 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; }
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); } }
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; }
/** * 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; }
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; }
/** * 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; }
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; }
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; }
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; } }
/* 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); }
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; }
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> <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"); }