[gthumb] get the image type from the file content when loading the image



commit ea4af725c3bdecee5a61bae1fea37717e6ad1640
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Wed Aug 15 12:23:04 2012 +0200

    get the image type from the file content when loading the image

 gthumb/gth-file-data.c    |  126 +++++++++++++++++++++++++++++++++++++++++++-
 gthumb/gth-file-data.h    |    3 +
 gthumb/gth-image-loader.c |    2 +-
 gthumb/gth-thumb-loader.c |    2 +-
 4 files changed, 128 insertions(+), 5 deletions(-)
---
diff --git a/gthumb/gth-file-data.c b/gthumb/gth-file-data.c
index 3f41f2b..1182e58 100644
--- a/gthumb/gth-file-data.c
+++ b/gthumb/gth-file-data.c
@@ -28,6 +28,9 @@
 #include "gth-string-list.h"
 
 
+#define BUFFER_SIZE_FOR_SNIFFING 32
+
+
 const char *FileDataDigitalizationTags[] = {
 	"Exif::Photo::DateTimeOriginal",
 	"Xmp::exif::DateTimeOriginal",
@@ -220,10 +223,127 @@ gth_file_data_get_mime_type (GthFileData *self)
 			return NULL;
 
 		filename = g_file_get_basename (self->file);
-		if (filename != NULL) {
-			content_type = g_content_type_guess (filename, NULL, 0, NULL);
-			g_free (filename);
+		if (filename == NULL)
+			return NULL;
+
+		content_type = g_content_type_guess (filename, NULL, 0, NULL);
+		g_file_info_set_attribute_string (self->info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, content_type);
+
+		g_free (filename);
+	}
+
+	return get_static_string (content_type);
+}
+
+
+static const char *
+get_mime_type_from_magic_numbers (void  *buffer,
+				  gsize  buffer_size)
+{
+#if ENABLE_MAGIC
+
+	static magic_t magic = NULL;
+
+	if (magic == NULL) {
+		magic = magic_open (MAGIC_MIME_TYPE);
+		if (magic != NULL)
+			magic_load (magic, NULL);
+		else
+			g_warning ("unable to open magic database");
+	}
+
+	if (magic != NULL) {
+		const char * mime_type;
+
+		mime_type = magic_buffer (magic, buffer, buffer_size);
+		if (mime_type)
+			return mime_type;
+
+		g_warning ("unable to detect filetype from magic: %s", magic_error (magic));
+	}
+
+#else
+
+	static const struct magic {
+		const unsigned int off;
+		const unsigned int len;
+		const char * const id;
+		const char * const mime_type;
+	}
+	magic_ids [] = {
+		/* magic ids taken from magic/Magdir/archive from the file-4.21 tarball */
+		{ 0,  8, "\x89PNG\x0d\x0a\x1a\x0a",		"image/png" },
+		{ 0,  4, "MM\x00\x2a",				"image/tiff" },
+		{ 0,  4, "II\x2a\x00",				"image/tiff" },
+		{ 0,  4, "GIF8",				"image/gif" },
+		{ 0,  2, "\xff\xd8",				"image/jpeg" },
+	};
+
+	int  i;
+
+	for (i = 0; i < G_N_ELEMENTS (magic_ids); i++) {
+		const struct magic * const magic = &magic_ids[i];
+
+		if ((magic->off + magic->len) > buffer_size)
+			g_warning ("buffer underrun for mime-type '%s' magic", magic->mime_type);
+		else if (! memcmp (buffer + magic->off, magic->id, magic->len))
+			return magic->mime_type;
+	}
+
+#endif
+
+	return NULL;
+}
+
+
+const char *
+gth_file_data_get_mime_type_from_content (GthFileData  *self,
+					  GCancellable *cancellable)
+{
+	const char *content_type;
+
+	if (self->info == NULL)
+		return NULL;
+
+	content_type = g_file_info_get_attribute_string (self->info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
+	if (content_type == NULL) {
+		char             *filename;
+		GFileInputStream *istream;
+		GError           *error = NULL;
+		guchar            buffer[BUFFER_SIZE_FOR_SNIFFING];
+		gssize            n = 0;
+		gboolean          result_uncertain;
+
+		if (self->file == NULL)
+			return NULL;
+
+		filename = g_file_get_basename (self->file);
+		if (filename == NULL)
+			return NULL;
+
+		istream = g_file_read (self->file, cancellable, &error);
+		if (istream != NULL) {
+			n = g_input_stream_read (G_INPUT_STREAM (istream),
+						 buffer,
+						 BUFFER_SIZE_FOR_SNIFFING,
+						 cancellable,
+						 NULL);
+			g_object_unref (istream);
 		}
+		else {
+			g_warning ("%s", error->message);
+			g_clear_error (&error);
+		}
+
+		result_uncertain = FALSE;
+		content_type = get_mime_type_from_magic_numbers (buffer, n);
+		if (content_type == NULL)
+			content_type = g_content_type_guess (NULL, buffer, n, &result_uncertain);
+		if ((content_type == NULL) || (strcmp (content_type, "application/xml") == 0) || result_uncertain)
+			content_type = g_content_type_guess (filename, NULL, n, NULL);
+		g_file_info_set_attribute_string (self->info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, content_type);
+
+		g_free (filename);
 	}
 
 	return get_static_string (content_type);
diff --git a/gthumb/gth-file-data.h b/gthumb/gth-file-data.h
index aad7ed8..24fe58a 100644
--- a/gthumb/gth-file-data.h
+++ b/gthumb/gth-file-data.h
@@ -76,6 +76,9 @@ void          gth_file_data_set_info                (GthFileData    *self,
 void          gth_file_data_set_mime_type           (GthFileData    *self,
 						     const char     *mime_type);
 const char *  gth_file_data_get_mime_type           (GthFileData    *self);
+const char *  gth_file_data_get_mime_type_from_content
+						    (GthFileData    *self,
+						     GCancellable   *cancellable);
 const char *  gth_file_data_get_filename_sort_key   (GthFileData    *self);
 time_t        gth_file_data_get_mtime               (GthFileData    *self);
 GTimeVal *    gth_file_data_get_modification_time   (GthFileData    *self);
diff --git a/gthumb/gth-image-loader.c b/gthumb/gth-image-loader.c
index a0f8b51..3b8c2b6 100644
--- a/gthumb/gth-image-loader.c
+++ b/gthumb/gth-image-loader.c
@@ -190,7 +190,7 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
 	else  {
 		GthImageLoaderFunc loader_func;
 
-		loader_func = gth_main_get_image_loader_func (gth_file_data_get_mime_type (load_data->file_data),
+		loader_func = gth_main_get_image_loader_func (gth_file_data_get_mime_type_from_content (load_data->file_data, cancellable),
 							      self->priv->preferred_format);
 		if (loader_func != NULL)
 			image = loader_func (load_data->file_data,
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index b2dad2a..73c21da 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -134,7 +134,7 @@ generate_thumbnail (GthFileData   *file_data,
 	uri = g_file_get_uri (file_data->file);
 	pixbuf = gnome_desktop_thumbnail_factory_generate_no_script (self->priv->thumb_factory,
 								     uri,
-								     gth_file_data_get_mime_type (file_data),
+								     gth_file_data_get_mime_type_from_content (file_data, cancellable),
 								     cancellable);
 
 	if (g_cancellable_is_cancelled (cancellable)) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]