static void cover_thumbnailer_size_prepared (GdkPixbufLoader *loader, gint source_width, gint source_height, TumblerThumbnailFlavor *flavor) { gint dest_width; gint dest_height; gdouble hratio; gdouble wratio; g_return_if_fail (GDK_IS_PIXBUF_LOADER (loader)); g_return_if_fail (TUMBLER_IS_THUMBNAIL_FLAVOR (flavor)); /* get the destination size */ tumbler_thumbnail_flavor_get_size (flavor, &dest_width, &dest_height); if (source_width <= dest_width && source_height <= dest_height) { /* do not scale the image */ dest_width = source_width; dest_height = source_height; } else { /* determine which axis needs to be scaled down more */ wratio = (gdouble) source_width / (gdouble) dest_width; hratio = (gdouble) source_height / (gdouble) dest_height; /* adjust the other axis */ if (hratio > wratio) dest_width = rint (source_width / hratio); else dest_height = rint (source_height / wratio); } gdk_pixbuf_loader_set_size (loader, MAX (dest_width, 1), MAX (dest_height, 1)); }
static void jpeg_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer, GCancellable *cancellable, TumblerFileInfo *info) { TumblerThumbnailFlavor *flavor; TumblerImageData data; TumblerThumbnail *thumbnail; struct stat statb; const gchar *uri; GdkPixbuf *pixbuf = NULL; gboolean streaming_needed = TRUE; JOCTET *content; GError *error = NULL; GFile *file; gchar *path; gsize length; gint fd; gint height; gint width; gint size; g_return_if_fail (IS_JPEG_THUMBNAILER (thumbnailer)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (TUMBLER_IS_FILE_INFO (info)); /* do nothing if cancelled */ if (g_cancellable_is_cancelled (cancellable)) return; uri = tumbler_file_info_get_uri (info); /* try to open the source file for reading */ file = g_file_new_for_uri (uri); thumbnail = tumbler_file_info_get_thumbnail (info); g_assert (thumbnail != NULL); flavor = tumbler_thumbnail_get_flavor (thumbnail); g_assert (flavor != NULL); tumbler_thumbnail_flavor_get_size (flavor, &width, &height); size = MIN (width, height); #ifdef HAVE_MMAP if (g_file_is_native (file)) { path = g_file_get_path (file); /* try to open the file at the given path */ fd = open (path, O_RDONLY); if (G_LIKELY (fd >= 0)) { /* determine the status of the file */ if (G_LIKELY (fstat (fd, &statb) == 0 && statb.st_size > 0)) { /* try to mmap the file */ content = (JOCTET *) mmap (NULL, statb.st_size, PROT_READ, MAP_SHARED, fd, 0); /* verify whether the mmap was successful */ if (G_LIKELY (content != (JOCTET *) MAP_FAILED)) { /* try to load the embedded thumbnail first */ pixbuf = tvtj_jpeg_load_thumbnail (content, statb.st_size, size); if (pixbuf == NULL) { /* fall back to loading and scaling the image itself */ pixbuf = tvtj_jpeg_load (content, statb.st_size, size); if (pixbuf == NULL) { g_set_error (&error, TUMBLER_ERROR, TUMBLER_ERROR_INVALID_FORMAT, _("Thumbnail could not be inferred from file contents")); } } /* we have successfully mmapped the file. we may not have * a thumbnail but trying to read the image from a stream * won't help us here, so we don't need to attempt streaming * as a fallback */ streaming_needed = FALSE; } /* unmap the file content */ munmap ((void *) content, statb.st_size); } /* close the file */ close (fd); } g_free (path); } #endif if (streaming_needed) { g_file_load_contents (file, cancellable, (gchar **)&content, &length, NULL, &error); if (error == NULL) { pixbuf = tvtj_jpeg_load_thumbnail (content, length, size); if (pixbuf == NULL) { pixbuf = tvtj_jpeg_load (content, length, size); if (pixbuf == NULL) { g_set_error (&error, TUMBLER_ERROR, TUMBLER_ERROR_INVALID_FORMAT, _("Thumbnail could not be inferred from file contents")); } } } } /* either we have an error now or we have a valid thumbnail pixbuf */ g_assert (error != NULL || pixbuf != NULL); if (pixbuf != NULL) { data.data = gdk_pixbuf_get_pixels (pixbuf); data.has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); data.bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf); data.width = gdk_pixbuf_get_width (pixbuf); data.height = gdk_pixbuf_get_height (pixbuf); data.rowstride = gdk_pixbuf_get_rowstride (pixbuf); data.colorspace = (TumblerColorspace) gdk_pixbuf_get_colorspace (pixbuf); tumbler_thumbnail_save_image_data (thumbnail, &data, tumbler_file_info_get_mtime (info), NULL, &error); g_object_unref (pixbuf); } if (error != NULL) { g_signal_emit_by_name (thumbnailer, "error", uri, error->code, error->message); g_error_free (error); } else { g_signal_emit_by_name (thumbnailer, "ready", uri); } g_object_unref (flavor); g_object_unref (thumbnail); g_object_unref (file); }
static gchar * cover_thumbnailer_poster_url (CoverThumbnailer *cover, const gchar *title, const gchar *year, TumblerThumbnailFlavor *flavor, GCancellable *cancellable, GError **error) { gchar *query; const gchar *needle; const gchar *p; const gchar *k = NULL; gchar *url_part; gchar *url = NULL; gchar *data; gint dest_size; g_return_val_if_fail (TUMBLER_IS_THUMBNAIL_FLAVOR (flavor), NULL); g_return_val_if_fail (IS_COVER_THUMBNAILER (cover), NULL); if (G_LIKELY (cover->api_key == NULL)) { needle = "\"Poster\":\"http://"; query = g_strconcat (OMDBAPI_QUERY_URL, title, year != NULL ? "&y=" : NULL, year, NULL); } else { needle = "\"poster_path\":\"/"; query = g_strconcat (TMDB_QUERY_URL, cover->api_key, "&query=", title, year != NULL ? "&year=" : NULL, year, NULL); } data = cover_thumbnailer_load_contents (cover, query, cancellable, error); g_free (query); if (data != NULL) { p = strstr (data, needle); if (p != NULL) { p += strlen (needle); k = strstr (p, ".jpg\""); } if (p != NULL && k != NULL) { /* extract poster data from the contents */ url_part = g_strndup (p, k - p); /* get destination size */ tumbler_thumbnail_flavor_get_size (flavor, &dest_size, NULL); if (cover->api_key == NULL) { if (g_str_has_suffix (url_part, "_V1_SX300")) { /* imdb supports output sizes, above means image X is 300px * so set something that avoids scaling. Y is most of the time * higher with posters, so set Y<thumbsize> */ url_part[strlen (url_part) - 4] = '\0'; url = g_strdup_printf ("http://%sY%d.jpg", url_part, dest_size); } else { /* fallback that always works */ url = g_strconcat ("http://", url_part, ".jpg", NULL); } } else { /* see http://api.themoviedb.org/3/configuration?api_key= for the values */ url = g_strconcat (TMDB_BASE_URL, dest_size <= 154 ? "w154" : "w342", /* optimize for 128 or 256 */ "/", url_part, ".jpg", NULL); } g_free (url_part); } else { /* check for api key problems */ if (cover->api_key != NULL && strstr (data, "Invalid API key") != NULL) { g_printerr ("\n%s.\n\n", _("Invalid API key, you must be granted a valid " "key. The Movie DB backend will be disabled.")); g_free (cover->api_key); cover->api_key = NULL; } g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("No poster key found in metadata")); } g_free (data); } return url; }
static void gst_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer, GCancellable *cancellable, TumblerFileInfo *info) { GstElement *play; GdkPixbuf *pixbuf = NULL; gint64 duration; TumblerImageData data; GError *error = NULL; TumblerThumbnail *thumbnail; gint width, height; TumblerThumbnailFlavor *flavor; GdkPixbuf *scaled; /* check for early cancellation */ if (g_cancellable_is_cancelled (cancellable)) return; /* get size of dest thumb */ thumbnail = tumbler_file_info_get_thumbnail (info); flavor = tumbler_thumbnail_get_flavor (thumbnail); tumbler_thumbnail_flavor_get_size (flavor, &width, &height); /* prepare factory */ play = gst_thumbnailer_play_init (info); if (gst_thumbnailer_play_start (play, cancellable)) { /* check for covers in the file */ pixbuf = gst_thumbnailer_cover (play, cancellable); /* extract cover from video stream */ if (pixbuf == NULL && gst_thumbnailer_has_video (play)) { /* get the length of the video track */ if (gst_element_query_duration (play, GST_FORMAT_TIME, &duration) && duration != -1) duration /= GST_MSECOND; else duration = -1; pixbuf = gst_thumbnailer_capture_interesting_frame (play, duration, width, cancellable); } } /* stop factory */ gst_element_set_state (play, GST_STATE_NULL); g_object_unref (play); if (G_LIKELY (pixbuf != NULL)) { /* scale to correct size if required */ scaled = gst_thumbnailer_scale_pixbuf (pixbuf, width, height); g_object_unref (pixbuf); pixbuf = scaled; data.data = gdk_pixbuf_get_pixels (pixbuf); data.has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); data.bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf); data.width = gdk_pixbuf_get_width (pixbuf); data.height = gdk_pixbuf_get_height (pixbuf); data.rowstride = gdk_pixbuf_get_rowstride (pixbuf); data.colorspace = (TumblerColorspace) gdk_pixbuf_get_colorspace (pixbuf); tumbler_thumbnail_save_image_data (thumbnail, &data, tumbler_file_info_get_mtime (info), NULL, &error); g_object_unref (pixbuf); if (error != NULL) { g_signal_emit_by_name (thumbnailer, "error", tumbler_file_info_get_uri (info), error->code, error->message); g_error_free (error); } else { g_signal_emit_by_name (thumbnailer, "ready", tumbler_file_info_get_uri (info)); } } g_object_unref (thumbnail); }