Commit d36f5fc8 authored by Paolo Bacchilega's avatar Paolo Bacchilega

cairo_io: read images from a stream if possible

parent e0ccd3ec
......@@ -135,7 +135,8 @@ YCbCr_tables_init (void)
GthImage *
_cairo_image_surface_create_from_jpeg (GthFileData *file_data,
_cairo_image_surface_create_from_jpeg (GInputStream *istream,
GthFileData *file_data,
int requested_size,
int *original_width,
int *original_height,
......@@ -171,11 +172,11 @@ _cairo_image_surface_create_from_jpeg (GthFileData *file_data,
image = gth_image_new ();
if (! _g_file_load_in_buffer (file_data->file,
&in_buffer,
&in_buffer_size,
cancellable,
error))
if (! _g_input_stream_read_all (istream,
&in_buffer,
&in_buffer_size,
cancellable,
error))
{
return image;
}
......
......@@ -27,7 +27,8 @@
G_BEGIN_DECLS
GthImage * _cairo_image_surface_create_from_jpeg (GthFileData *file_data,
GthImage * _cairo_image_surface_create_from_jpeg (GInputStream *istream,
GthFileData *file_data,
int requested_size,
int *original_width,
int *original_height,
......
......@@ -39,7 +39,7 @@
#endif
typedef struct {
GFileInputStream *stream;
GInputStream *stream;
GCancellable *cancellable;
GError **error;
png_struct *png_ptr;
......@@ -88,7 +88,7 @@ cairo_png_read_data_func (png_structp png_ptr,
GError *error = NULL;
cairo_png_data = png_get_io_ptr (png_ptr);
n = g_input_stream_read (G_INPUT_STREAM (cairo_png_data->stream),
n = g_input_stream_read (cairo_png_data->stream,
buffer,
size,
cairo_png_data->cancellable,
......@@ -131,7 +131,8 @@ transform_to_argb32_format_func (png_structp png,
GthImage *
_cairo_image_surface_create_from_png (GthFileData *file_data,
_cairo_image_surface_create_from_png (GInputStream *istream,
GthFileData *file_data,
int requested_size,
int *original_width,
int *original_height,
......@@ -154,7 +155,7 @@ _cairo_image_surface_create_from_png (GthFileData *file_data,
cairo_png_data = g_new0 (CairoPngData, 1);
cairo_png_data->cancellable = cancellable;
cairo_png_data->error = error;
cairo_png_data->stream = g_file_read (file_data->file, cancellable, error);
cairo_png_data->stream = _g_object_ref (istream);
if (cairo_png_data->stream == NULL) {
_cairo_png_data_destroy (cairo_png_data);
return image;
......
......@@ -27,7 +27,8 @@
G_BEGIN_DECLS
GthImage * _cairo_image_surface_create_from_png (GthFileData *file_data,
GthImage * _cairo_image_surface_create_from_png (GInputStream *istream,
GthFileData *file_data,
int requested_size,
int *original_width,
int *original_height,
......
......@@ -164,7 +164,8 @@ gth_image_svg_set_handle (GthImageSvg *self,
GthImage *
_cairo_image_surface_create_from_svg (GthFileData *file_data,
_cairo_image_surface_create_from_svg (GInputStream *istream,
GthFileData *file_data,
int requested_size,
int *original_width,
int *original_height,
......@@ -176,10 +177,11 @@ _cairo_image_surface_create_from_svg (GthFileData *file_data,
RsvgHandle *rsvg;
image = gth_image_svg_new ();
rsvg = rsvg_handle_new_from_gfile_sync (file_data->file,
RSVG_HANDLE_FLAGS_NONE,
cancellable,
error);
rsvg = rsvg_handle_new_from_stream_sync (istream,
(file_data != NULL ? file_data->file : NULL),
RSVG_HANDLE_FLAGS_NONE,
cancellable,
error);
if (rsvg != NULL) {
gth_image_svg_set_handle (GTH_IMAGE_SVG (image), rsvg);
g_object_unref (rsvg);
......
......@@ -27,7 +27,8 @@
G_BEGIN_DECLS
GthImage * _cairo_image_surface_create_from_svg (GthFileData *file_data,
GthImage * _cairo_image_surface_create_from_svg (GInputStream *istream,
GthFileData *file_data,
int requested_size,
int *original_width,
int *original_height,
......
......@@ -417,7 +417,8 @@ photoset_combobox_changed_cb (GtkComboBox *widget,
static GthImage *
flickr_thumbnail_loader (GthFileData *file_data,
flickr_thumbnail_loader (GInputStream *istream,
GthFileData *file_data,
int requested_size,
int *original_width,
int *original_height,
......
......@@ -63,7 +63,7 @@ fill_input_buffer (j_decompress_ptr cinfo)
}
void
static void
skip_input_data (j_decompress_ptr cinfo,
long num_bytes)
{
......
......@@ -883,7 +883,8 @@ album_combobox_changed_cb (GtkComboBox *widget,
GthImage *
picasa_web_thumbnail_loader (GthFileData *file_data,
picasa_web_thumbnail_loader (GInputStream *istream,
GthFileData *file_data,
int requested_size,
int *original_width,
int *original_height,
......
......@@ -269,7 +269,8 @@ get_file_mtime (const char *path)
static GthImage *
openraw_pixbuf_animation_new_from_file (GthFileData *file_data,
openraw_pixbuf_animation_new_from_file (GInputStream *istream,
GthFileData *file_data,
int requested_size,
int *original_width,
int *original_height,
......@@ -289,6 +290,12 @@ openraw_pixbuf_animation_new_from_file (GthFileData *file_data,
char *local_file_esc;
char *command = NULL;
if (file_data == NULL) {
if (error != NULL)
*error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME, "Could not load file");
return NULL;
}
is_thumbnail = requested_size > 0;
is_raw = _g_mime_type_is_raw (gth_file_data_get_mime_type (file_data));
is_hdr = _g_mime_type_is_hdr (gth_file_data_get_mime_type (file_data));
......
......@@ -1934,32 +1934,22 @@ _g_delete_files_async (GList *file_list,
gboolean
_g_file_load_in_buffer (GFile *file,
void **buffer,
gsize *size,
GCancellable *cancellable,
GError **error)
{
GFileInputStream *istream;
gboolean retval;
void *local_buffer;
gsize count;
gssize n;
char tmp_buffer[BUFFER_SIZE];
istream = g_file_read (file, cancellable, error);
if (istream == NULL)
return FALSE;
retval = FALSE;
local_buffer = NULL;
_g_input_stream_read_all (GInputStream *istream,
void **buffer,
gsize *size,
GCancellable *cancellable,
GError **error)
{
gboolean retval = FALSE;
void *local_buffer = NULL;
char *tmp_buffer;
gsize count;
gssize n;
tmp_buffer = g_new (char, BUFFER_SIZE);
count = 0;
for (;;) {
n = g_input_stream_read (G_INPUT_STREAM (istream),
tmp_buffer,
BUFFER_SIZE,
cancellable,
error);
n = g_input_stream_read (istream, tmp_buffer, BUFFER_SIZE, cancellable, error);
if (n < 0) {
g_free (local_buffer);
retval = FALSE;
......@@ -1979,7 +1969,27 @@ _g_file_load_in_buffer (GFile *file,
count += n;
}
g_object_unref (istream);
g_free (tmp_buffer);
return retval;
}
gboolean
_g_file_load_in_buffer (GFile *file,
void **buffer,
gsize *size,
GCancellable *cancellable,
GError **error)
{
GInputStream *istream;
gboolean retval = FALSE;
istream = (GInputStream *) g_file_read (file, cancellable, error);
if (istream != NULL) {
retval = _g_input_stream_read_all (istream, buffer, size, cancellable, error);
g_object_unref (istream);
}
return retval;
}
......
......@@ -148,6 +148,11 @@ void _g_delete_files_async (GList *file_list,
/* -- load/write/create file -- */
gboolean _g_input_stream_read_all (GInputStream *istream,
void **buffer,
gsize *size,
GCancellable *cancellable,
GError **error);
gboolean _g_file_load_in_buffer (GFile *file,
void **buffer,
gsize *size,
......
......@@ -31,6 +31,7 @@
#include "glib-utils.h"
#define MAX_PATTERNS 128
#define BUFFER_SIZE_FOR_SNIFFING 32
/* gobject utils*/
......@@ -2809,6 +2810,99 @@ _g_content_type_is_a (const char *type,
}
/* -- _g_content_type_get_from_stream -- */
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 *
_g_content_type_get_from_stream (GInputStream *istream,
GCancellable *cancellable,
GError **error)
{
guchar buffer[BUFFER_SIZE_FOR_SNIFFING];
gssize n = 0;
gboolean result_uncertain = FALSE;
const char *content_type;
n = g_input_stream_read (istream,
buffer,
BUFFER_SIZE_FOR_SNIFFING,
cancellable,
error);
if (n < 0)
return NULL;
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 (result_uncertain)
content_type = NULL;
g_seekable_seek (G_SEEKABLE (istream), 0, G_SEEK_SET, cancellable, NULL);
return content_type;
}
gboolean
_g_mime_type_is_image (const char *mime_type)
{
......@@ -2963,3 +3057,11 @@ _g_list_prepend_link (GList *list,
if (list != NULL) list->prev = link;
return link;
}
void
_g_error_free (GError *error)
{
if (error != NULL)
g_error_free (error);
}
......@@ -309,6 +309,9 @@ void _g_file_info_swap_attributes (GFileInfo *info,
const char *attr2);
gboolean _g_content_type_is_a (const char *type,
const char *supertype);
const char * _g_content_type_get_from_stream (GInputStream *istream,
GCancellable *cancellable,
GError **error);
gboolean _g_mime_type_is_image (const char *mime_type);
gboolean _g_mime_type_is_video (const char *mime_type);
gboolean _g_mime_type_is_audio (const char *mime_type);
......@@ -331,6 +334,7 @@ GList * _g_settings_get_string_list (GSettings *settings,
char * _g_format_duration_for_display (gint64 msecs);
GList * _g_list_prepend_link (GList *list,
GList *link);
void _g_error_free (GError *error);
G_END_DECLS
......
......@@ -28,9 +28,6 @@
#include "gth-string-list.h"
#define BUFFER_SIZE_FOR_SNIFFING 32
const char *FileDataDigitalizationTags[] = {
"Exif::Photo::DateTimeOriginal",
"Xmp::exif::DateTimeOriginal",
......@@ -236,66 +233,6 @@ gth_file_data_get_mime_type (GthFileData *self)
}
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)
......@@ -307,12 +244,11 @@ gth_file_data_get_mime_type_from_content (GthFileData *self,
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;
char *filename;
GInputStream *istream;
GError *error = NULL;
if (self->file == NULL)
return NULL;
......@@ -321,28 +257,21 @@ gth_file_data_get_mime_type_from_content (GthFileData *self,
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 {
istream = (GInputStream *) g_file_read (self->file, cancellable, &error);
if (istream == NULL) {
g_free (filename);
g_warning ("%s", error->message);
g_clear_error (&error);
return NULL;
}
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);
content_type = _g_content_type_get_from_stream (istream, cancellable, &error);
if ((content_type == NULL) || (strcmp (content_type, "application/xml") == 0))
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_object_unref (istream);
g_free (filename);
}
......
......@@ -29,10 +29,6 @@
#include "gth-main.h"
#define USE_G_IO_SCHEDULER
#define THREAD_STACK_SIZE (512*1024)
struct _GthImageLoaderPrivate {
gboolean as_animation; /* Whether to load the image in a
* GdkPixbufAnimation structure. */
......@@ -114,6 +110,9 @@ typedef struct {
GthFileData *file_data;
int requested_size;
GCancellable *cancellable;
GthImage *image;
int original_width;
int original_height;
} LoadData;
......@@ -125,7 +124,7 @@ load_data_new (GthFileData *file_data,
LoadData *load_data;
load_data = g_new0 (LoadData, 1);
load_data->file_data = g_object_ref (file_data);
load_data->file_data = _g_object_ref (file_data);
load_data->requested_size = requested_size;
load_data->cancellable = _g_object_ref (cancellable);
......@@ -136,31 +135,13 @@ load_data_new (GthFileData *file_data,
static void
load_data_unref (LoadData *load_data)
{
g_object_unref (load_data->file_data);
_g_object_unref (load_data->file_data);
_g_object_unref (load_data->cancellable);
_g_object_unref (load_data->image);
g_free (load_data);
}
typedef struct {
GthImage *image;
int original_width;
int original_height;
} LoadResult;
static void
load_result_unref (LoadResult *load_result)
{
if (load_result->image != NULL)
g_object_unref (load_result->image);
g_free (load_result);
}
#ifdef USE_G_IO_SCHEDULER
static void
load_pixbuf_thread (GSimpleAsyncResult *result,
GObject *object,
......@@ -168,18 +149,26 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
{
GthImageLoader *self = GTH_IMAGE_LOADER (object);
LoadData *load_data;
GthImage *image = NULL;
int original_width;
int original_height;
GInputStream *istream;
GthImage *image = NULL;
GError *error = NULL;
LoadResult *load_result;
load_data = g_simple_async_result_get_op_res_gpointer (result);
original_width = -1;
original_height = -1;
istream = (GInputStream *) g_file_read (load_data->file_data->file, cancellable, &error);
if (istream == NULL) {
g_simple_async_result_set_from_error (result, error);
g_error_free (error);
return;