Compare commits

...

2 Commits

Author SHA1 Message Date
Přemysl Eric Janouch 919a55c90b
Try to thumbnail everything we can 2022-02-21 00:02:15 +01:00
Přemysl Eric Janouch 68bb695054
Clean up 2022-02-20 21:29:34 +01:00
2 changed files with 83 additions and 33 deletions

View File

@ -535,6 +535,7 @@ on_thumbnailer_ready(GObject *object, GAsyncResult *res, gpointer user_data)
// 2. it enables thumbnailing things that cannot be placed in the cache.
GError *error = NULL;
GBytes *out = NULL;
gboolean succeeded = FALSE;
if (!g_subprocess_communicate_finish(subprocess, res, &out, NULL, &error)) {
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
g_error_free(error);
@ -543,6 +544,8 @@ on_thumbnailer_ready(GObject *object, GAsyncResult *res, gpointer user_data)
} else if (!g_subprocess_get_if_exited(subprocess)) {
// If it exited, it probably printed its own message.
g_spawn_check_wait_status(g_subprocess_get_status(subprocess), &error);
} else {
succeeded = g_subprocess_get_exit_status(subprocess) == EXIT_SUCCESS;
}
if (error) {
@ -551,9 +554,6 @@ on_thumbnailer_ready(GObject *object, GAsyncResult *res, gpointer user_data)
}
g_return_if_fail(subprocess == t->minion);
gboolean succeeded = g_subprocess_get_if_exited(subprocess) &&
g_subprocess_get_exit_status(subprocess) == EXIT_SUCCESS;
g_clear_object(&t->minion);
if (!t->target) {
g_warning("finished thumbnailing an unknown image");

View File

@ -229,31 +229,10 @@ save_thumbnail(cairo_surface_t *thumbnail, const char *path, GString *thum)
WebPDataClear(&assembled);
}
gboolean
fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size,
cairo_surface_t **max_size_surface, GError **error)
static cairo_surface_t *
fiv_thumbnail_prepare(
GFile *target, GBytes *data, gboolean *color_managed, GError **error)
{
g_return_val_if_fail(max_size >= FIV_THUMBNAIL_SIZE_MIN &&
max_size <= FIV_THUMBNAIL_SIZE_MAX, FALSE);
// Local files only, at least for now.
// TODO(p): Support thumbnailing the trash scheme.
const gchar *path = g_file_peek_path(target);
if (!path) {
set_error(error, "only local files are supported");
return FALSE;
}
GMappedFile *mf = g_mapped_file_new(path, FALSE, error);
if (!mf)
return FALSE;
GStatBuf st = {};
if (g_stat(path, &st)) {
set_error(error, g_strerror(errno));
return FALSE;
}
FivIoOpenContext ctx = {
.uri = g_file_get_uri(target),
.screen_profile = fiv_io_profile_new_sRGB(),
@ -263,15 +242,86 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size,
.warnings = g_ptr_array_new_with_free_func(g_free),
};
gsize filesize = g_mapped_file_get_length(mf);
cairo_surface_t *surface = fiv_io_open_from_data(
g_mapped_file_get_contents(mf), filesize, &ctx, error);
g_mapped_file_unref(mf);
g_bytes_get_data(data, NULL), g_bytes_get_size(data), &ctx, error);
g_free((gchar *) ctx.uri);
g_ptr_array_free(ctx.warnings, TRUE);
if (ctx.screen_profile)
if ((*color_managed = !!ctx.screen_profile))
fiv_io_profile_free(ctx.screen_profile);
g_bytes_unref(data);
return surface;
}
static gboolean
fiv_thumbnail_fallback(GFile *target, FivThumbnailSize size,
cairo_surface_t **surface, GError **error)
{
goffset filesize = 0;
GFileInfo *info = g_file_query_info(target,
G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_SIZE,
G_FILE_QUERY_INFO_NONE, NULL, NULL);
if (info) {
filesize = g_file_info_get_size(info);
g_object_unref(info);
}
// TODO(p): Try to be a bit more intelligent about this.
// For example, we can employ magic checks.
if (filesize > 10 << 20) {
set_error(error, "oversize, not thumbnailing");
return FALSE;
}
GBytes *data = g_file_load_bytes(target, NULL, NULL, error);
if (!data)
return FALSE;
gboolean color_managed = FALSE;
cairo_surface_t *result =
fiv_thumbnail_prepare(target, data, &color_managed, error);
if (!result)
return FALSE;
if (!*surface)
*surface = adjust_thumbnail(result, fiv_thumbnail_sizes[size].size);
cairo_surface_destroy(result);
return TRUE;
}
gboolean
fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size,
cairo_surface_t **max_size_surface, GError **error)
{
g_return_val_if_fail(max_size >= FIV_THUMBNAIL_SIZE_MIN &&
max_size <= FIV_THUMBNAIL_SIZE_MAX, FALSE);
const gchar *path = g_file_peek_path(target);
if (!path || !g_file_is_native(target) /* Don't save sftp://. */) {
return fiv_thumbnail_fallback(
target, max_size, max_size_surface, error);
}
// Make the TOCTTOU issue favour unnecessary reloading.
GStatBuf st = {};
if (g_stat(path, &st)) {
set_error(error, g_strerror(errno));
return FALSE;
}
GError *e = NULL;
GMappedFile *mf = g_mapped_file_new(path, FALSE, &e);
if (!mf) {
g_debug("%s: %s", path, e->message);
g_error_free(e);
return fiv_thumbnail_fallback(
target, max_size, max_size_surface, error);
}
gsize filesize = g_mapped_file_get_length(mf);
gboolean color_managed = FALSE;
cairo_surface_t *surface = fiv_thumbnail_prepare(
target, g_mapped_file_get_bytes(mf), &color_managed, error);
g_mapped_file_unref(mf);
if (!surface)
return FALSE;
@ -296,7 +346,7 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size,
}
// Without a CMM, no conversion is attempted.
if (ctx.screen_profile) {
if (color_managed) {
g_string_append_printf(
thum, "%s%c%s%c", THUMB_COLORSPACE, 0, THUMB_COLORSPACE_SRGB, 0);
}