aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/picture.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/picture.c')
-rwxr-xr-xsrc/picture.c1174
1 files changed, 1174 insertions, 0 deletions
diff --git a/src/picture.c b/src/picture.c
new file mode 100755
index 0000000..8dd7b37
--- /dev/null
+++ b/src/picture.c
@@ -0,0 +1,1174 @@
+/* picture.c - 2004/11/21 */
+/*
+ * EasyTAG - Tag editor for MP3 and Ogg Vorbis files
+ * Copyright (C) 2000-2003 Jerome Couderc <easytag@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdk.h>
+#include <glib/gi18n-lib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "picture.h"
+#include "easytag.h"
+#include "log.h"
+#include "misc.h"
+#include "setting.h"
+#include "msgbox.h"
+#include "bar.h"
+#include "charset.h"
+
+#ifdef WIN32
+# include "win32/win32dep.h"
+#endif
+
+
+/****************
+ * Declarations *
+ ****************/
+
+
+/**************
+ * Prototypes *
+ **************/
+
+void Tag_Area_Picture_Drag_Data (GtkWidget *widget, GdkDragContext *dc,
+ gint x, gint y, GtkSelectionData *selection_data,
+ guint info, guint t, gpointer data);
+void Picture_Selection_Changed_cb (GtkTreeSelection *selection, gpointer data);
+void Picture_Load_Filename (gchar *filename, gpointer user_data);
+
+void Picture_Add_Button_Clicked (GObject *object);
+void Picture_Properties_Button_Clicked (GObject *object);
+void Picture_Save_Button_Clicked (GObject *object);
+void Picture_Clear_Button_Clicked (GObject *object);
+
+gint Picture_Format (Picture *pic);
+const gchar *Picture_Format_String (gint format);
+const gchar *Picture_Type_String (gint type);
+gchar *Picture_Info (Picture *pic);
+void PictureEntry_Clear (void);
+void PictureEntry_Update (Picture *pic, gint select);
+
+Picture *Picture_Allocate (void);
+Picture *Picture_Copy_One (const Picture *pic);
+Picture *Picture_Copy (const Picture *pic);
+void Picture_Free (Picture *pic);
+Picture *Picture_Load_File_Data (const gchar *filename);
+gboolean Picture_Save_File_Data (const Picture *pic, const gchar *filename);
+
+gboolean Picture_Entry_View_Button_Pressed (GtkTreeView *treeview, GdkEventButton *event, gpointer data);
+gboolean Picture_Entry_View_Key_Pressed (GtkTreeView *treeview, GdkEvent *event, gpointer data);
+
+
+/*
+ * Note :
+ * -> MP4_TAG :
+ * Just has one picture (PICTURE_TYPE_FRONT_COVER).
+ * The format's don't matter to the MP4 side.
+ *
+ */
+
+/*************
+ * Functions *
+ *************/
+
+void Tag_Area_Picture_Drag_Data (GtkWidget *widget, GdkDragContext *dc,
+ gint x, gint y, GtkSelectionData *selection_data,
+ guint info, guint t, gpointer data)
+{
+ GtkTreeSelection *selection;
+ gchar **uri_list, **uri;
+
+ gtk_drag_finish(dc, TRUE, FALSE, t);
+
+ if (info != TARGET_URI_LIST
+ || !selection_data
+ || !PictureEntryView)
+ return;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
+ gtk_tree_selection_unselect_all(selection);
+
+ uri = uri_list = g_strsplit((const gchar *)selection_data->data, "\r\n", 0);
+ while (*uri && strlen(*uri))
+ {
+ //Picture *pic;
+ gchar *filename;
+
+ filename = g_filename_from_uri(*uri, 0, 0);
+ if (filename)
+ {
+ Picture_Load_Filename(filename,NULL);
+ /*pic = Picture_Load_File_Data(filename);
+ g_free(filename);
+ if (pic)
+ PictureEntry_Update(pic, 1);*/
+ }
+ uri++;
+ }
+ g_strfreev(uri_list);
+}
+
+void Picture_Selection_Changed_cb (GtkTreeSelection *selection, gpointer data)
+{
+ //if (gtk_tree_selection_count_selected_rows(GTK_TREE_SELECTION(selection)) == 1)
+ //{
+ gtk_widget_set_sensitive(GTK_WIDGET(PictureSaveButton), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(PicturePropertiesButton), TRUE);
+ //}else
+ //{
+ // gtk_widget_set_sensitive(GTK_WIDGET(PictureSaveButton), FALSE);
+ // gtk_widget_set_sensitive(GTK_WIDGET(PicturePropertiesButton), FALSE);
+ //}
+}
+
+void Picture_Clear_Button_Clicked (GObject *object)
+{
+ GList *paths, *refs = NULL, *node = NULL;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gpointer proxy;
+ gint n = 0;
+
+ if (!PictureEntryView) return;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView));
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
+ paths = gtk_tree_selection_get_selected_rows(selection, 0);
+ proxy = g_object_newv(G_TYPE_OBJECT, 0, NULL);
+
+ // List of items to delete
+ for (node = paths; node; node = node->next)
+ {
+ refs = g_list_append(refs, gtk_tree_row_reference_new_proxy(proxy, model, node->data));
+ gtk_tree_path_free(node->data);
+ }
+ g_list_free(paths);
+
+ for (node = refs; node; node = node->next)
+ {
+ GtkTreePath *path = gtk_tree_row_reference_get_path(node->data);
+ Picture *pic;
+ gboolean valid;
+
+ valid = gtk_tree_model_get_iter(model, &iter, path);
+ if (valid)
+ {
+ gtk_tree_model_get(model, &iter, PICTURE_COLUMN_DATA, &pic,-1);
+ Picture_Free(pic);
+
+ gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+ }
+
+ gtk_tree_row_reference_deleted(proxy, path);
+ gtk_tree_path_free(path);
+ gtk_tree_row_reference_free(node->data);
+ n++;
+ }
+ g_list_free(refs);
+
+ if (!n)
+ // Delete all if no one was selected.
+ PictureEntry_Clear();
+}
+
+/*
+ * - 'filename' : path + filename of picture file
+ */
+void Picture_Load_Filename (gchar *filename, gpointer user_data)
+{
+ Picture *pic;
+ gchar *filename_utf8;
+ gchar *filename_utf8_folded = NULL;
+ gchar *front_folded = NULL;
+ gchar *back_folded = NULL;
+ gchar *cd_folded = NULL;
+ gchar *inside_folded = NULL;
+ //gchar *inlay_folded = NULL;
+
+ // Filename must be passed in filesystem encoding!
+ pic = Picture_Load_File_Data(filename);
+
+ filename_utf8 = filename_to_display(filename);
+
+ if (pic && filename_utf8)
+ {
+ // Behaviour following the tag type...
+ switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
+ {
+ case MP4_TAG:
+ {
+ pic->type = PICTURE_TYPE_FRONT_COVER;
+ break;
+ }
+
+ // Other tag types
+ default:
+ {
+ // By default, set the filename in the description
+ pic->description = g_path_get_basename(filename_utf8);
+
+ // Try to identify the type of the picture from the file name
+ filename_utf8_folded = g_utf8_casefold(pic->description, -1);
+ front_folded = g_utf8_casefold("Front", -1);
+ back_folded = g_utf8_casefold("Back", -1);
+ cd_folded = g_utf8_casefold("CD", -1);
+ inside_folded = g_utf8_casefold("inside", -1);
+ //inlay_folded = g_utf8_casefold("inlay", -1);
+ if ( strstr(filename_utf8_folded, front_folded) != NULL )
+ pic->type = PICTURE_TYPE_FRONT_COVER;
+ else if ( strstr(filename_utf8_folded, back_folded) != NULL )
+ pic->type = PICTURE_TYPE_BACK_COVER;
+ else if ( strstr(filename_utf8_folded, cd_folded) != NULL )
+ pic->type = PICTURE_TYPE_MEDIA;
+ else if ( strstr(filename_utf8_folded, inside_folded) != NULL )
+ pic->type = PICTURE_TYPE_LEAFLET_PAGE;
+ //else if ( strstr(filename_utf8_folded, inlay_folded) != NULL )
+ // pic->type = PICTURE_TYPE_LEAFLET_PAGE;
+
+ break;
+ }
+ }
+
+ PictureEntry_Update(pic, 1);
+
+ // FIXME: Call Picture_Free(pic) here? It seems PictureEntry_Update makes copies of pic.
+ //Picture_Free(pic);
+ }
+
+ g_free(filename_utf8);
+ g_free(filename_utf8_folded);
+ g_free(front_folded);
+ g_free(back_folded);
+ g_free(cd_folded);
+ g_free(inside_folded);
+ //g_free(inlay_folded);
+}
+
+/*
+ * To add an image in the list -> call a FileSelectionWindow
+ */
+void Picture_Add_Button_Clicked (GObject *object)
+{
+ GtkWidget *FileSelectionWindow;
+ GtkFileFilter *filter;
+ GtkWindow *parent_window = NULL;
+ static gchar *init_dir = NULL;
+
+ if (!PictureEntryView) return;
+
+ parent_window = (GtkWindow *) gtk_widget_get_toplevel(GTK_WIDGET(object));
+ if (!GTK_WIDGET_TOPLEVEL(parent_window))
+ {
+ g_warning("Could not get parent window\n");
+ return;
+ }
+
+
+ FileSelectionWindow = gtk_file_chooser_dialog_new(_("Add pictures"),
+ parent_window,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+ NULL);
+
+ // Add files filters
+ // "All files" filter
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name(GTK_FILE_FILTER(filter), _("All Files"));
+ gtk_file_filter_add_pattern(GTK_FILE_FILTER(filter), "*");
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(FileSelectionWindow), GTK_FILE_FILTER(filter));
+
+ // "PNG and JPEG" filter
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name(GTK_FILE_FILTER(filter), _("PNG and JPEG"));
+ //gtk_file_filter_add_mime_type(GTK_FILE_FILTER(filter), "image/jpeg");
+ //gtk_file_filter_add_mime_type(GTK_FILE_FILTER(filter), "image/png");
+ gtk_file_filter_add_pattern(GTK_FILE_FILTER(filter), "*.jpeg");
+ gtk_file_filter_add_pattern(GTK_FILE_FILTER(filter), "*.jpg");
+ gtk_file_filter_add_pattern(GTK_FILE_FILTER(filter), "*.png");
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (FileSelectionWindow), GTK_FILE_FILTER(filter));
+ // Make this filter the default
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(FileSelectionWindow), GTK_FILE_FILTER(filter));
+
+ // Set window position
+ if (MESSAGE_BOX_POSITION_NONE)
+ gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_NONE);
+ else if (MESSAGE_BOX_POSITION_CENTER)
+ gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_CENTER);
+ else if (MESSAGE_BOX_POSITION_MOUSE)
+ gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_MOUSE);
+
+ // Behaviour following the tag type...
+ switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
+ {
+ case MP4_TAG:
+ {
+ // Only one file can be selected
+ gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(FileSelectionWindow), FALSE);
+ break;
+ }
+
+ // Other tag types
+ default:
+ {
+ gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(FileSelectionWindow), TRUE);
+ break;
+ }
+ }
+
+ gtk_dialog_set_default_response(GTK_DIALOG(FileSelectionWindow), GTK_RESPONSE_OK);
+
+ // Starting directory (the same of the current file)
+ if (ETCore->ETFileDisplayed)
+ {
+ gchar *cur_filename_utf8 = ((File_Name *)((GList *)ETCore->ETFileDisplayed->FileNameCur)->data)->value_utf8;
+ init_dir = g_path_get_dirname(cur_filename_utf8);
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow),init_dir);
+ }else
+ // Starting directory (the same than the previous one)
+ if (init_dir)
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow),init_dir);
+
+ if (gtk_dialog_run(GTK_DIALOG(FileSelectionWindow)) == GTK_RESPONSE_OK)
+ {
+ GtkTreeSelection *selection;
+ GSList *list;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
+ gtk_tree_selection_unselect_all(selection);
+
+ list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(FileSelectionWindow));
+ g_slist_foreach(list, (GFunc) Picture_Load_Filename, 0);
+ g_slist_free(list);
+
+ // Save the directory selected for initialize next time
+ g_free(init_dir);
+ init_dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow));
+ }
+ gtk_widget_destroy(FileSelectionWindow);
+}
+
+
+void Picture_Properties_Button_Clicked (GObject *object)
+{
+ GtkWidget *ScrollWindowPictureTypes, *PictureTypesWindow;
+ GtkWidget *type, *label, *desc;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+ GtkListStore *store;
+ GtkTreeIter type_iter_to_select, iter;
+ GtkTreeModel *model;
+ GtkWindow *parent_window = NULL;
+ GList *selection_list = NULL;
+ guint i;
+ gint selection_nbr, selection_i = 1;
+ gint picture_types[] =
+ {
+ PICTURE_TYPE_OTHER,
+ PICTURE_TYPE_FILE_ICON,
+ PICTURE_TYPE_OTHER_FILE_ICON,
+ PICTURE_TYPE_FRONT_COVER,
+ PICTURE_TYPE_BACK_COVER,
+ PICTURE_TYPE_LEAFLET_PAGE,
+ PICTURE_TYPE_MEDIA,
+ PICTURE_TYPE_LEAD_ARTIST_LEAD_PERFORMER_SOLOIST,
+ PICTURE_TYPE_ARTIST_PERFORMER,
+ PICTURE_TYPE_CONDUCTOR,
+ PICTURE_TYPE_BAND_ORCHESTRA,
+ PICTURE_TYPE_COMPOSER,
+ PICTURE_TYPE_LYRICIST_TEXT_WRITER,
+ PICTURE_TYPE_RECORDING_LOCATION,
+ PICTURE_TYPE_DURING_RECORDING,
+ PICTURE_TYPE_DURING_PERFORMANCE,
+ PICTURE_TYPE_MOVIDE_VIDEO_SCREEN_CAPTURE,
+ PICTURE_TYPE_A_BRIGHT_COLOURED_FISH,
+ PICTURE_TYPE_ILLUSTRATION,
+ PICTURE_TYPE_BAND_ARTIST_LOGOTYPE,
+ PICTURE_TYPE_PUBLISHER_STUDIO_LOGOTYPE
+ };
+
+
+ if (!PictureEntryView) return;
+
+ parent_window = (GtkWindow *) gtk_widget_get_toplevel(GTK_WIDGET(object));
+ if (!GTK_WIDGET_TOPLEVEL(parent_window))
+ {
+ g_warning("Could not get parent window\n");
+ return;
+ }
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView));
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
+ selection_list = gtk_tree_selection_get_selected_rows(selection, NULL);
+ selection_nbr = gtk_tree_selection_count_selected_rows(GTK_TREE_SELECTION(selection));
+ while (selection_list)
+ {
+ GtkTreePath *path = selection_list->data;
+ Picture *pic = NULL;
+ GtkTreeSelection *selectiontype;
+ gchar *title;
+ GtkTreePath *rowPath;
+ gboolean valid;
+
+ // Get corresponding picture
+ valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
+ if (valid)
+ gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, PICTURE_COLUMN_DATA, &pic, -1);
+
+ title = g_strdup_printf(_("Picture Properties %d/%d"),selection_i++,selection_nbr);
+ PictureTypesWindow = gtk_dialog_new_with_buttons(title,
+ parent_window,
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
+ g_free(title);
+
+ // Set window position
+ if (MESSAGE_BOX_POSITION_NONE)
+ gtk_window_set_position(GTK_WINDOW(PictureTypesWindow),GTK_WIN_POS_NONE);
+ else if (MESSAGE_BOX_POSITION_CENTER)
+ gtk_window_set_position(GTK_WINDOW(PictureTypesWindow),GTK_WIN_POS_CENTER);
+ else if (MESSAGE_BOX_POSITION_MOUSE)
+ gtk_window_set_position(GTK_WINDOW(PictureTypesWindow),GTK_WIN_POS_MOUSE);
+
+ gtk_dialog_set_default_response(GTK_DIALOG(PictureTypesWindow), GTK_RESPONSE_OK);
+
+ ScrollWindowPictureTypes = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ScrollWindowPictureTypes),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ store = gtk_list_store_new(PICTURE_TYPE_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_INT);
+ type = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+ gtk_container_add(GTK_CONTAINER(ScrollWindowPictureTypes), type);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_column_pack_start(column, renderer, FALSE);
+ gtk_tree_view_column_set_title(column, _("Picture Type"));
+ gtk_tree_view_column_set_attributes(column, renderer,
+ "text", PICTURE_TYPE_COLUMN_TEXT,
+ NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(type), column);
+ gtk_widget_set_size_request(type, 256, 256);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(PictureTypesWindow)->vbox),ScrollWindowPictureTypes,TRUE,TRUE,0);
+
+ // Behaviour following the tag type...
+ switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
+ {
+ case MP4_TAG:
+ {
+ // Load picture type (only Front Cover!)
+ GtkTreeIter itertype;
+
+ gtk_list_store_append(store, &itertype);
+ gtk_list_store_set(store, &itertype,
+ PICTURE_TYPE_COLUMN_TEXT, _(Picture_Type_String(PICTURE_TYPE_FRONT_COVER)),
+ PICTURE_TYPE_COLUMN_TYPE_CODE, PICTURE_TYPE_FRONT_COVER,
+ -1);
+ // Line to select by default
+ type_iter_to_select = itertype;
+ break;
+ }
+
+ // Other tag types
+ default:
+ {
+ // Load pictures types
+ for (i = 0; i < sizeof(picture_types)/sizeof(picture_types[0]); i++)
+ {
+ GtkTreeIter itertype;
+
+ gtk_list_store_append(store, &itertype);
+ gtk_list_store_set(store, &itertype,
+ PICTURE_TYPE_COLUMN_TEXT, _(Picture_Type_String(picture_types[i])),
+ PICTURE_TYPE_COLUMN_TYPE_CODE, picture_types[i],
+ -1);
+ // Line to select by default
+ if (pic->type == picture_types[i])
+ type_iter_to_select = itertype;
+ }
+ break;
+ }
+ }
+
+ // Select the line by default
+ selectiontype = gtk_tree_view_get_selection(GTK_TREE_VIEW(type));
+ gtk_tree_selection_select_iter(selectiontype, &type_iter_to_select);
+
+ // Set visible the current selected line
+ rowPath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &type_iter_to_select);
+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(type), rowPath, NULL, FALSE, 0, 0);
+ gtk_tree_path_free(rowPath);
+
+ // Description
+ label = gtk_label_new(_("Picture Description:"));
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(PictureTypesWindow)->vbox),label,FALSE,FALSE,4);
+
+ // Entry for the description
+ desc = gtk_entry_new();
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(PictureTypesWindow)->vbox),desc,FALSE,FALSE,0);
+ if (pic->description)
+ {
+ gchar *tmp = ET_Utf8_Validate_Full_String(pic->description);
+ gtk_entry_set_text(GTK_ENTRY(desc), tmp);
+ g_free(tmp);
+ }
+
+ // Behaviour following the tag type...
+ switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
+ {
+ case MP4_TAG:
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(label), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(desc), FALSE);
+ break;
+ }
+
+ // Other tag types
+ default:
+ {
+ break;
+ }
+ }
+
+ gtk_widget_show_all(PictureTypesWindow);
+
+ if (gtk_dialog_run(GTK_DIALOG(PictureTypesWindow)) == GTK_RESPONSE_OK)
+ {
+ GtkTreeModel *modeltype;
+ GtkTreeIter itertype;
+
+ modeltype = gtk_tree_view_get_model(GTK_TREE_VIEW(type));
+ selectiontype = gtk_tree_view_get_selection(GTK_TREE_VIEW(type));
+ if (gtk_tree_selection_get_selected(selectiontype, &modeltype, &itertype))
+ {
+ gchar *buffer, *pic_info;
+ gint t;
+
+ gtk_tree_model_get(modeltype, &itertype,
+ PICTURE_TYPE_COLUMN_TYPE_CODE, &t, -1);
+ pic->type = t;
+
+ buffer = g_strdup(gtk_entry_get_text(GTK_ENTRY(desc)));
+ Strip_String(buffer);
+ if (pic->description)
+ g_free(pic->description);
+ if ( g_utf8_strlen(buffer, -1) > 0 )
+ {
+ pic->description = buffer;
+ }else
+ {
+ pic->description = 0;
+ g_free(buffer);
+ }
+
+ // Update value in the PictureEntryView
+ pic_info = Picture_Info(pic);
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+ PICTURE_COLUMN_TEXT, pic_info,
+ -1);
+ g_free(pic_info);
+ }
+ }
+ gtk_widget_destroy(PictureTypesWindow);
+
+ if (!selection_list->next) break;
+ selection_list = selection_list->next;
+ }
+}
+
+
+void Picture_Save_Button_Clicked (GObject *object)
+{
+ GtkWidget *FileSelectionWindow;
+ GtkFileFilter *filter;
+ GtkWindow *parent_window = NULL;
+ static gchar *init_dir = NULL;
+
+ GtkTreeSelection *selection;
+ GList *selection_list = NULL;
+ GtkTreeModel *model;
+ gint selection_nbr, selection_i = 1;
+
+
+ if (!PictureEntryView) return;
+
+ parent_window = (GtkWindow*) gtk_widget_get_toplevel(GTK_WIDGET(object));
+ if (!GTK_WIDGET_TOPLEVEL(parent_window))
+ {
+ g_warning("Could not get parent window\n");
+ return;
+ }
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView));
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
+ selection_list = gtk_tree_selection_get_selected_rows(selection, NULL);
+ selection_nbr = gtk_tree_selection_count_selected_rows(GTK_TREE_SELECTION(selection));
+
+ while (selection_list)
+ {
+ GtkTreePath *path = selection_list->data;
+ GtkTreeIter iter;
+ Picture *pic;
+ gchar *title;
+ gboolean valid;
+
+ // Get corresponding picture
+ valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
+ if (valid)
+ gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, PICTURE_COLUMN_DATA, &pic, -1);
+
+ title = g_strdup_printf(_("Save picture %d/%d"),selection_i++,selection_nbr);
+ FileSelectionWindow = gtk_file_chooser_dialog_new(title,
+ parent_window,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+ g_free(title);
+
+ // Add files filters
+ // "All files" filter
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name(GTK_FILE_FILTER(filter), _("All Files"));
+ gtk_file_filter_add_pattern(GTK_FILE_FILTER(filter), "*");
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(FileSelectionWindow), GTK_FILE_FILTER(filter));
+
+ // "PNG and JPEG" filter
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name(GTK_FILE_FILTER(filter), _("PNG and JPEG"));
+ gtk_file_filter_add_mime_type(GTK_FILE_FILTER(filter), "image/jpeg");
+ gtk_file_filter_add_mime_type(GTK_FILE_FILTER(filter), "image/png");
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (FileSelectionWindow), GTK_FILE_FILTER(filter));
+ // Make this filter the default
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(FileSelectionWindow), GTK_FILE_FILTER(filter));
+
+ // Set window position
+ if (MESSAGE_BOX_POSITION_NONE)
+ gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_NONE);
+ else if (MESSAGE_BOX_POSITION_CENTER)
+ gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_CENTER);
+ else if (MESSAGE_BOX_POSITION_MOUSE)
+ gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_MOUSE);
+
+ gtk_dialog_set_default_response(GTK_DIALOG(FileSelectionWindow), GTK_RESPONSE_OK);
+
+ // Set the default folder if defined
+ if (init_dir)
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow),init_dir);
+
+ // Suggest a filename to the user
+ if ( pic->description && strlen(pic->description) )
+ {
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(FileSelectionWindow), pic->description); //filename in UTF8
+ }else
+ {
+ gchar *image_name = NULL;
+ switch (Picture_Format(pic))
+ {
+ case PICTURE_FORMAT_JPEG :
+ image_name = g_strdup("image_name.jpg");
+ break;
+ case PICTURE_FORMAT_PNG :
+ image_name = g_strdup("image_name.png");
+ break;
+ case PICTURE_FORMAT_UNKNOWN :
+ image_name = g_strdup("image_name.ext");
+ break;
+ }
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(FileSelectionWindow), image_name); //filename in UTF8
+ g_free(image_name);
+ }
+
+ if (gtk_dialog_run(GTK_DIALOG(FileSelectionWindow)) == GTK_RESPONSE_OK)
+ {
+ FILE *file;
+ gchar *filename, *filename_utf8;
+
+ // Save the directory selected for initialize next time
+ g_free(init_dir);
+ init_dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow));
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(FileSelectionWindow));
+ filename_utf8 = filename_to_display(filename);
+
+ // Warn user if the file already exists, else saves directly
+ if ( (file=fopen(filename_utf8,"r"))!=NULL )
+ {
+ gchar *msg;
+ GtkWidget *msgbox;
+ gint button;
+
+ fclose(file);
+
+ msg = g_strdup_printf(_("The following file already exists :\n'%s'\n"
+ "Do you want to overwrite?"),filename_utf8);
+ msgbox = msg_box_new(_("Save file..."),msg,GTK_STOCK_DIALOG_QUESTION,BUTTON_NO,BUTTON_YES,0);
+ g_free(msg);
+ msg_box_hide_check_button(MSG_BOX(msgbox));
+ button = msg_box_run(MSG_BOX(msgbox));
+ gtk_widget_destroy(msgbox);
+
+ if (button == BUTTON_YES)
+ {
+ Picture_Save_File_Data(pic, filename_utf8);
+ }
+ }else
+ {
+ Picture_Save_File_Data(pic, filename_utf8);
+ }
+ g_free(filename_utf8);
+ }
+ gtk_widget_destroy(FileSelectionWindow);
+
+ if (!selection_list->next) break;
+ selection_list = selection_list->next;
+ }
+}
+
+
+/* FIXME: Possibly use gnome_vfs_get_mime_type_for_buffer. */
+gint Picture_Format (Picture *pic)
+{
+ if (pic->data && pic->size > 2
+ && pic->data[0] == 0xff
+ && pic->data[1] == 0xd8)
+ return PICTURE_FORMAT_JPEG;
+
+ if (pic->data && pic->size > 8
+ && pic->data[0] == 0x89
+ && pic->data[1] == 0x50
+ && pic->data[2] == 0x4e
+ && pic->data[3] == 0x47
+ && pic->data[4] == 0x0d
+ && pic->data[5] == 0x0a
+ && pic->data[6] == 0x1a
+ && pic->data[7] == 0x0a)
+ return PICTURE_FORMAT_PNG;
+
+ return PICTURE_FORMAT_UNKNOWN;
+}
+
+const gchar *Picture_Format_String (gint format)
+{
+ switch (format)
+ {
+ case PICTURE_FORMAT_JPEG:
+ return _("JPEG image");
+ case PICTURE_FORMAT_PNG:
+ return _("PNG image");
+ default:
+ return _("Unknown image");
+ }
+}
+
+const gchar *Picture_Type_String (gint type)
+{
+ switch (type)
+ {
+ case PICTURE_TYPE_OTHER:
+ return _("Other");
+ case PICTURE_TYPE_FILE_ICON:
+ return _("32x32 pixel PNG file icon");
+ case PICTURE_TYPE_OTHER_FILE_ICON:
+ return _("Other file icon");
+ case PICTURE_TYPE_FRONT_COVER:
+ return _("Cover (front)");
+ case PICTURE_TYPE_BACK_COVER:
+ return _("Cover (back)");
+ case PICTURE_TYPE_LEAFLET_PAGE:
+ return _("Leaflet page");
+ case PICTURE_TYPE_MEDIA:
+ return _("Media (e.g. label side of CD)");
+ case PICTURE_TYPE_LEAD_ARTIST_LEAD_PERFORMER_SOLOIST:
+ return _("Lead artist/lead performer/soloist");
+ case PICTURE_TYPE_ARTIST_PERFORMER:
+ return _("Artist/performer");
+ case PICTURE_TYPE_CONDUCTOR:
+ return _("Conductor");
+ case PICTURE_TYPE_BAND_ORCHESTRA:
+ return _("Band/Orchestra");
+ case PICTURE_TYPE_COMPOSER:
+ return _("Composer");
+ case PICTURE_TYPE_LYRICIST_TEXT_WRITER:
+ return _("Lyricist/text writer");
+ case PICTURE_TYPE_RECORDING_LOCATION:
+ return _("Recording location");
+ case PICTURE_TYPE_DURING_RECORDING:
+ return _("During recording");
+ case PICTURE_TYPE_DURING_PERFORMANCE:
+ return _("During performance");
+ case PICTURE_TYPE_MOVIDE_VIDEO_SCREEN_CAPTURE:
+ return _("Movie/video screen capture");
+ case PICTURE_TYPE_A_BRIGHT_COLOURED_FISH:
+ return _("A bright coloured fish");
+ case PICTURE_TYPE_ILLUSTRATION:
+ return _("Illustration");
+ case PICTURE_TYPE_BAND_ARTIST_LOGOTYPE:
+ return _("Band/Artist logotype");
+ case PICTURE_TYPE_PUBLISHER_STUDIO_LOGOTYPE:
+ return _("Publisher/studio logotype");
+ default:
+ return _("Unknown picture type");
+ }
+}
+
+gchar *Picture_Info (Picture *pic)
+{
+ gchar *format, *desc, *type, *r, *size_str;
+ GString *s;
+
+ format = (gchar *)Picture_Format_String(Picture_Format(pic));
+
+ if (pic->description)
+ desc = pic->description;
+ else
+ desc = "";
+
+ type = (gchar *)Picture_Type_String(pic->type);
+ size_str = Convert_Size_1((gfloat)pic->size);
+
+ s = g_string_new(0);
+ // Behaviour following the tag type...
+ switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
+ {
+ case MP4_TAG:
+ {
+ g_string_sprintf(s, "%s (%s - %dx%d %s)\n%s: %s",
+ format,
+ size_str,
+ pic->width, pic->height, _("pixels"),
+ _("Type"), type);
+ break;
+ }
+
+ // Other tag types
+ default:
+ {
+ g_string_sprintf(s, "%s (%s - %dx%d %s)\n%s: %s\n%s: %s",
+ format,
+ size_str,
+ pic->width, pic->height, _("pixels"),
+ _("Type"), type,
+ _("Description"), desc);
+ break;
+ }
+ }
+ r = ET_Utf8_Validate_Full_String(s->str);
+ g_string_free(s, TRUE); // TRUE to free also 's->str'!
+ g_free(size_str);
+
+ return r;
+}
+
+void PictureEntry_Clear (void)
+{
+ GtkListStore *picture_store;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ Picture *pic;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView));
+ if (gtk_tree_model_get_iter_first(model, &iter))
+ {
+ do
+ {
+ gtk_tree_model_get(model, &iter, PICTURE_COLUMN_DATA, &pic,-1);
+ Picture_Free(pic);
+ } while (gtk_tree_model_iter_next(model, &iter));
+ }
+
+ picture_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView)));
+ if (picture_store)
+ gtk_list_store_clear(picture_store);
+}
+
+void PictureEntry_Update (Picture *pic, gint select)
+{
+ GdkPixbufLoader *loader = 0;
+
+ if (!pic || !PictureEntryView) return;
+
+ if (!pic->data)
+ {
+ PictureEntry_Clear();
+ return;
+ }
+
+ loader = gdk_pixbuf_loader_new();
+ if (loader)
+ {
+ if (gdk_pixbuf_loader_write(loader, pic->data, pic->size, 0))
+ {
+ GtkTreeSelection *selection;
+ GdkPixbuf *pixbuf;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
+ if (pixbuf)
+ {
+ GtkListStore *picture_store;
+ GtkTreeIter iter1;
+ GdkPixbuf *scaled_pixbuf;
+ gint scaled_pixbuf_width;
+ gint scaled_pixbuf_height;
+ gchar *pic_info;
+
+ // Keep aspect ratio of the picture
+ pic->width = gdk_pixbuf_get_width (pixbuf);
+ pic->height = gdk_pixbuf_get_height (pixbuf);
+ if (pic->width > pic->height)
+ {
+ scaled_pixbuf_width = 96;
+ scaled_pixbuf_height = 96 * pic->height / pic->width;
+ }else
+ {
+ scaled_pixbuf_width = 96 * pic->width / pic->height;
+ scaled_pixbuf_height = 96;
+ }
+
+ scaled_pixbuf = gdk_pixbuf_scale_simple(pixbuf,
+ scaled_pixbuf_width, scaled_pixbuf_height,
+ //GDK_INTERP_NEAREST); // Lower quality but better speed
+ GDK_INTERP_BILINEAR);
+ gdk_pixbuf_unref(pixbuf);
+
+ picture_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView)));
+ gtk_list_store_append(picture_store, &iter1);
+ pic_info = Picture_Info(pic);
+ gtk_list_store_set(picture_store, &iter1,
+ PICTURE_COLUMN_PIC, scaled_pixbuf,
+ PICTURE_COLUMN_TEXT, pic_info,
+ PICTURE_COLUMN_DATA, Picture_Copy_One(pic),
+ -1);
+ g_free(pic_info);
+
+ if (select)
+ gtk_tree_selection_select_iter(selection, &iter1);
+ gdk_pixbuf_unref(scaled_pixbuf);
+ }else
+ {
+ GtkWidget *msgbox = NULL;
+ gchar *msg = NULL;
+
+ msg = g_strdup(_("Can't display the picture, as not enough data "
+ "has been read to determine how to create the image buffer."));
+ Log_Print("%s",msg);
+ msgbox = msg_box_new(_("Loading Picture File..."),msg,
+ GTK_STOCK_DIALOG_ERROR,BUTTON_YES,0);
+ msg_box_hide_check_button(MSG_BOX(msgbox));
+ g_free(msg);
+ msg_box_run(MSG_BOX(msgbox));
+ gtk_widget_destroy(msgbox);
+ }
+ }
+ }
+ gdk_pixbuf_loader_close(loader, 0);
+
+ // Do also for next picture
+ if (pic->next)
+ PictureEntry_Update(pic->next, select);
+
+ return;
+}
+
+
+Picture *Picture_Allocate (void)
+{
+ Picture *pic = g_malloc0(sizeof(Picture));
+ return pic;
+}
+
+Picture *Picture_Copy_One (const Picture *pic)
+{
+ Picture *pic2;
+
+ if (!pic)
+ return 0;
+ pic2 = Picture_Allocate();
+ pic2->type = pic->type;
+ pic2->width = pic->width;
+ pic2->height = pic->height;
+ if (pic->description)
+ pic2->description = g_strdup(pic->description);
+ if (pic->data)
+ {
+ pic2->size = pic->size;
+ pic2->data = g_malloc(pic2->size);
+ memcpy(pic2->data, pic->data, pic->size);
+ }
+ return pic2;
+}
+
+Picture *Picture_Copy (const Picture *pic)
+{
+ Picture *pic2 = Picture_Copy_One(pic);
+ if (pic->next)
+ pic2->next = Picture_Copy(pic->next);
+ return pic2;
+}
+
+void Picture_Free (Picture *pic)
+{
+ if (!pic)
+ return;
+ if (pic->next)
+ Picture_Free(pic->next);
+ if (pic->description)
+ g_free(pic->description);
+ if (pic->data)
+ g_free(pic->data);
+ g_free(pic);
+}
+
+
+/*
+ * Load the picture represented by the 'filename' (must be passed in
+ * file system encoding, not UTF-8)
+ */
+Picture *Picture_Load_File_Data (const gchar *filename)
+{
+ Picture *pic;
+ gchar *buffer = 0;
+ size_t size = 0;
+ struct stat st;
+
+ if (lstat(filename, &st)==-1)
+ return (Picture *)NULL;
+
+ size = st.st_size;
+ buffer = g_malloc(size);
+
+ FILE *fd = fopen(filename, "rb");
+ if (!fd)
+ {
+ gchar *msg;
+ gchar *filename_utf8;
+ GtkWidget *msgbox;
+
+ /* Picture file not opened */
+ filename_utf8 = filename_to_display(filename);
+ msg = g_strdup_printf(_("Can't open file :\n'%s'!\n(%s)"),
+ filename_utf8,g_strerror(errno));
+ msgbox = msg_box_new(_("Error..."),msg,GTK_STOCK_DIALOG_ERROR,BUTTON_OK,0);
+ g_free(msg);
+ msg_box_hide_check_button(MSG_BOX(msgbox));
+ msg_box_run(MSG_BOX(msgbox));
+ gtk_widget_destroy(msgbox);
+
+ Statusbar_Message(_("Picture file not loaded..."),TRUE);
+ g_free(filename_utf8);
+ return FALSE;
+ }
+
+ if (fread(buffer, size, 1, fd) != 1)
+ goto fail;
+
+ fclose(fd);
+
+ pic = Picture_Allocate();
+ pic->size = size;
+ pic->data = (guchar *)buffer;
+ return pic;
+
+ fail:
+ if (buffer)
+ g_free(buffer);
+ fclose(fd);
+ return (Picture *)NULL;
+}
+
+/*
+ * Save picture data to a file (jpeg, png)
+ */
+gboolean Picture_Save_File_Data (const Picture *pic, const gchar *filename)
+{
+ gint fd;
+
+ fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ if (fd == -1)
+ return FALSE;
+
+ if (write(fd, pic->data, pic->size) != pic->size)
+ {
+ close(fd);
+ return FALSE;
+ }
+
+ close(fd);
+ return TRUE;
+}
+
+/*
+ * If double clicking the PictureEntryView :
+ * - over a selected row : opens properties window
+ * - over an empty area : open the adding window
+ */
+gboolean Picture_Entry_View_Button_Pressed (GtkTreeView *treeview, GdkEventButton *event, gpointer data)
+{
+ if (event->type==GDK_2BUTTON_PRESS && event->button==1)
+ {
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
+
+ if (gtk_tree_selection_count_selected_rows(GTK_TREE_SELECTION(selection)) != 0)
+ Picture_Properties_Button_Clicked(G_OBJECT(PicturePropertiesButton));
+ else
+ Picture_Add_Button_Clicked(G_OBJECT(PictureAddButton));
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * Key press into picture entry
+ * - Delete = delete selected picture files
+ */
+gboolean Picture_Entry_View_Key_Pressed (GtkTreeView *treeview, GdkEvent *event, gpointer data)
+{
+ GdkEventKey *kevent;
+
+ kevent = (GdkEventKey *)event;
+ if (event && event->type==GDK_KEY_PRESS)
+ {
+ switch(kevent->keyval)
+ {
+ case GDK_Delete:
+ Picture_Clear_Button_Clicked(NULL);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}