Compare commits
	
		
			2 Commits
		
	
	
		
			04ec292caf
			...
			919a55c90b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 919a55c90b | |||
| 68bb695054 | 
| @ -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"); | ||||
|  | ||||
							
								
								
									
										110
									
								
								fiv-thumbnail.c
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								fiv-thumbnail.c
									
									
									
									
									
								
							| @ -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); | ||||
| 	} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user