diff --git a/ChangeLog b/ChangeLog index 3aeaa778..50ab6597 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2003-12-21 Jens Finke + + * collection/eog-collection-view.c (save_image_loading_finished): + Adapted to new eog_image_save signature. + + * libeog/eog-file-selection.[ch] (eog_file_selection_add_filter): + Attach GdkPixbufFormat to filter for further reference. + (eog_file_selection_get_format): New function. + + * libeog/eog-image-jpeg.[ch] (get_tmp_filepath), + (move_file_to_uri): New functions. + (eog_image_jpeg_save), + (eog_image_jpeg_save_lossless): Dump data to temporary file first + and move it to final destination afterwards. + + * libeog/eog-image.[ch] (real_image_load): Set image status to failed + if we read 0 bytes. + (eog_image_save): Added GdkPixbufFormat parameter, better + retrieving of target filetype. + + * viewer/eog-image-view.c (verb_SaveAs_cb): Get image format from + file chooser. + (save_uri): New function, which takes an additional + GdkPixbufFormat parameter. + 2003-12-19 Jens Finke * libeog/eog-image.c (eog_image_save): Update URI and clear diff --git a/collection/eog-collection-view.c b/collection/eog-collection-view.c index ff77bf97..ea32f427 100644 --- a/collection/eog-collection-view.c +++ b/collection/eog-collection-view.c @@ -312,7 +312,7 @@ save_image_loading_finished (EogImage *image, gpointer data) uri = eog_image_get_uri (image); - if (!eog_image_save (image, uri, &error)) { + if (!eog_image_save (image, uri, NULL, &error)) { /* FIXME: indicate failed state to the user */ } gnome_vfs_uri_unref (uri); diff --git a/libeog/eog-file-selection.c b/libeog/eog-file-selection.c index 7e68cebf..fe73e173 100644 --- a/libeog/eog-file-selection.c +++ b/libeog/eog-file-selection.c @@ -10,12 +10,13 @@ #include #include #include -#include #include "eog-hig-dialog.h" #include "eog-pixbuf-util.h" static char* last_dir[] = { NULL, NULL }; +#define FILE_FORMAT_KEY "file-format" + GNOME_CLASS_BOILERPLATE (EogFileSelection, eog_file_selection, GtkFileChooserDialog, @@ -137,7 +138,7 @@ eog_file_selection_add_filter (GtkWidget *widget) gdk_pixbuf_format_get_name (format)); gtk_file_filter_set_name (filter, filter_name); g_free (filter_name); - + mime_types = gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) it->data); for (i = 0; mime_types[i] != NULL; i++) { gtk_file_filter_add_mime_type (filter, mime_types[i]); @@ -154,6 +155,12 @@ eog_file_selection_add_filter (GtkWidget *widget) } g_strfreev (pattern); + /* attach GdkPixbufFormat to filter, see also + * eog_file_selection_get_format. */ + g_object_set_data (G_OBJECT (filter), + FILE_FORMAT_KEY, + format); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), filter); } @@ -233,3 +240,19 @@ eog_folder_selection_new (void) return filesel; } + +GdkPixbufFormat* +eog_file_selection_get_format (EogFileSelection *sel) +{ + GtkFileFilter *filter; + GdkPixbufFormat* format; + + g_return_val_if_fail (EOG_IS_FILE_SELECTION (sel), NULL); + + filter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (sel)); + if (filter == NULL) return NULL; + + format = g_object_get_data (G_OBJECT (filter), FILE_FORMAT_KEY); + + return format; +} diff --git a/libeog/eog-file-selection.h b/libeog/eog-file-selection.h index af0e34aa..cf01784d 100644 --- a/libeog/eog-file-selection.h +++ b/libeog/eog-file-selection.h @@ -2,6 +2,7 @@ #define _EOG_FILE_SELECTION_H_ #include +#include G_BEGIN_DECLS @@ -32,6 +33,8 @@ GtkWidget* eog_file_selection_new (GtkFileChooserAction action); GtkWidget* eog_folder_selection_new (void); +GdkPixbufFormat* eog_file_selection_get_format (EogFileSelection *sel); + G_END_DECLS #endif /* _EOG_FILE_SELECTION_H_ */ diff --git a/libeog/eog-image-jpeg.c b/libeog/eog-image-jpeg.c index eb77c445..d1e1c710 100644 --- a/libeog/eog-image-jpeg.c +++ b/libeog/eog-image-jpeg.c @@ -32,6 +32,8 @@ #if HAVE_JPEG +#include +#include #include #include #include @@ -46,11 +48,51 @@ #endif #include "eog-image-private.h" +static char* +get_tmp_filepath (void) +{ + char *tmp_file; + char *tmp_file_name; + static int file_count = 0; + + tmp_file_name = g_strdup_printf ("eog%i%i.tmp", getpid (), file_count++); + tmp_file = g_build_filename (g_get_tmp_dir (), tmp_file_name, NULL); + + g_free (tmp_file_name); + + return tmp_file; +} + +static GnomeVFSResult +move_file_to_uri (char *file_path, GnomeVFSURI *uri) +{ + GnomeVFSResult result; + GnomeVFSURI *source_uri; + + source_uri = gnome_vfs_uri_new (file_path); + + result = gnome_vfs_xfer_uri (source_uri, + uri, + GNOME_VFS_XFER_DELETE_ITEMS, /* delete source file */ + GNOME_VFS_XFER_ERROR_MODE_ABORT, /* abort on all errors */ + GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE, /* we checked for existing + file already */ + NULL, /* no progress callback */ + NULL); + + gnome_vfs_uri_unref (source_uri); + + return result; +} + + gboolean -eog_image_jpeg_save (EogImage *image, const char *path, GError **error) +eog_image_jpeg_save (EogImage *image, GnomeVFSURI *uri, GError **error) { EogImagePrivate *priv; GdkPixbuf *pixbuf; + GnomeVFSResult vfs_result; + char *tmp_path; struct jpeg_compress_struct cinfo; guchar *buf = NULL; guchar *ptr; @@ -76,8 +118,9 @@ eog_image_jpeg_save (EogImage *image, const char *path, GError **error) if (pixbuf == NULL) { return FALSE; } - - outfile = fopen (path, "wb"); + + tmp_path = get_tmp_filepath (); + outfile = fopen (tmp_path, "wb"); if (outfile == NULL) { return FALSE; } @@ -151,19 +194,30 @@ eog_image_jpeg_save (EogImage *image, const char *path, GError **error) fclose (outfile); - return TRUE; + /* move temporary file to final destination */ + vfs_result = move_file_to_uri (tmp_path, uri); + if (vfs_result != GNOME_VFS_OK) { + g_set_error (error, EOG_IMAGE_ERROR, + EOG_IMAGE_ERROR_VFS, + gnome_vfs_result_to_string (vfs_result)); + } + g_free (tmp_path); + + return (vfs_result == GNOME_VFS_OK); } gboolean -eog_image_jpeg_save_lossless (EogImage *image, const char *path, GError **error) +eog_image_jpeg_save_lossless (EogImage *image, GnomeVFSURI *uri, GError **error) { const char *img_path; int result; JXFORM_CODE trans_code = JXFORM_NONE; EogTransformType transformation; + char *tmp_file; + GnomeVFSResult vfs_result = GNOME_VFS_OK; g_return_val_if_fail (EOG_IS_IMAGE (image), FALSE); - g_return_val_if_fail (path != NULL, FALSE); + g_return_val_if_fail (uri != NULL, FALSE); img_path = gnome_vfs_uri_get_path (image->priv->uri); @@ -191,9 +245,32 @@ eog_image_jpeg_save_lossless (EogImage *image, const char *path, GError **error) } } - result = jpegtran ((char*) img_path, (char*) path, trans_code, error); + /* We save the resulting jpeg file to a temporary location + * first and move it to the final destination then. This way + * can also overwrite a file. + */ + tmp_file = get_tmp_filepath (); + g_print ("tmp_file: %s\n", tmp_file); - return (result == 0); + result = jpegtran ((char*) img_path, (char*) tmp_file, trans_code, error); + + if (result == 0) { + /* image successfully written */ + vfs_result = move_file_to_uri (tmp_file, uri); + if (vfs_result != GNOME_VFS_OK) { + g_set_error (error, EOG_IMAGE_ERROR, + EOG_IMAGE_ERROR_VFS, + gnome_vfs_result_to_string (vfs_result)); + } + } + + if (g_file_test (tmp_file, G_FILE_TEST_EXISTS)) { + gnome_vfs_unlink (tmp_file); + } + + g_free (tmp_file); + + return ((result == 0) && (vfs_result == GNOME_VFS_OK)); } #endif diff --git a/libeog/eog-image-jpeg.h b/libeog/eog-image-jpeg.h index 53795516..8d6d3cd6 100644 --- a/libeog/eog-image-jpeg.h +++ b/libeog/eog-image-jpeg.h @@ -6,15 +6,16 @@ #if HAVE_JPEG #include +#include #include "eog-image.h" /* This will include some specialized routines for JPEG images, to support saving and transformations better for this format. */ -gboolean eog_image_jpeg_save (EogImage *image, const char *path, GError **error); +gboolean eog_image_jpeg_save (EogImage *image, GnomeVFSURI *uri, GError **error); /* This assumes that image represents a jpeg file on the local filesystem! */ -gboolean eog_image_jpeg_save_lossless (EogImage *image, const char *path, GError **error); +gboolean eog_image_jpeg_save_lossless (EogImage *image, GnomeVFSURI *uri, GError **error); #endif diff --git a/libeog/eog-image.c b/libeog/eog-image.c index 3080be80..a57bbf4b 100644 --- a/libeog/eog-image.c +++ b/libeog/eog-image.c @@ -843,7 +843,7 @@ real_image_load (gpointer data) gnome_vfs_close (handle); gnome_vfs_file_info_unref (info); - if (failed) { + if (failed || (bytes_read_total == 0)) { g_mutex_lock (priv->status_mutex); if (priv->image != NULL) { g_object_unref (priv->image); @@ -855,6 +855,9 @@ real_image_load (gpointer data) if (error != NULL) { priv->error_message = g_strdup (error->message); } + else if (bytes_read_total == 0) { + priv->error_message = g_strdup (_("empty file")); + } else { priv->error_message = NULL; } @@ -1274,7 +1277,7 @@ get_save_file_type_by_suffix (const char *local_path) } gboolean -eog_image_save (EogImage *img, GnomeVFSURI *uri, GError **error) +eog_image_save (EogImage *img, GnomeVFSURI *uri, GdkPixbufFormat *format, GError **error) { EogImagePrivate *priv; char *file; @@ -1306,11 +1309,25 @@ eog_image_save (EogImage *img, GnomeVFSURI *uri, GError **error) _("Images can only be saved as local files.")); return FALSE; } - - /* find file type for saving, according to filename suffix */ + file = (char*) gnome_vfs_uri_get_path (uri); /* don't free file, it's a static string */ - - target_type = get_save_file_type_by_suffix (file); + + /* determine type of file to write (eg. 'png') */ + if (format == NULL) { + if (gnome_vfs_uri_equal (priv->uri, uri)) { + /* we overwrite the same file, therefore we + * can reuse the file type saved in the EogImage object. */ + target_type = g_strdup (priv->file_type); + } + else { + /* find file type for saving, according to filename suffix */ + target_type = get_save_file_type_by_suffix (file); + } + } + else { + target_type = gdk_pixbuf_format_get_name (format); + } + if (target_type == NULL) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, @@ -1321,8 +1338,8 @@ eog_image_save (EogImage *img, GnomeVFSURI *uri, GError **error) source_is_local = (priv->uri != NULL && is_local_uri (priv->uri)); source_type = priv->file_type; - /* Check for some special cases, so that we use always the least intrusive method - * for saving the image. + /* Check for some special cases, so that we use always the + * least intrusive method for saving the image. */ if ((g_ascii_strcasecmp (target_type, source_type) == 0) && !eog_image_is_modified (img)) @@ -1334,11 +1351,11 @@ eog_image_save (EogImage *img, GnomeVFSURI *uri, GError **error) vfs_result = gnome_vfs_xfer_uri (priv->uri, uri, - GNOME_VFS_XFER_DEFAULT /* copy the data */, - GNOME_VFS_XFER_ERROR_MODE_ABORT, /* abort on all errors */ + GNOME_VFS_XFER_DEFAULT /* copy the data */, + GNOME_VFS_XFER_ERROR_MODE_ABORT, /* abort on all errors */ GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE, /* we checked for existing file already */ - NULL, /* no progress callback */ + NULL, /* no progress callback */ NULL); result = (vfs_result == GNOME_VFS_OK); if (!result) { @@ -1356,7 +1373,7 @@ eog_image_save (EogImage *img, GnomeVFSURI *uri, GError **error) /* If source is a local file and both are jpeg files, * then use lossless transformation through libjpeg. */ - result = eog_image_jpeg_save_lossless (img, file, error); + result = eog_image_jpeg_save_lossless (img, uri, error); g_print ("loseless saving of %s to %s\n", gnome_vfs_uri_to_string (priv->uri, GNOME_VFS_URI_HIDE_NONE), file); @@ -1368,7 +1385,7 @@ eog_image_save (EogImage *img, GnomeVFSURI *uri, GError **error) * libjpeg. */ g_print ("Save through jpeg library.\n"); - result = eog_image_jpeg_save (img, file, error); + result = eog_image_jpeg_save (img, uri, error); } #endif #endif diff --git a/libeog/eog-image.h b/libeog/eog-image.h index 17bbfaea..75338733 100644 --- a/libeog/eog-image.h +++ b/libeog/eog-image.h @@ -75,6 +75,7 @@ gboolean eog_image_is_loaded (EogImage *img); /* saving API */ gboolean eog_image_save (EogImage *img, GnomeVFSURI *uri, + GdkPixbufFormat *format, GError **error); /* query API */ diff --git a/viewer/eog-image-view.c b/viewer/eog-image-view.c index f505b82b..3b5f1086 100644 --- a/viewer/eog-image-view.c +++ b/viewer/eog-image-view.c @@ -117,6 +117,7 @@ enum { static void popup_menu_cb (gpointer data, guint action, GtkWidget *widget); static gint save_uri_cb (BonoboPersistFile *pf, const CORBA_char *text_uri, CORBA_Environment *ev, void *closure); +static gboolean save_uri (EogImageView *view, const char *text_uri, GdkPixbufFormat *format); static guint signals[LAST_SIGNAL] = { 0 }; @@ -316,6 +317,7 @@ verb_SaveAs_cb (BonoboUIComponent *uic, gpointer user_data, GtkWidget *dlg; int response; gchar *filename = NULL; + GdkPixbufFormat *format = NULL; g_return_if_fail (EOG_IS_IMAGE_VIEW (user_data)); @@ -330,14 +332,13 @@ verb_SaveAs_cb (BonoboUIComponent *uic, gpointer user_data, if (response == GTK_RESPONSE_OK) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg)); + format = eog_file_selection_get_format (EOG_FILE_SELECTION (dlg)); } gtk_widget_destroy (dlg); - - if (response == GTK_RESPONSE_OK) { - save_uri_cb (NULL, filename, NULL, image_view); + save_uri (image_view, filename, format); } if (filename != NULL) { @@ -1102,22 +1103,26 @@ static gint save_uri_cb (BonoboPersistFile *pf, const CORBA_char *text_uri, CORBA_Environment *ev, void *closure) { - EogImageView *view; + return save_uri (EOG_IMAGE_VIEW (closure), text_uri, NULL); +} + +static gboolean +save_uri (EogImageView *view, const char *text_uri, GdkPixbufFormat *format) +{ GnomeVFSURI *uri; GError *error = NULL; GtkWidget *dialog; gboolean result; - g_return_val_if_fail (EOG_IS_IMAGE_VIEW (closure), 1); - g_return_val_if_fail (text_uri != NULL, 1); + g_return_val_if_fail (EOG_IS_IMAGE_VIEW (view), FALSE); + g_return_val_if_fail (text_uri != NULL, FALSE); - view = EOG_IMAGE_VIEW (closure); if (view->priv->image == NULL) return FALSE; /* FIXME: what kind of escaping do we need here? */ uri = gnome_vfs_uri_new (text_uri); - result = eog_image_save (view->priv->image, uri, &error); + result = eog_image_save (view->priv->image, uri, format, &error); if (result) { dialog = eog_hig_dialog_new (GTK_STOCK_DIALOG_INFO,