diff options
Diffstat (limited to 'src')
41 files changed, 5918 insertions, 7022 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 5debbbb..4ea7a66 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -108,7 +108,7 @@ clean: rm -rf .libs distclean: clean - rm -f Makefile $(PROGRAMS) + rm -f Makefile $(PROGRAMS) depend: makedepend $(INCLUDES) *.c @@ -232,6 +232,7 @@ xsane-multipage-project.o: xsane-front-gtk.h xsane-multipage-project.o: xsane-preferences.h xsane-multipage-project.o: xsane-multipage-project.h xsane-multipage-project.o: xsane-text.h +xsane-multipage-project.o: xsane-save.h xsane-fax-project.o: xsane.h xsane-fax-project.o: xsane-back-gtk.h diff --git a/src/xsane-back-gtk.c b/src/xsane-back-gtk.c index 10ac0b3..6ed24a4 100644 --- a/src/xsane-back-gtk.c +++ b/src/xsane-back-gtk.c @@ -3,7 +3,7 @@ xsane-back-gtk.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -470,7 +470,7 @@ void xsane_back_gtk_set_option(int opt_num, void *val, SANE_Action action) SANE_Status status; SANE_Int info; char buf[TEXTBUFSIZE]; - int old_colors = xsane.xsane_colors; + int old_channels = xsane.xsane_channels; int update_gamma = FALSE; DBG(DBG_proc, "xsane_back_gtk_set_option\n"); @@ -505,7 +505,7 @@ void xsane_back_gtk_set_option(int opt_num, void *val, SANE_Action action) /* XXXXXXXXXXXXXX this also has to be handled XXXXXXXXXXXXXXX */ } - if (xsane.xsane_colors != old_colors) + if (xsane.xsane_channels != old_channels) { /* we have to update gamma tables and histogram because medium settings */ /* may have changed */ @@ -734,7 +734,7 @@ gint xsane_back_gtk_decision(gchar *title, gchar **xpm_d, gchar *message, gchar button = gtk_button_new_with_label(oktext); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_back_gtk_decision_ok_callback, (void *) decision_flag_ptr); - gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5); + gtk_box_pack_end(GTK_BOX(hbox), button, TRUE, TRUE, 5); gtk_widget_grab_default(button); gtk_widget_show(button); @@ -743,7 +743,7 @@ gint xsane_back_gtk_decision(gchar *title, gchar **xpm_d, gchar *message, gchar { button = gtk_button_new_with_label(rejecttext); g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_back_gtk_decision_reject_callback, (void *) decision_flag_ptr); - gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5); + gtk_box_pack_end(GTK_BOX(hbox), button, TRUE, TRUE, 5); gtk_widget_show(button); } @@ -871,59 +871,6 @@ void xsane_back_gtk_info(gchar *info, int wait) /* ---------------------------------------------------------------------------------------------------------------------- */ -GtkWidget *fileselection; -char *fileselection_filetype = NULL; - -static void xsane_back_gtk_filetype_callback(GtkWidget *widget, gpointer data) -{ - char *extension, *filename; - char buffer[PATH_MAX]; - char *new_filetype = (char *) data; - - DBG(DBG_proc, "xsane_filetype_callback\n"); - - filename = strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection))); - - if ((new_filetype) && (*new_filetype)) - { - extension = strrchr(filename, '.'); - - if ((extension) && (extension != filename)) - { - if ( (!strcasecmp(extension, ".pnm")) || (!strcasecmp(extension, ".raw")) - || (!strcasecmp(extension, ".png")) || (!strcasecmp(extension, ".ps")) - || (!strcasecmp(extension, ".pdf")) || (!strcasecmp(extension, ".rgba")) - || (!strcasecmp(extension, ".tiff")) || (!strcasecmp(extension, ".tif")) - || (!strcasecmp(extension, ".text")) || (!strcasecmp(extension, ".txt")) - || (!strcasecmp(extension, ".jpg")) || (!strcasecmp(extension, ".jpeg")) - ) /* remove filetype extension */ - { - *extension = 0; /* remove extension */ - } - } - snprintf(buffer, sizeof(buffer), "%s%s", filename, new_filetype); - free(filename); - filename = strdup(buffer); - } - - if (fileselection_filetype) - { - free(fileselection_filetype); - fileselection_filetype = NULL; - } - - if (data) - { - fileselection_filetype = strdup(new_filetype); - } - - gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection), filename); - - free(filename); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - void xsane_back_gtk_filetype_menu_set_history(GtkWidget *xsane_filetype_option_menu, char *filetype) { int filetype_nr; @@ -940,6 +887,13 @@ void xsane_back_gtk_filetype_menu_set_history(GtkWidget *xsane_filetype_option_m } #endif + filetype_nr++; + if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PDF)) ) + { + select_item = filetype_nr; + } + + #ifdef HAVE_LIBPNG #ifdef HAVE_LIBZ filetype_nr++; @@ -962,12 +916,6 @@ void xsane_back_gtk_filetype_menu_set_history(GtkWidget *xsane_filetype_option_m select_item = filetype_nr; } - filetype_nr++; - if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PDF)) ) - { - select_item = filetype_nr; - } - #ifdef SUPPORT_RGBA filetype_nr++; if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_RGBA)) ) @@ -1112,6 +1060,475 @@ GtkWidget *xsane_back_gtk_filetype_menu_new(char *filetype, GtkSignalFunc filety /* ----------------------------------------------------------------------------------------------------------------- */ +GtkWidget *xsane_back_gtk_cms_function_menu_new(int select_cms_function, GtkSignalFunc cms_function_menu_callback) +{ + GtkWidget *xsane_cms_function_menu, *xsane_cms_function_item; + GtkWidget *xsane_cms_function_option_menu; + + xsane_cms_function_menu = gtk_menu_new(); + + xsane_cms_function_item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE); + if (cms_function_menu_callback) + { + g_signal_connect(GTK_OBJECT(xsane_cms_function_item), "activate", (GtkSignalFunc) cms_function_menu_callback, (void *) XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE); + } + gtk_container_add(GTK_CONTAINER(xsane_cms_function_menu), xsane_cms_function_item); + gtk_widget_show(xsane_cms_function_item); + + xsane_cms_function_item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_FUNCTION_CONVERT_TO_SRGB); + if (cms_function_menu_callback) + { + g_signal_connect(GTK_OBJECT(xsane_cms_function_item), "activate", (GtkSignalFunc) cms_function_menu_callback, (void *) XSANE_CMS_FUNCTION_CONVERT_TO_SRGB); + } + gtk_container_add(GTK_CONTAINER(xsane_cms_function_menu), xsane_cms_function_item); + gtk_widget_show(xsane_cms_function_item); + + xsane_cms_function_item = gtk_menu_item_new_with_label(MENU_ITEM_FUNCTION_CONVERT_TO_WORKING_CS); + if (cms_function_menu_callback) + { + g_signal_connect(GTK_OBJECT(xsane_cms_function_item), "activate", (GtkSignalFunc) cms_function_menu_callback, (void *) XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS); + } + gtk_container_add(GTK_CONTAINER(xsane_cms_function_menu), xsane_cms_function_item); + gtk_widget_show(xsane_cms_function_item); + + xsane_cms_function_option_menu = gtk_option_menu_new(); + xsane_back_gtk_set_tooltip(xsane.tooltips, xsane_cms_function_option_menu, DESC_CMS_FUNCTION); + gtk_option_menu_set_menu(GTK_OPTION_MENU(xsane_cms_function_option_menu), xsane_cms_function_menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(xsane_cms_function_option_menu), select_cms_function); + + return (xsane_cms_function_option_menu); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +#ifdef __GTK_FILE_CHOOSER_H__ + +GtkWidget *filechooser; +char *filechooser_filetype = NULL; + +static void xsane_back_gtk_filetype2_callback(GtkWidget *widget, gpointer data) +{ + char *extension, *chooser_filename; + char filename[PATH_MAX]; + char *basename; + char *new_filetype = (char *) data; + int pos; + + DBG(DBG_proc, "xsane_filetype2_callback\n"); + + chooser_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser)); + + if ((new_filetype) && (*new_filetype)) + { + extension = strrchr(chooser_filename, '.'); + + if ((extension) && (extension != chooser_filename)) + { + if ( (!strcasecmp(extension, ".pnm")) || (!strcasecmp(extension, ".raw")) + || (!strcasecmp(extension, ".png")) || (!strcasecmp(extension, ".ps")) + || (!strcasecmp(extension, ".pdf")) || (!strcasecmp(extension, ".rgba")) + || (!strcasecmp(extension, ".tiff")) || (!strcasecmp(extension, ".tif")) + || (!strcasecmp(extension, ".text")) || (!strcasecmp(extension, ".txt")) + || (!strcasecmp(extension, ".jpg")) || (!strcasecmp(extension, ".jpeg")) + ) /* remove filetype extension */ + { + *extension = 0; /* remove extension */ + } + } + snprintf(filename, sizeof(filename), "%s%s", chooser_filename, new_filetype); + } + + if (filechooser_filetype) + { + free(filechooser_filetype); + filechooser_filetype = NULL; + } + + if (data) + { + filechooser_filetype = strdup(new_filetype); + } + + + basename = filename; + + for (pos = strlen(filename) - 1; pos > 0; pos--) + { + if (filename[pos] == '/') + { + filename[pos]=0; + + basename = filename+pos+1; + break; + } + } + + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filechooser), basename); + + g_free(chooser_filename); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +int xsane_back_gtk_get_filename(const char *label, const char *default_name, size_t max_len, char *filename, char **filetype, int *cms_function, + XsaneFileChooserAction action, int show_extra_widgets, int enable_filters, int activate_filter) +{ + int ok = 0; + GtkWidget *xsane_filetype_option_menu; + GtkWidget *xsane_cms_function_option_menu = xsane_cms_function_option_menu; + gint result; + const gchar *accept_text = NULL; + const gchar *reject_text = NULL; + GtkFileChooserAction chooser_action = GTK_FILE_CHOOSER_ACTION_OPEN; + GtkResponseType accept_code; + GtkResponseType reject_code; + char buf[PATH_MAX]; + + + DBG(DBG_proc, "xsane_back_gtk_get_filename\n"); + + if (filechooser) + { + gdk_beep(); + return -1; /* cancel => do not allow to open more than one filechooser dialog */ + } + + switch (action) + { + default: + case XSANE_FILE_CHOOSER_ACTION_OPEN: + chooser_action = GTK_FILE_CHOOSER_ACTION_OPEN; + accept_text = GTK_STOCK_OPEN; + accept_code = GTK_RESPONSE_ACCEPT; + reject_text = GTK_STOCK_CANCEL; + reject_code = GTK_RESPONSE_CANCEL; + break; + + case XSANE_FILE_CHOOSER_ACTION_SELECT_OPEN: + chooser_action = GTK_FILE_CHOOSER_ACTION_OPEN; + accept_text = GTK_STOCK_OK; + accept_code = GTK_RESPONSE_ACCEPT; + reject_text = GTK_STOCK_CANCEL; + reject_code = GTK_RESPONSE_CANCEL; + break; + + case XSANE_FILE_CHOOSER_ACTION_SAVE: + chooser_action = GTK_FILE_CHOOSER_ACTION_SAVE; + accept_text = GTK_STOCK_SAVE; + accept_code = GTK_RESPONSE_ACCEPT; + reject_text = GTK_STOCK_CANCEL; + reject_code = GTK_RESPONSE_CANCEL; + break; + + case XSANE_FILE_CHOOSER_ACTION_SELECT_SAVE: + chooser_action = GTK_FILE_CHOOSER_ACTION_SAVE; + accept_text = GTK_STOCK_OK; + accept_code = GTK_RESPONSE_ACCEPT; + reject_text = GTK_STOCK_CANCEL; + reject_code = GTK_RESPONSE_CANCEL; + break; + + case XSANE_FILE_CHOOSER_ACTION_SELECT_FOLDER: + chooser_action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; + accept_text = GTK_STOCK_OK; + accept_code = GTK_RESPONSE_ACCEPT; + reject_text = GTK_STOCK_CANCEL; + reject_code = GTK_RESPONSE_CANCEL; + break; + + case XSANE_FILE_CHOOSER_ACTION_SELECT_PROJECT: + chooser_action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; + accept_text = GTK_STOCK_OK; + accept_code = GTK_RESPONSE_NO; /* when we would use ACCEPT, OK, YES or APPLY then the filechooser_dialog would create non existant directories */ + reject_text = GTK_STOCK_CANCEL; + reject_code = GTK_RESPONSE_CANCEL; + break; + } + + filechooser = gtk_file_chooser_dialog_new (label, + NULL, + chooser_action, + reject_text, reject_code, + accept_text, accept_code, + NULL); + + xsane_set_window_icon(filechooser, 0); + + gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(filechooser), TRUE); + + + /* add paths to filechooser */ + if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL) + { + snprintf(buf, sizeof(buf)-2, "%s", getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME))); + gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), buf, NULL); + } + + if (getcwd(buf, sizeof(buf))) + { + gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), buf, NULL); + } + + + if (enable_filters & XSANE_FILE_FILTER_ALL) /* filter: all files */ + { + GtkFileFilter *filter; + + filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*"); + + gtk_file_filter_set_name(filter, FILE_FILTER_ALL_FILES); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter); + + if (activate_filter == XSANE_FILE_FILTER_ALL) + { + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter); + } + } + + if (enable_filters & XSANE_FILE_FILTER_DRC) /* filter: device rc */ + { + GtkFileFilter *filter; + + filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*.[dD][rR][cC]"); + + gtk_file_filter_set_name(filter, FILE_FILTER_DRC); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter); + + if (activate_filter == XSANE_FILE_FILTER_DRC) + { + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter); + } + + /* add path to filechooser */ + if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL) + { + gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)), NULL); + } + } + + if (enable_filters & XSANE_FILE_FILTER_ICM) /* filter: color management profiles */ + { + GtkFileFilter *filter; + + filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*.[iI][cC][cCmM]"); + + gtk_file_filter_set_name(filter, FILE_FILTER_ICM); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter); + + if (activate_filter == XSANE_FILE_FILTER_ICM) + { + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter); + } + + /* add path to filechooser */ + if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL) + { + snprintf(buf, sizeof(buf)-2, "%s%c.color%cicc", getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)), SLASH, SLASH); + gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), buf, NULL); + } + gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), "/usr/share/color/icc", NULL); + } + + if (enable_filters & XSANE_FILE_FILTER_IMAGES) /* filter: images */ + { + GtkFileFilter *filter; + + filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*.[jJ][pP][gG]"); + gtk_file_filter_add_pattern(filter, "*.[jJ][pP][eE][gG]"); + gtk_file_filter_add_pattern(filter, "*.[pP][nN][gG]"); + gtk_file_filter_add_pattern(filter, "*.[tT][iI][fF]"); + gtk_file_filter_add_pattern(filter, "*.[tT][iI][fF][fF]"); + gtk_file_filter_add_pattern(filter, "*.[pP][sS]"); + gtk_file_filter_add_pattern(filter, "*.[pP][dD][fF]"); + gtk_file_filter_add_pattern(filter, "*.[pP][nN][mM]"); + gtk_file_filter_add_pattern(filter, "*.[pP][bB][mM]"); + gtk_file_filter_add_pattern(filter, "*.[pP][gG][mM]"); + gtk_file_filter_add_pattern(filter, "*.[pP][pP][mM]"); + + gtk_file_filter_set_name(filter, FILE_FILTER_IMAGES); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter); + + if (activate_filter == XSANE_FILE_FILTER_IMAGES) + { + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter); + } + } + + if (enable_filters & XSANE_FILE_FILTER_BATCHLIST) /* filter: color management profiles */ + { + GtkFileFilter *filter; + + filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*.[xX][bV][lL]"); + + gtk_file_filter_set_name(filter, FILE_FILTER_XBL); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter); + + if (activate_filter == XSANE_FILE_FILTER_BATCHLIST) + { + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter); + } + } + + /* set default filename */ + if (default_name) /* select file */ + { + const char *basename = default_name; + char *path; + int pos; + + DBG(DBG_info, "xsane_back_gtk_get_filename: default_name =%s\n", default_name); + + path = strdup(default_name); + for (pos = strlen(path)-1; pos > 0; pos--) + { + if (path[pos] == '/') + { + path[pos]=0; + + basename = path+pos+1; + break; + } + } + + if (pos) + { + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), path); + } + + if ((action == XSANE_FILE_CHOOSER_ACTION_SAVE) || (action == XSANE_FILE_CHOOSER_ACTION_SELECT_SAVE)) + { + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filechooser), (char *) basename); + } + else + { + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(filechooser), (char *) default_name); + } + } + + + /* add filetype menu */ + + if (show_extra_widgets) + { + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *label; + + vbox = gtk_vbox_new(FALSE, 15); + gtk_widget_show(vbox); + + if (show_extra_widgets & XSANE_GET_FILENAME_SHOW_FILETYPE) + { + DBG(DBG_info, "xsane_back_gtk_get_filename: showing filetype menu\n"); + + if (filechooser_filetype) + { + free(filechooser_filetype); + } + + if ((filetype) && (*filetype)) + { + filechooser_filetype = strdup(*filetype); + } + else + { + filechooser_filetype = NULL; + } + + hbox = gtk_hbox_new(FALSE, 2); + gtk_widget_show(hbox); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new(TEXT_FILETYPE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + xsane_filetype_option_menu = xsane_back_gtk_filetype_menu_new(filechooser_filetype, (GtkSignalFunc) xsane_back_gtk_filetype2_callback); + gtk_box_pack_start(GTK_BOX(hbox), xsane_filetype_option_menu, TRUE, TRUE, 2); + gtk_widget_show(xsane_filetype_option_menu); + } + +#ifdef HAVE_LIBLCMS + if ((cms_function) && (show_extra_widgets & XSANE_GET_FILENAME_SHOW_CMS_FUNCTION)) + { + hbox = gtk_hbox_new(FALSE, 2); + gtk_widget_show(hbox); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new(TEXT_CMS_FUNCTION); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + xsane_cms_function_option_menu = xsane_back_gtk_cms_function_menu_new(*cms_function, NULL); + gtk_box_pack_start(GTK_BOX(hbox), xsane_cms_function_option_menu, TRUE, TRUE, 2); + gtk_widget_show(xsane_cms_function_option_menu); + } +#endif + + gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(filechooser), vbox); + } + + + gtk_widget_show(filechooser); + + result = gtk_dialog_run(GTK_DIALOG(filechooser)); + + DBG(DBG_info, "xsane_back_gtk_get_filename: gtk_dialog_run() returned with result=%d\n", result); + + if (result == accept_code) + { + char *chooser_filename; + + if ((filetype) && (*filetype)) + { + free(*filetype); + *filetype = NULL; + } + + if (filechooser_filetype) + { + if (filetype) + { + *filetype = strdup(filechooser_filetype); + } + } + +#ifdef HAVE_LIBLCMS + if ((cms_function) && (show_extra_widgets & XSANE_GET_FILENAME_SHOW_CMS_FUNCTION)) + { + *cms_function = gtk_option_menu_get_history(GTK_OPTION_MENU(xsane_cms_function_option_menu)); + + DBG(DBG_info, "selected cms_function = %d\n", *cms_function); + } +#endif + + chooser_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser)); + strncpy(filename, chooser_filename, max_len - 1); + g_free(chooser_filename); + + filename[max_len - 1] = '\0'; + + ok = TRUE; + } + + gtk_widget_destroy(filechooser); + filechooser = NULL; + + return ok ? 0 : -1; +} + +#else + +GtkWidget *fileselection; +char *fileselection_filetype = NULL; + +/* ----------------------------------------------------------------------------------------------------------------- */ + static void xsane_back_gtk_get_filename_button_clicked(GtkWidget *w, gpointer data) { int *clicked = data; @@ -1122,12 +1539,73 @@ static void xsane_back_gtk_get_filename_button_clicked(GtkWidget *w, gpointer da /* ----------------------------------------------------------------------------------------------------------------- */ -int xsane_back_gtk_get_filename(const char *label, const char *default_name, size_t max_len, char *filename, char **filetype, - int show_fileopts, int shorten_path, int select_directory, int show_filetype_menu) +static void xsane_back_gtk_filetype_callback(GtkWidget *widget, gpointer data) +{ + char *extension, *filename; + char buffer[PATH_MAX]; + char *new_filetype = (char *) data; + + DBG(DBG_proc, "xsane_filetype_callback\n"); + + filename = strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection))); + + if ((new_filetype) && (*new_filetype)) + { + extension = strrchr(filename, '.'); + + if ((extension) && (extension != filename)) + { + if ( (!strcasecmp(extension, ".pnm")) || (!strcasecmp(extension, ".raw")) + || (!strcasecmp(extension, ".png")) || (!strcasecmp(extension, ".ps")) + || (!strcasecmp(extension, ".pdf")) || (!strcasecmp(extension, ".rgba")) + || (!strcasecmp(extension, ".tiff")) || (!strcasecmp(extension, ".tif")) + || (!strcasecmp(extension, ".text")) || (!strcasecmp(extension, ".txt")) + || (!strcasecmp(extension, ".jpg")) || (!strcasecmp(extension, ".jpeg")) + ) /* remove filetype extension */ + { + *extension = 0; /* remove extension */ + } + } + snprintf(buffer, sizeof(buffer), "%s%s", filename, new_filetype); + free(filename); + filename = strdup(buffer); + } + + if (fileselection_filetype) + { + free(fileselection_filetype); + fileselection_filetype = NULL; + } + + if (data) + { + fileselection_filetype = strdup(new_filetype); + } + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection), filename); + + free(filename); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +int xsane_back_gtk_get_filename(const char *label, const char *default_name, size_t max_len, char *filename, char **filetype, int *cms_function, + XsaneFileChooserAction action, int show_filetype_menu, int enable_filters, int activate_filter) { int cancel = 0, ok = 0, destroy = 0; GtkAccelGroup *accelerator_group; GtkWidget *xsane_filetype_option_menu; + int show_fileopts = 0; + int select_directory = 0; + + if (action == XSANE_FILE_CHOOSER_ACTION_SELECT_FOLDER) + { + select_directory = TRUE; + } + else + { + show_fileopts = TRUE; + } DBG(DBG_proc, "xsane_back_gtk_get_filename\n"); @@ -1277,11 +1755,6 @@ int xsane_back_gtk_get_filename(const char *label, const char *default_name, siz cwd[cwd_len] = '\0'; DBG(DBG_info, "xsane_back_gtk_get_filename: full path filename = %s\n", filename); - if (shorten_path && (strncmp(filename, cwd, cwd_len) == 0)) - { - memcpy(filename, filename + cwd_len, len - cwd_len + 1); - DBG(DBG_info, "xsane_back_gtk_get_filename: short path filename = %s\n", filename); - } } if (!destroy) @@ -1293,6 +1766,7 @@ int xsane_back_gtk_get_filename(const char *label, const char *default_name, siz return ok ? 0 : -1; } +#endif /* ----------------------------------------------------------------------------------------------------------------- */ diff --git a/src/xsane-back-gtk.h b/src/xsane-back-gtk.h index 584e6d5..a1a49bf 100644 --- a/src/xsane-back-gtk.h +++ b/src/xsane-back-gtk.h @@ -3,7 +3,7 @@ xsane-back-gtk.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -43,6 +43,30 @@ CornerCoordinates; /* ---------------------------------------------------------------------------------------------------------------------- */ +#define XSANE_FILE_FILTER_ALL 1 +#define XSANE_FILE_FILTER_IMAGES 2 +#define XSANE_FILE_FILTER_DRC 4 +#define XSANE_FILE_FILTER_BATCHLIST 8 +#define XSANE_FILE_FILTER_ICM 16 + +#define XSANE_GET_FILENAME_SHOW_NOTHING 0 +#define XSANE_GET_FILENAME_SHOW_FILETYPE 1 +#define XSANE_GET_FILENAME_SHOW_CMS_FUNCTION 2 + + +typedef enum + { + XSANE_FILE_CHOOSER_ACTION_OPEN = 1, + XSANE_FILE_CHOOSER_ACTION_SELECT_OPEN, + XSANE_FILE_CHOOSER_ACTION_SAVE, + XSANE_FILE_CHOOSER_ACTION_SELECT_SAVE, + XSANE_FILE_CHOOSER_ACTION_SELECT_FOLDER, + XSANE_FILE_CHOOSER_ACTION_SELECT_PROJECT + } +XsaneFileChooserAction; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + extern int xsane_back_gtk_message_dialog_active; /* ---------------------------------------------------------------------------------------------------------------------- */ @@ -63,8 +87,9 @@ extern void xsane_back_gtk_warning(gchar *warning_message, int wait); extern void xsane_back_gtk_info(gchar *info_message, int wait); extern void xsane_back_gtk_filetype_menu_set_history(GtkWidget *xsane_filetype_option_menu, char *filetype); extern GtkWidget *xsane_back_gtk_filetype_menu_new(char *filetype, GtkSignalFunc filetype_callback); -extern int xsane_back_gtk_get_filename(const char *label, const char *default_name, size_t max_len, char *filename, char **filetype, - int show_fileopts, int shorten_path, int hide_file_list, int show_filetype_menu); +extern GtkWidget *xsane_back_gtk_cms_function_menu_new(int cms_select_function, GtkSignalFunc cms_function_menu_callback); +extern int xsane_back_gtk_get_filename(const char *label, const char *default_name, size_t max_len, char *filename, char **filetype, int *cms_function, + XsaneFileChooserAction action, int show_filetype_menu, int enable_filters, int activate_filter); extern void xsane_back_gtk_update_vector(int opt_num, SANE_Int *vector); extern void xsane_back_gtk_refresh_dialog(void); diff --git a/src/xsane-batch-scan.c b/src/xsane-batch-scan.c index 604e052..ff07e0c 100644 --- a/src/xsane-batch-scan.c +++ b/src/xsane-batch-scan.c @@ -3,7 +3,7 @@ xsane-batch-scan.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -345,7 +345,7 @@ static void xsane_batch_scan_load_list(void) sprintf(windowname, "%s %s %s", xsane.prog_name, WINDOW_LOAD_BATCH_LIST, xsane.device_text); xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", "batch-lists", 0, "default", ".xbl", XSANE_PATH_LOCAL_SANE); - if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, FALSE, FALSE, FALSE, FALSE)) + if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_OPEN, XSANE_GET_FILENAME_SHOW_NOTHING, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_BATCHLIST, XSANE_FILE_FILTER_BATCHLIST)) { if (xsane_batch_scan_load_list_from_file(filename)) /* error while loading file ? */ { @@ -396,7 +396,7 @@ static void xsane_batch_scan_save_list(void) sprintf(windowname, "%s %s %s", xsane.prog_name, WINDOW_SAVE_BATCH_LIST, xsane.device_text); xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", "batch-lists", 0, "default", ".xbl", XSANE_PATH_LOCAL_SANE); - if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, FALSE, FALSE, FALSE, FALSE)) + if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SAVE, XSANE_GET_FILENAME_SHOW_NOTHING, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_BATCHLIST, XSANE_FILE_FILTER_BATCHLIST)); { fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); @@ -893,27 +893,29 @@ static void xsane_batch_scan_rename_callback(GtkWidget *widget, gpointer data) gtk_box_pack_start(GTK_BOX(vbox), text, TRUE, TRUE, 4); gtk_widget_show(text); + #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_OK); + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); #else - button = gtk_button_new_with_label(BUTTON_OK); + button = gtk_button_new_with_label(BUTTON_CANCEL); #endif - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_batch_scan_rename_button_callback, (void *) 1); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_batch_scan_rename_button_callback, (void *) -1); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); - gtk_widget_grab_default(button); gtk_widget_show(button); #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + button = gtk_button_new_from_stock(GTK_STOCK_OK); #else - button = gtk_button_new_with_label(BUTTON_CANCEL); + button = gtk_button_new_with_label(BUTTON_OK); #endif - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_batch_scan_rename_button_callback, (void *) -1); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_batch_scan_rename_button_callback, (void *) 1); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_grab_default(button); gtk_widget_show(button); + xsane_batch_scan_rename = 0; while (xsane_batch_scan_rename == 0) diff --git a/src/xsane-batch-scan.h b/src/xsane-batch-scan.h index 03b018d..82aad85 100644 --- a/src/xsane-batch-scan.h +++ b/src/xsane-batch-scan.h @@ -3,7 +3,7 @@ xsane-batch-scan.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-device-preferences.c b/src/xsane-device-preferences.c index 003cb77..41293e6 100644 --- a/src/xsane-device-preferences.c +++ b/src/xsane-device-preferences.c @@ -3,7 +3,7 @@ xsane-device-preferences.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -102,6 +102,10 @@ desc_xsane_device[] = {"xsane-enhancement-rgb-default", xsane_rc_pref_int, DPOFFSET(enhancement_rgb_default)}, {"xsane-negative", xsane_rc_pref_int, DPOFFSET(negative)}, {"xsane-show-preview", xsane_rc_pref_int, DPOFFSET(show_preview)}, + + {"xsane-enable-color-management", xsane_rc_pref_int, DPOFFSET(enable_color_management)}, + {"xsane-scanner-default-color-icm-profile", xsane_rc_pref_string, DPOFFSET(scanner_default_color_icm_profile)}, + {"xsane-scanner-default-gray-icm-profile", xsane_rc_pref_string, DPOFFSET(scanner_default_gray_icm_profile)}, }; /* ---------------------------------------------------------------------------------------------------------------- */ @@ -109,7 +113,7 @@ desc_xsane_device[] = static int xsane_device_preferences_load_values(Wire *w, SANE_Handle device) { const SANE_Option_Descriptor *opt; - SANE_Word *word_array; + char *word_array; SANE_String name, str; u_long *caused_reload; SANE_Int num_options; @@ -193,12 +197,12 @@ static int xsane_device_preferences_load_values(Wire *w, SANE_Handle device) } else /* array */ { - SANE_Int len; + SANE_Int len; - xsane_rc_io_w_array(w, &len, (void **) &word_array, (WireCodecFunc) xsane_rc_io_w_word, sizeof(SANE_Word)); + xsane_rc_io_w_array(w, &len, &word_array, (WireCodecFunc) xsane_rc_io_w_word, sizeof(SANE_Word)); status = xsane_control_option(device, i, SANE_ACTION_SET_VALUE, word_array, &info); w->direction = WIRE_FREE; - xsane_rc_io_w_array(w, &len, (void **) &word_array, (WireCodecFunc) xsane_rc_io_w_word, sizeof(SANE_Word)); + xsane_rc_io_w_array(w, &len, &word_array, (WireCodecFunc) xsane_rc_io_w_word, sizeof(SANE_Word)); w->direction = WIRE_DECODE; } break; @@ -239,7 +243,7 @@ static int xsane_device_preferences_save_values(Wire *w, SANE_Handle device) { const SANE_Option_Descriptor *opt; size_t word_array_size = 0; - SANE_Word *word_array = 0; + char *word_array = 0; size_t str_size = 0; SANE_String str = 0; SANE_Word word; @@ -308,7 +312,7 @@ static int xsane_device_preferences_save_values(Wire *w, SANE_Handle device) } xsane_rc_io_w_string(w, (SANE_String *) &opt->name); - xsane_rc_io_w_array(w, &len, (void **) &word_array, (WireCodecFunc) xsane_rc_io_w_word, sizeof(SANE_Word)); + xsane_rc_io_w_array(w, &len, &word_array, (WireCodecFunc) xsane_rc_io_w_word, sizeof(SANE_Word)); } break; @@ -580,6 +584,10 @@ void xsane_device_preferences_load_file(char *filename) gtk_window_set_default_size(GTK_WINDOW(xsane.preview->top), xsane.preview_dialog_width, xsane.preview_dialog_height); #endif +#ifdef HAVE_LIBLCMS + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.enable_color_management_widget), xsane.enable_color_management); +#endif + xsane_update_param(0); xsane_refresh_dialog(); xsane_enhancement_by_gamma(); @@ -621,7 +629,7 @@ void xsane_device_preferences_load(void) sprintf(windowname, "%s %s %s", xsane.prog_name, WINDOW_LOAD_SETTINGS, xsane.device_text); xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, 0, xsane.device_set_filename, ".drc", XSANE_PATH_LOCAL_SANE); - if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, FALSE, FALSE, FALSE, FALSE)) + if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_OPEN, FALSE, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_DRC, XSANE_FILE_FILTER_DRC)) { xsane_device_preferences_load_file(filename); } @@ -772,7 +780,7 @@ void xsane_device_preferences_save(void) sprintf(windowname, "%s %s %s", xsane.prog_name, WINDOW_SAVE_SETTINGS, xsane.device_text); xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, 0, xsane.device_set_filename, ".drc", XSANE_PATH_LOCAL_SANE); - if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, FALSE, FALSE, FALSE, FALSE)) + if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SAVE, FALSE, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_DRC, XSANE_FILE_FILTER_DRC)) { xsane_device_preferences_save_file(filename); } diff --git a/src/xsane-device-preferences.h b/src/xsane-device-preferences.h index e980d47..ab705c0 100644 --- a/src/xsane-device-preferences.h +++ b/src/xsane-device-preferences.h @@ -3,7 +3,7 @@ xsane-device-preferences.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-email-project.c b/src/xsane-email-project.c index 79df15b..b36dd59 100644 --- a/src/xsane-email-project.c +++ b/src/xsane-email-project.c @@ -3,7 +3,7 @@ xsane-email-project.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -64,6 +64,7 @@ static gint xsane_email_dialog_delete(); static void xsane_email_filetype_callback(GtkWidget *filetype_option_menu, char *filetype); static void xsane_email_receiver_changed_callback(GtkWidget *widget, gpointer data); static void xsane_email_subject_changed_callback(GtkWidget *widget, gpointer data); +static void xsane_email_project_browse_filename_callback(GtkWidget *widget, gpointer data); static void xsane_email_project_changed_callback(GtkWidget *widget, gpointer data); static void xsane_email_html_mode_callback(GtkWidget *widget); static void xsane_email_project_display_status(void); @@ -150,10 +151,14 @@ void xsane_email_dialog() gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); gtk_box_pack_start(GTK_BOX(email_scan_vbox), hbox, FALSE, FALSE, 1); +#if 0 pixmap = gdk_pixmap_create_from_xpm_d(xsane.dialog->window, &mask, xsane.bg_trans, (gchar **) email_xpm); pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask); gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); gdk_drawable_unref(pixmap); +#endif + button = xsane_button_new_with_pixmap(xsane.dialog->window, hbox, email_xpm, DESC_EMAIL_PROJECT_BROWSE, + (GtkSignalFunc) xsane_email_project_browse_filename_callback, NULL); text = gtk_entry_new(); xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_EMAIL_PROJECT); @@ -165,7 +170,7 @@ void xsane_email_dialog() xsane.project_entry = text; xsane.project_entry_box = hbox; - gtk_widget_show(pixmapwidget); +// gtk_widget_show(pixmapwidget); gtk_widget_show(text); gtk_widget_show(hbox); @@ -1073,6 +1078,64 @@ static void xsane_email_subject_changed_callback(GtkWidget *widget, gpointer dat /* ---------------------------------------------------------------------------------------------------------------------- */ +void xsane_email_project_set_filename(gchar *filename) +{ + g_signal_handlers_block_by_func(GTK_OBJECT(xsane.project_entry), (GtkSignalFunc) xsane_email_project_changed_callback, NULL); + gtk_entry_set_text(GTK_ENTRY(xsane.project_entry), (char *) filename); /* update filename in entry */ + gtk_entry_set_position(GTK_ENTRY(xsane.project_entry), strlen(filename)); /* set cursor to right position of filename */ + + g_signal_handlers_unblock_by_func(GTK_OBJECT(xsane.project_entry), (GtkSignalFunc) xsane_email_project_changed_callback, NULL); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_email_project_browse_filename_callback(GtkWidget *widget, gpointer data) +{ + char filename[PATH_MAX]; + char windowname[TEXTBUFSIZE]; + + DBG(DBG_proc, "xsane_email_project_browse_filename_callback\n"); + + xsane_set_sensitivity(FALSE); + + if (preferences.email_project) /* make sure a correct filename is defined */ + { + strncpy(filename, preferences.email_project, sizeof(filename)); + filename[sizeof(filename) - 1] = '\0'; + } + else /* no filename given, take standard filename */ + { + strcpy(filename, OUT_FILENAME); + } + + snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_EMAIL_PROJECT_BROWSE, xsane.device_text); + + umask((mode_t) preferences.directory_umask); /* define new file permissions */ + if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_PROJECT, XSANE_GET_FILENAME_SHOW_NOTHING, 0, 0)) + { + + if (preferences.email_project) + { + free((void *) preferences.email_project); + } + + preferences.email_project = strdup(filename); + + xsane_set_sensitivity(TRUE); + xsane_email_project_set_filename(filename); + + xsane_email_project_load(); + } + else + { + xsane_set_sensitivity(TRUE); + } + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + static void xsane_email_project_changed_callback(GtkWidget *widget, gpointer data) { DBG(DBG_proc, "xsane_email_project_changed_callback\n"); @@ -1277,20 +1340,20 @@ static void xsane_email_entry_rename_callback(GtkWidget *widget, gpointer list) #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_OK); + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); #else - button = gtk_button_new_with_label(BUTTON_OK); + button = gtk_button_new_with_label(BUTTON_CANCEL); #endif - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_email_entry_rename_button_callback, (void *) 1); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_email_entry_rename_button_callback,(void *) -1); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); gtk_widget_show(button); #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + button = gtk_button_new_from_stock(GTK_STOCK_OK); #else - button = gtk_button_new_with_label(BUTTON_CANCEL); + button = gtk_button_new_with_label(BUTTON_OK); #endif - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_email_entry_rename_button_callback,(void *) -1); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_email_entry_rename_button_callback, (void *) 1); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); gtk_widget_show(button); @@ -1595,7 +1658,7 @@ static void xsane_create_email(int fd) /* doc files like ps and pdf can not be displayed inline in html email */ if (display_images_inline) { - snprintf(buf, sizeof(buf), "<p><img SRC=\"cid:%s\">\n", content_id); + snprintf(buf, sizeof(buf), "<p><img SRC=\"cid:%s\">\r\n", content_id); } write(fd, buf, strlen(buf)); } @@ -1605,7 +1668,7 @@ static void xsane_create_email(int fd) } else if (*email_text_pos == 10) /* new line */ { - snprintf(buf, sizeof(buf), "<br>\n"); + snprintf(buf, sizeof(buf), "<br>\r\n"); write(fd, buf, strlen(buf)); } else @@ -1624,12 +1687,12 @@ static void xsane_create_email(int fd) /* doc files like ps and pdf can not be displayed inline in html email */ if (display_images_inline) { - snprintf(buf, sizeof(buf), "<p><img SRC=\"cid:%s\">\n", content_id); + snprintf(buf, sizeof(buf), "<p><img SRC=\"cid:%s\">\r\n", content_id); } write(fd, buf, strlen(buf)); } - snprintf(buf, sizeof(buf), "</html>\n"); + snprintf(buf, sizeof(buf), "</html>\r\n"); write(fd, buf, strlen(buf)); @@ -1666,7 +1729,7 @@ static void xsane_create_email(int fd) write_email_mime_ascii(fd, boundary); write(fd, email_text, strlen(email_text)); - write(fd, "\n\n", 2); + write(fd, "\r\n\r\n", 4); for (i=0; i<attachments; i++) { @@ -1856,7 +1919,7 @@ static void xsane_email_send() free(type); DBG(DBG_info, "converting %s to %s\n", source_filename, email_filename); output_format = xsane_identify_output_format(email_filename, NULL, NULL); - xsane_save_image_as(email_filename, source_filename, output_format, xsane.project_progress_bar, &cancel_save); + xsane_save_image_as(email_filename, source_filename, output_format, xsane.enable_color_management, preferences.cms_function, preferences.cms_intent, preferences.cms_bpc, xsane.project_progress_bar, &cancel_save); list = list->next; xsane.email_progress_size += xsane_get_filesize(email_filename); } diff --git a/src/xsane-email-project.h b/src/xsane-email-project.h index 2148ef2..8bc44b8 100644 --- a/src/xsane-email-project.h +++ b/src/xsane-email-project.h @@ -3,7 +3,7 @@ xsane-email-project.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-fax-project.c b/src/xsane-fax-project.c index 8f23bf2..4b7b770 100644 --- a/src/xsane-fax-project.c +++ b/src/xsane-fax-project.c @@ -3,7 +3,7 @@ xsane-fax-project.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -57,6 +57,7 @@ void xsane_fax_dialog(void); void xsane_fax_project_save(void); static gint xsane_fax_dialog_delete(); +static void xsane_fax_project_browse_filename_callback(GtkWidget *widget, gpointer data); static void xsane_fax_receiver_changed_callback(GtkWidget *widget, gpointer data); static void xsane_fax_project_changed_callback(GtkWidget *widget, gpointer data); static void xsane_fax_fine_mode_callback(GtkWidget *widget); @@ -86,8 +87,9 @@ void xsane_fax_dialog() GtkWidget *fax_dialog, *fax_scan_vbox, *fax_project_vbox, *hbox, *fax_project_exists_hbox, *button; GtkWidget *scrolled_window, *list; char buf[64]; - GtkWidget *pixmapwidget, *text; + GtkWidget *text; GtkWidget *pages_frame; + GtkWidget *pixmapwidget; GdkBitmap *mask; GdkPixmap *pixmap; @@ -119,10 +121,8 @@ void xsane_fax_dialog() gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); gtk_box_pack_start(GTK_BOX(fax_scan_vbox), hbox, FALSE, FALSE, 1); - pixmap = gdk_pixmap_create_from_xpm_d(xsane.dialog->window, &mask, xsane.bg_trans, (gchar **) fax_xpm); - pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask); - gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); - gdk_drawable_unref(pixmap); + button = xsane_button_new_with_pixmap(xsane.dialog->window, hbox, fax_xpm, DESC_FAX_PROJECT_BROWSE, + (GtkSignalFunc) xsane_fax_project_browse_filename_callback, NULL); text = gtk_entry_new(); xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_FAXPROJECT); @@ -134,7 +134,6 @@ void xsane_fax_dialog() xsane.project_entry = text; xsane.project_entry_box = hbox; - gtk_widget_show(pixmapwidget); gtk_widget_show(text); gtk_widget_show(hbox); @@ -582,6 +581,64 @@ static void xsane_fax_receiver_changed_callback(GtkWidget *widget, gpointer data gtk_progress_bar_update(GTK_PROGRESS_BAR(xsane.project_progress_bar), 0.0); } +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_fax_project_set_filename(gchar *filename) +{ + g_signal_handlers_block_by_func(GTK_OBJECT(xsane.project_entry), (GtkSignalFunc) xsane_fax_project_changed_callback, NULL); + gtk_entry_set_text(GTK_ENTRY(xsane.project_entry), (char *) filename); /* update filename in entry */ + gtk_entry_set_position(GTK_ENTRY(xsane.project_entry), strlen(filename)); /* set cursor to right position of filename */ + + g_signal_handlers_unblock_by_func(GTK_OBJECT(xsane.project_entry), (GtkSignalFunc) xsane_fax_project_changed_callback, NULL); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_project_browse_filename_callback(GtkWidget *widget, gpointer data) +{ + char filename[PATH_MAX]; + char windowname[TEXTBUFSIZE]; + + DBG(DBG_proc, "xsane_fax_project_browse_filename_callback\n"); + + xsane_set_sensitivity(FALSE); + + if (preferences.fax_project) /* make sure a correct filename is defined */ + { + strncpy(filename, preferences.fax_project, sizeof(filename)); + filename[sizeof(filename) - 1] = '\0'; + } + else /* no filename given, take standard filename */ + { + strcpy(filename, OUT_FILENAME); + } + + snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_FAX_PROJECT_BROWSE, xsane.device_text); + + umask((mode_t) preferences.directory_umask); /* define new file permissions */ + if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_PROJECT, FALSE, 0, 0)) + { + + if (preferences.fax_project) + { + free((void *) preferences.fax_project); + } + + preferences.fax_project = strdup(filename); + + xsane_set_sensitivity(TRUE); + xsane_fax_project_set_filename(filename); + + xsane_fax_project_load(); + } + else + { + xsane_set_sensitivity(TRUE); + } + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + +} + /* ---------------------------------------------------------------------------------------------------------------------- */ static void xsane_fax_project_changed_callback(GtkWidget *widget, gpointer data) @@ -761,20 +818,21 @@ static void xsane_fax_entry_rename_callback(GtkWidget *widget, gpointer list) #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_OK); + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); #else - button = gtk_button_new_with_label(BUTTON_OK); + button = gtk_button_new_with_label(BUTTON_CANCEL); #endif - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_entry_rename_button_callback, (void *) 1); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_entry_rename_button_callback, (void *) -1); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); gtk_widget_show(button); + #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + button = gtk_button_new_from_stock(GTK_STOCK_OK); #else - button = gtk_button_new_with_label(BUTTON_CANCEL); + button = gtk_button_new_with_label(BUTTON_OK); #endif - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_entry_rename_button_callback, (void *) -1); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_entry_rename_button_callback, (void *) 1); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); gtk_widget_show(button); @@ -833,7 +891,7 @@ static void xsane_fax_entry_insert_callback(GtkWidget *widget, gpointer list) umask((mode_t) preferences.directory_umask); /* define new file permissions */ - if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, TRUE, FALSE, FALSE, FALSE)) /* filename is selected */ + if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_OPEN, FALSE, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_IMAGES, XSANE_FILE_FILTER_IMAGES)) /* filename is selected */ { FILE *sourcefile; @@ -1082,7 +1140,12 @@ static int xsane_fax_convert_pnm_to_ps(char *source_filename, char *fax_filename preferences.fax_width * 72.0/MM_PER_INCH, /* paper_width */ preferences.fax_height * 72.0/MM_PER_INCH, /* paper_height */ 0 /* portrait top left */, - preferences.fax_ps_flatdecoded, /* use ps level 3 zlib compression */ + preferences.fax_ps_flatedecoded, /* use ps level 3 zlib compression */ + NULL, /* hTransform */ + 0 /* do not apply ICM profile */, + 0, NULL, /* no CSA */ + 0, NULL, 0, /* no CRD */ + 0, /* intent */ xsane.project_progress_bar, &cancel_save); fclose(outfile); diff --git a/src/xsane-fax-project.h b/src/xsane-fax-project.h index 775aafc..cca541e 100644 --- a/src/xsane-fax-project.h +++ b/src/xsane-fax-project.h @@ -3,7 +3,7 @@ xsane-fax-project.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-fixedtext.h b/src/xsane-fixedtext.h index d655d34..d207450 100644 --- a/src/xsane-fixedtext.h +++ b/src/xsane-fixedtext.h @@ -3,7 +3,7 @@ xsane-fixedtext.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-front-gtk.c b/src/xsane-front-gtk.c index a11779e..3d98a5b 100644 --- a/src/xsane-front-gtk.c +++ b/src/xsane-front-gtk.c @@ -3,7 +3,7 @@ xsane-front-gtk.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -67,14 +67,14 @@ void xsane_option_menu_new(GtkWidget *parent, char *str_list[], const char *val, void *option_menu_callback, SANE_Int settable, const gchar *widget_name); void xsane_option_menu_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc, char *str_list[], const char *val, - GtkObject **data, int option, + GtkWidget **data, int option, void *option_menu_callback, SANE_Int settable, const gchar *widget_name); void xsane_range_new(GtkBox *parent, char *labeltext, const char *desc, float min, float max, float quant, float page_step, - int digits, double *val, GtkObject **data, void *xsane_range_callback, SANE_Int settable); + int digits, double *val, GtkWidget **data, void *xsane_range_callback, SANE_Int settable); void xsane_range_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc, float min, float max, float quant, float page_step, int digits, - double *val, GtkObject **data, int option, void *xsane_range_callback, SANE_Int settable); + double *val, GtkWidget **data, int option, void *xsane_range_callback, SANE_Int settable); static void xsane_outputfilename_changed_callback(GtkWidget *widget, gpointer data); void xsane_set_filename(gchar *filename); void xsane_separator_new(GtkWidget *xsane_parent, int dist); @@ -411,7 +411,7 @@ void xsane_define_maximum_output_size() if ( (opt) && (opt->unit== SANE_UNIT_MM) ) { - switch(preferences.xsane_mode) + switch(xsane.xsane_mode) { case XSANE_SAVE: @@ -662,6 +662,15 @@ gint xsane_authorization_callback(SANE_String_Const resource, gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 10); /* y-space around buttons */ #ifdef HAVE_GTK2 + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); +#else + button = gtk_button_new_with_label(BUTTON_CANCEL); +#endif + g_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(xsane_authorization_button_callback), (void *) -1); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 10); /* x-space around cancel-button */ + gtk_widget_show(button); + +#ifdef HAVE_GTK2 button = gtk_button_new_from_stock(GTK_STOCK_OK); #else button = gtk_button_new_with_label(BUTTON_OK); @@ -672,15 +681,6 @@ gint xsane_authorization_callback(SANE_String_Const resource, gtk_widget_grab_default(button); gtk_widget_show(button); -#ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); -#else - button = gtk_button_new_with_label(BUTTON_CANCEL); -#endif - g_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(xsane_authorization_button_callback), (void *) -1); - gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 10); /* x-space around cancel-button */ - gtk_widget_show(button); - gtk_widget_show(hbox); gtk_widget_show(authorize_dialog); @@ -1032,7 +1032,7 @@ void xsane_option_menu_new(GtkWidget *parent, char *str_list[], const char *val, void xsane_option_menu_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc, char *str_list[], const char *val, - GtkObject **data, int option, + GtkWidget **data, int option, void *option_menu_callback, SANE_Int settable, const gchar *widget_name) { GtkWidget *hbox; @@ -1071,7 +1071,7 @@ static void xsane_range_display_value_right_callback(GtkAdjustment *adjust, gpoi void xsane_range_new(GtkBox *parent, char *labeltext, const char *desc, float min, float max, float quant, float page_step, - int digits, double *val, GtkObject **data, void *xsane_range_callback, SANE_Int settable) + int digits, double *val, GtkWidget **data, void *xsane_range_callback, SANE_Int settable) { GtkWidget *hbox; GtkWidget *label; @@ -1087,7 +1087,7 @@ void xsane_range_new(GtkBox *parent, char *labeltext, const char *desc, label = gtk_label_new(labeltext); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 1); - *data = gtk_adjustment_new(*val, min, max, quant, page_step, (max-min) * 1e-30); + *data = (GtkWidget *) gtk_adjustment_new(*val, min, max, quant, page_step, (max-min) * 1e-30); /* 1e-30 => hscrollbar has an unwanted side effect: the maximum is not the maximum */ /* of the given range, it is reduced by the page_size, so it has to be very small */ @@ -1159,7 +1159,7 @@ void xsane_range_new(GtkBox *parent, char *labeltext, const char *desc, void xsane_range_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc, float min, float max, float quant, float page_step, - int digits, double *val, GtkObject **data, int option, void *xsane_range_callback, SANE_Int settable) + int digits, double *val, GtkWidget **data, int option, void *xsane_range_callback, SANE_Int settable) { GtkWidget *hbox; GtkWidget *slider = NULL; @@ -1180,7 +1180,7 @@ void xsane_range_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char * gtk_widget_show(pixmapwidget); gdk_drawable_unref(pixmap); - *data = gtk_adjustment_new(*val, min, max, quant, page_step, (max-min) * 1e-30); + *data = (GtkWidget *) gtk_adjustment_new(*val, min, max, quant, page_step, (max-min) * 1e-30); /* 1e-30 => hscrollbar has an unwanted side effect: the maximum is not the maximum */ /* of the given range, it is reduced by the page_size, so it has to be very small */ @@ -1251,7 +1251,7 @@ void xsane_range_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char * DialogElement *elem; elem=xsane.element + option; - elem->data = *data; + elem->data = (GtkObject *) *data; elem->widget = slider; } } @@ -1262,6 +1262,7 @@ static void xsane_browse_filename_callback(GtkWidget *widget, gpointer data) { char filename[PATH_MAX]; char windowname[TEXTBUFSIZE]; + int show_extra_widgets; DBG(DBG_proc, "xsane_browse_filename_callback\n"); @@ -1277,10 +1278,17 @@ static void xsane_browse_filename_callback(GtkWidget *widget, gpointer data) strcpy(filename, OUT_FILENAME); } + show_extra_widgets = XSANE_GET_FILENAME_SHOW_FILETYPE; + if (xsane.enable_color_management) + { + show_extra_widgets |= XSANE_GET_FILENAME_SHOW_CMS_FUNCTION; + } + + snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_OUTPUT_FILENAME, xsane.device_text); umask((mode_t) preferences.directory_umask); /* define new file permissions */ - xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, &preferences.filetype, TRUE, TRUE, FALSE, TRUE); + xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, &preferences.filetype, &preferences.cms_function, XSANE_FILE_CHOOSER_ACTION_SELECT_SAVE, show_extra_widgets, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_IMAGES, XSANE_FILE_FILTER_IMAGES); umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ if (preferences.filename) @@ -1294,6 +1302,10 @@ static void xsane_browse_filename_callback(GtkWidget *widget, gpointer data) xsane_back_gtk_filetype_menu_set_history(xsane.filetype_option_menu, preferences.filetype); +#ifdef HAVE_LIBLCMS + gtk_option_menu_set_history(GTK_OPTION_MENU(xsane.cms_function_option_menu), preferences.cms_function); +#endif + /* correct length of filename counter if it is shorter than minimum length */ xsane_update_counter_in_filename(&preferences.filename, FALSE, 0, preferences.filename_counter_len); @@ -1629,17 +1641,17 @@ void xsane_update_param(void *arg) if (xsane.param.format == SANE_FRAME_GRAY) { - xsane.xsane_colors = 1; + xsane.xsane_channels = 1; } #ifdef SUPPORT_RGBA else if (xsane.param.format == SANE_FRAME_RGBA) { - xsane.xsane_colors = 4; + xsane.xsane_channels = 4; } #endif else /* RGB */ { - xsane.xsane_colors = 3; + xsane.xsane_channels = 3; } } else @@ -1785,6 +1797,7 @@ int xsane_identify_output_format(char *filename, char *filetype, char **ext) /* ---------------------------------------------------------------------------------------------------------------------- */ +#if 0 void xsane_change_working_directory(void) { char filename[PATH_MAX]; @@ -1797,7 +1810,7 @@ void xsane_change_working_directory(void) sprintf(windowname, "%s %s %s", xsane.prog_name, WINDOW_CHANGE_WORKING_DIR, xsane.device_text); if (getcwd(filename, sizeof(filename))) { - xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, TRUE, FALSE, TRUE, FALSE); +// xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, TRUE, FALSE, TRUE, FALSE); if (chdir(filename)) { char buf[TEXTBUFSIZE]; @@ -1819,6 +1832,7 @@ void xsane_change_working_directory(void) xsane_set_sensitivity(TRUE); } +#endif /* ---------------------------------------------------------------------------------------------------------------------- */ @@ -2019,11 +2033,6 @@ int xsane_display_eula(int ask_for_accept) if (ask_for_accept) /* show accept + not accept buttons */ { - button = gtk_button_new_with_label(BUTTON_ACCEPT); - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_eula_button_callback, (void *) 0 /* accept */); - gtk_container_add(GTK_CONTAINER(hbox), button); - gtk_widget_show(button); - button = gtk_button_new_with_label(BUTTON_NOT_ACCEPT); gtk_widget_add_accelerator(button, "clicked", accelerator_group, GDK_Escape, 0, DEF_GTK_ACCEL_LOCKED); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); @@ -2031,6 +2040,11 @@ int xsane_display_eula(int ask_for_accept) gtk_container_add(GTK_CONTAINER(hbox), button); gtk_widget_grab_default(button); gtk_widget_show(button); + + button = gtk_button_new_with_label(BUTTON_ACCEPT); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_eula_button_callback, (void *) 0 /* accept */); + gtk_container_add(GTK_CONTAINER(hbox), button); + gtk_widget_show(button); } else /* show close button */ { @@ -2397,22 +2411,22 @@ int xsane_front_gtk_getname_dialog(const char *dialog_title, const char *desc_te gtk_window_add_accel_group(GTK_WINDOW(getname_dialog), accelerator_group); #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_OK); + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); #else - button = gtk_button_new_with_label(BUTTON_OK); + button = gtk_button_new_with_label(BUTTON_CANCEL); #endif - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_front_gtk_getname_button_callback, (void *) 1); - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_front_gtk_getname_button_callback, (void *) -1); + gtk_widget_add_accelerator(button, "clicked", accelerator_group, GDK_Escape, 0, DEF_GTK_ACCEL_LOCKED); /* ESC */ gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); gtk_widget_show(button); #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + button = gtk_button_new_from_stock(GTK_STOCK_OK); #else - button = gtk_button_new_with_label(BUTTON_CANCEL); + button = gtk_button_new_with_label(BUTTON_OK); #endif - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_front_gtk_getname_button_callback, (void *) -1); - gtk_widget_add_accelerator(button, "clicked", accelerator_group, GDK_Escape, 0, DEF_GTK_ACCEL_LOCKED); /* ESC */ + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_front_gtk_getname_button_callback, (void *) 1); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); gtk_widget_show(button); diff --git a/src/xsane-front-gtk.h b/src/xsane-front-gtk.h index 1db2b7b..b7752bf 100644 --- a/src/xsane-front-gtk.h +++ b/src/xsane-front-gtk.h @@ -3,7 +3,7 @@ xsane-front-gtk.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -57,14 +57,14 @@ extern void xsane_option_menu_new(GtkWidget *parent, char *str_list[], const cha void *option_menu_callback, SANE_Int settable, const gchar *widget_name); extern void xsane_option_menu_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc, char *str_list[], const char *val, - GtkObject **data, int option, + GtkWidget **data, int option, void *option_menu_callback, SANE_Int settable, const gchar *widget_name); extern void xsane_range_new(GtkBox *parent, char *labeltext, const char *desc, float min, float max, float quant, float page_step, - int digits, double *val, GtkObject **data, void *xsane_range_callback, SANE_Int settable); + int digits, double *val, GtkWidget **data, void *xsane_range_callback, SANE_Int settable); extern void xsane_range_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc, float min, float max, float quant, float page_step, int digits, - double *val, GtkObject **data, int option, void *xsane_range_callback, SANE_Int settable); + double *val, GtkWidget **data, int option, void *xsane_range_callback, SANE_Int settable); extern void xsane_set_filename(gchar *filename); extern void xsane_outputfilename_new(GtkWidget *vbox); extern void xsane_separator_new(GtkWidget *xsane_parent, int dist); diff --git a/src/xsane-gamma.c b/src/xsane-gamma.c index 40fe835..8304f07 100644 --- a/src/xsane-gamma.c +++ b/src/xsane-gamma.c @@ -3,7 +3,7 @@ xsane-gamma.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -132,7 +132,7 @@ static void xsane_draw_histogram_with_points(XsanePixmap *hist, { inten = show_inten * count[i] * scale; - if (xsane.xsane_colors > 1) + if (xsane.xsane_channels > 1) { red = show_red * count_red[i] * scale; green = show_green * count_green[i] * scale; @@ -208,7 +208,7 @@ static void xsane_draw_histogram_with_lines(XsanePixmap *hist, { inten = show_inten * count[i] * scale; - if (xsane.xsane_colors > 1) + if (xsane.xsane_channels > 1) { red = show_red * count_red[i] * scale; green = show_green * count_green[i] * scale; @@ -518,7 +518,7 @@ void xsane_update_sliders() xsane_update_slider(&xsane.slider_gray); - if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) ) + if ( (xsane.xsane_channels > 1) && (!xsane.enhancement_rgb_default) && (!xsane.enable_color_management)) { xsane_update_slider(&xsane.slider_red); xsane_update_slider(&xsane.slider_green); @@ -539,7 +539,7 @@ void xsane_update_sliders() xsane.slider_green.active = XSANE_SLIDER_INACTIVE; /* mark slider inactive */ xsane.slider_blue.active = XSANE_SLIDER_INACTIVE; /* mark slider inactive */ - if (xsane.param.depth == 1) + if ((xsane.param.depth == 1) || (xsane.enable_color_management)) { xsane_draw_slider_level(&xsane.slider_gray); /* remove slider */ xsane.slider_gray.active = XSANE_SLIDER_INACTIVE; /* mark slider inactive */ @@ -1599,7 +1599,7 @@ void xsane_update_gamma_curve(int update_raw) xsane.brightness + xsane.brightness_blue, xsane.contrast + xsane.contrast_blue , xsane.preview_gamma_size, 255); #else - if ( ( ( (xsane.xsane_colors > 1) && xsane.scanner_gamma_color ) || /* color scan and gamma table for red, green and blue available */ + if ( ( ( (xsane.xsane_channels > 1) && xsane.scanner_gamma_color ) || /* color scan and gamma table for red, green and blue available */ xsane.scanner_gamma_gray ) && /* grayscale scan and gamma table for gray available */ (!xsane.no_preview_medium_gamma) ) /* do not use gamma table when disabled */ { @@ -1663,7 +1663,7 @@ void xsane_update_gamma_curve(int update_raw) xsane.preview_gamma_size); } } - else if (xsane.xsane_colors > 1) /* color scan, no color scanner gamma tables available */ + else if (xsane.xsane_channels > 1) /* color scan, no color scanner gamma tables available */ { DBG(DBG_info, "creating preview gamma tables with medium correction\n"); @@ -1826,13 +1826,18 @@ static void xsane_enhancement_update(void) return; } + if (xsane.enable_color_management) /* color management? no gamma */ + { + return; + } + xsane.block_enhancement_update = TRUE; gtk_adjustment_set_value(GTK_ADJUSTMENT(xsane.gamma_widget), xsane.gamma); gtk_adjustment_set_value(GTK_ADJUSTMENT(xsane.brightness_widget), xsane.brightness); gtk_adjustment_set_value(GTK_ADJUSTMENT(xsane.contrast_widget), xsane.contrast); - if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) ) + if ( (xsane.xsane_channels > 1) && (!xsane.enhancement_rgb_default) ) { gtk_adjustment_set_value(GTK_ADJUSTMENT(xsane.gamma_red_widget), xsane.gamma_red); gtk_adjustment_set_value(GTK_ADJUSTMENT(xsane.brightness_red_widget), xsane.brightness_red); @@ -2107,7 +2112,7 @@ void xsane_enhancement_by_histogram(int update_gamma) xsane.contrast = gray_contrast; } - if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) ) /* rgb sliders active */ + if ( (xsane.xsane_channels > 1) && (!xsane.enhancement_rgb_default) ) /* rgb sliders active */ { if ((xsane.slider_gray.active == XSANE_SLIDER_ACTIVE) || (xsane.slider_gray.active == XSANE_SLIDER_INACTIVE)) /* gray slider not moved */ diff --git a/src/xsane-gamma.h b/src/xsane-gamma.h index e948a92..b40249f 100644 --- a/src/xsane-gamma.h +++ b/src/xsane-gamma.h @@ -3,7 +3,7 @@ xsane-gamma.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-gimp-1_0-compat.h b/src/xsane-gimp-1_0-compat.h index 1bdc758..141bd42 100644 --- a/src/xsane-gimp-1_0-compat.h +++ b/src/xsane-gimp-1_0-compat.h @@ -3,7 +3,7 @@ xsane-gimp-1_0-compat.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 2000-2005 Oliver Rauch + Copyright (C) 2000-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-gtk-1_x-compat.h b/src/xsane-gtk-1_x-compat.h index 1653c33..fea9c18 100644 --- a/src/xsane-gtk-1_x-compat.h +++ b/src/xsane-gtk-1_x-compat.h @@ -3,7 +3,7 @@ xsane-gtk-1_x-compat.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 2002-2005 Oliver Rauch + Copyright (C) 2002-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -64,5 +64,5 @@ gtk_window_set_policy(widget, FALSE, resizable, FALSE) # define gtk_image_new_from_pixmap(pixmap, mask) \ gtk_pixmap_new(pixmap, mask) - +# define gtk_progress_bar_set_ellipsize() /* empty */ #endif diff --git a/src/xsane-icons.c b/src/xsane-icons.c index f06e3cd..ba76144 100644 --- a/src/xsane-icons.c +++ b/src/xsane-icons.c @@ -3,7 +3,7 @@ xsane-icons.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -2910,6 +2910,42 @@ const char *resolution_y_xpm[] = /* --------------------------------------------------- */ +const char *cms_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 6 1", +/* colors */ +". c #000000", +" none", +"w c #ffffff", +"r c #ff0000", +"g c #00ff00", +"b c #0000ff", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" rrrr g g bbbb ", +"rrrrrr gg gg bbbbbb", +"rr r gggggg bb b", +"rr gggggg bb ", +"rr gg gg bbbbb ", +"rr gg gg bbbb ", +"rr gg gg bb", +"rr r gg gg b bb", +"rrrrrr gg gg bbbbbb", +" rrrr gg gg bbbb ", +" ", +" ", +" ", +" ", +}; + +/* --------------------------------------------------- */ + const char *scanner_xpm[] = { /* width height num_colors chars_per_pixel */ diff --git a/src/xsane-icons.h b/src/xsane-icons.h index 1e4e1a1..6f38cfb 100644 --- a/src/xsane-icons.h +++ b/src/xsane-icons.h @@ -3,7 +3,7 @@ xsane-icons.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -119,6 +119,7 @@ extern const char *zoom_y_xpm[]; extern const char *resolution_xpm[]; extern const char *resolution_x_xpm[]; extern const char *resolution_y_xpm[]; +extern const char *cms_xpm[]; extern const char *scanner_xpm[]; extern const char *intensity_xpm[]; extern const char *red_xpm[]; diff --git a/src/xsane-multipage-project.c b/src/xsane-multipage-project.c index 20a1cc3..3721faa 100644 --- a/src/xsane-multipage-project.c +++ b/src/xsane-multipage-project.c @@ -3,7 +3,7 @@ xsane-multipage-project.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 2005 Oliver Rauch + Copyright (C) 2005-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -55,6 +55,7 @@ void xsane_multipage_dialog_close(void); void xsane_multipage_project_save(void); static gint xsane_multipage_dialog_delete(); static void xsane_multipage_filetype_callback(GtkWidget *filetype_option_menu, char *filetype); +static void xsane_multipage_project_browse_filename_callback(GtkWidget *widget, gpointer data); static void xsane_multipage_project_changed_callback(GtkWidget *widget, gpointer data); static void xsane_multipage_project_load(void); static void xsane_multipage_project_delete(void); @@ -94,13 +95,11 @@ void xsane_multipage_dialog() GtkWidget *multipage_project_exists_hbox, *button; GtkWidget *hbox; GtkWidget *scrolled_window, *list; - GtkWidget *pixmapwidget, *text; + GtkWidget *text; GtkWidget *pages_frame; GtkWidget *label; GtkWidget *filetype_menu, *filetype_item; GtkWidget *filetype_option_menu; - GdkPixmap *pixmap; - GdkBitmap *mask; char buf[64]; int filetype_nr; int select_item; @@ -133,10 +132,8 @@ void xsane_multipage_dialog() gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); gtk_box_pack_start(GTK_BOX(multipage_scan_vbox), hbox, FALSE, FALSE, 1); - pixmap = gdk_pixmap_create_from_xpm_d(xsane.dialog->window, &mask, xsane.bg_trans, (gchar **) multipage_xpm); - pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask); - gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); - gdk_drawable_unref(pixmap); + button = xsane_button_new_with_pixmap(xsane.dialog->window, hbox, multipage_xpm, DESC_MULTIPAGE_PROJECT_BROWSE, + (GtkSignalFunc) xsane_multipage_project_browse_filename_callback, NULL); text = gtk_entry_new(); xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_MULTIPAGE_PROJECT); @@ -148,7 +145,6 @@ void xsane_multipage_dialog() xsane.project_entry = text; xsane.project_entry_box = hbox; - gtk_widget_show(pixmapwidget); gtk_widget_show(text); gtk_widget_show(hbox); @@ -579,6 +575,65 @@ static void xsane_multipage_project_create() /* ---------------------------------------------------------------------------------------------------------------------- */ +void xsane_multipage_project_set_filename(gchar *filename) +{ + g_signal_handlers_block_by_func(GTK_OBJECT(xsane.project_entry), (GtkSignalFunc) xsane_multipage_project_changed_callback, NULL); + gtk_entry_set_text(GTK_ENTRY(xsane.project_entry), (char *) filename); /* update filename in entry */ + gtk_entry_set_position(GTK_ENTRY(xsane.project_entry), strlen(filename)); /* set cursor to right position of filename */ + + g_signal_handlers_unblock_by_func(GTK_OBJECT(xsane.project_entry), (GtkSignalFunc) xsane_multipage_project_changed_callback, NULL); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_multipage_project_browse_filename_callback(GtkWidget *widget, gpointer data) +{ + char filename[PATH_MAX]; + char windowname[TEXTBUFSIZE]; + + DBG(DBG_proc, "xsane_multipage_project_browse_filename_callback\n"); + + xsane_set_sensitivity(FALSE); + + if (preferences.multipage_project) /* make sure a correct filename is defined */ + { + strncpy(filename, preferences.multipage_project, sizeof(filename)); + filename[sizeof(filename) - 1] = '\0'; + } + else /* no filename given, take standard filename */ + { + strcpy(filename, OUT_FILENAME); + } + + snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_MULTIPAGE_PROJECT_BROWSE, xsane.device_text); + + umask((mode_t) preferences.directory_umask); /* define new file permissions */ + if (!xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_PROJECT, XSANE_GET_FILENAME_SHOW_NOTHING, 0, 0)) + { + + if (preferences.multipage_project) + { + free((void *) preferences.multipage_project); + } + + preferences.multipage_project = strdup(filename); + + xsane_set_sensitivity(TRUE); + xsane_multipage_project_set_filename(filename); + + xsane_multipage_project_load(); + } + else + { + xsane_set_sensitivity(TRUE); + } + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + +} + + +/* ---------------------------------------------------------------------------------------------------------------------- */ + static void xsane_multipage_project_changed_callback(GtkWidget *widget, gpointer data) { DBG(DBG_proc, "xsane_multipage_project_changed_callback\n"); @@ -913,11 +968,11 @@ static void xsane_multipage_save_file() if (output_format == XSANE_PS) { - xsane_save_ps_create_document_header(outfile, pages, preferences.save_ps_flatdecoded); + xsane_save_ps_create_document_header(outfile, pages, preferences.save_ps_flatedecoded); } else if (output_format == XSANE_PDF) { - xsane_save_pdf_create_document_header(outfile, &xref, pages, preferences.save_pdf_flatdecoded); + xsane_save_pdf_create_document_header(outfile, &xref, pages, preferences.save_pdf_flatedecoded); } } #ifdef HAVE_LIBTIFF @@ -1032,7 +1087,8 @@ static void xsane_multipage_save_file() xsane_save_ps_page(outfile, page, imagefile, &image_info, imagewidth, imageheight, 0, 0, imagewidth, imageheight, 0 /* portrait top left */, - preferences.save_ps_flatdecoded, + preferences.save_ps_flatedecoded, + NULL /* hTransform */, 0 /* embed_scanner_icm_profile */, xsane.project_progress_bar, &cancel_save); } else if (output_format == XSANE_PDF) @@ -1043,14 +1099,31 @@ static void xsane_multipage_save_file() xsane_save_pdf_page(outfile, &xref, page, imagefile, &image_info, imagewidth, imageheight, 0, 0, imagewidth, imageheight, 0 /* portrait top left */, - preferences.save_pdf_flatdecoded, + preferences.save_pdf_flatedecoded, + NULL /* hTransform */, 0 /* embed_scanner_icm_profile */, 0 /* icc_object */, xsane.project_progress_bar, &cancel_save); } #ifdef HAVE_LIBTIFF else if (output_format == XSANE_TIFF) { - xsane_save_tiff_page(tiffile, page, pages, imagefile, &image_info, preferences.jpeg_quality, + cmsHTRANSFORM hTransform = NULL; + +#ifdef HAVE_LIBLCMS + if ( (preferences.cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && xsane.enable_color_management ) + { + hTransform = xsane_create_cms_transform(&image_info, preferences.cms_function, preferences.cms_intent, preferences.cms_bpc); + } +#endif + + xsane_save_tiff_page(tiffile, page, pages, preferences.jpeg_quality, imagefile, &image_info, + hTransform, xsane.enable_color_management, preferences.cms_function, xsane.project_progress_bar, &cancel_save); +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + cmsDeleteTransform(hTransform); + } +#endif } #endif diff --git a/src/xsane-multipage-project.h b/src/xsane-multipage-project.h index 5f945eb..090ebc3 100644 --- a/src/xsane-multipage-project.h +++ b/src/xsane-multipage-project.h @@ -3,7 +3,7 @@ xsane-multipage-project.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 2005 Oliver Rauch + Copyright (C) 2005-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-preferences.c b/src/xsane-preferences.c index 011e802..2705477 100644 --- a/src/xsane-preferences.c +++ b/src/xsane-preferences.c @@ -3,7 +3,7 @@ xsane-preferences.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -55,6 +55,9 @@ Preferences preferences = 0, /* default working_directory */ 0, /* no default filename */ 0, /* no default filetype */ + 0, /* default cms_function: embed scanner profile */ + 0, /* default cms_intent: perceptual */ + 0, /* default cms_bpc (black point compensation) off */ 0137, /* image umask (permission mask for -rw-r------) */ 0027, /* directory umask (permission mask for -rwxr-x----) */ 0, /* no fax project */ @@ -69,7 +72,7 @@ Preferences preferences = 0.0, /* fax_leftoffset */ 0.0, /* fax_bottomoffset */ 1, /* fax_fine_mode */ - 1, /* fax_ps_flatdecoded */ + 1, /* fax_ps_flatedecoded */ #ifdef XSANE_ACTIVATE_EMAIL 0, /* no default from email address */ 0, /* no default reply to email address */ @@ -101,8 +104,8 @@ Preferences preferences = 1, /* save_devprefs_at_exit */ 1, /* overwrite_warning */ 1, /* skip_existing_numbers */ - 1, /* save_ps_flatdecoded */ - 1, /* save_pdf_flatdecoded */ + 1, /* save_ps_flatedecoded */ + 1, /* save_pdf_flatedecoded */ 0, /* save_pnm16_as_ascii */ 0, /* reduce_16bit_to_8bit */ 1, /* filename_counter_step */ @@ -168,6 +171,9 @@ desc[] = {"working-directory", xsane_rc_pref_string, POFFSET(working_directory)}, {"filename", xsane_rc_pref_string, POFFSET(filename)}, {"filetype", xsane_rc_pref_string, POFFSET(filetype)}, + {"cms-function", xsane_rc_pref_int, POFFSET(cms_function)}, + {"cms-intent", xsane_rc_pref_int, POFFSET(cms_intent)}, + {"cms-bpc", xsane_rc_pref_int, POFFSET(cms_bpc)}, {"image-umask", xsane_rc_pref_int, POFFSET(image_umask)}, {"directory-umask", xsane_rc_pref_int, POFFSET(directory_umask)}, {"fax-project", xsane_rc_pref_string, POFFSET(fax_project)}, @@ -182,7 +188,7 @@ desc[] = {"fax-left-offset", xsane_rc_pref_double, POFFSET(fax_leftoffset)}, {"fax-bottom-offset", xsane_rc_pref_double, POFFSET(fax_bottomoffset)}, {"fax-fine-mode", xsane_rc_pref_int, POFFSET(fax_fine_mode)}, - {"fax-ps-flatdecoded", xsane_rc_pref_int, POFFSET(fax_ps_flatdecoded)}, + {"fax-ps-flatedecoded", xsane_rc_pref_int, POFFSET(fax_ps_flatedecoded)}, #ifdef XSANE_ACTIVATE_EMAIL {"e-mail-from", xsane_rc_pref_string, POFFSET(email_from)}, {"e-mail-reply-to", xsane_rc_pref_string, POFFSET(email_reply_to)}, @@ -214,8 +220,8 @@ desc[] = {"save-devprefs-at-exit", xsane_rc_pref_int, POFFSET(save_devprefs_at_exit)}, {"overwrite-warning", xsane_rc_pref_int, POFFSET(overwrite_warning)}, {"skip-existing-numbers", xsane_rc_pref_int, POFFSET(skip_existing_numbers)}, - {"save-ps-flatdecoded", xsane_rc_pref_int, POFFSET(save_ps_flatdecoded)}, - {"save-pdf-flatdecoded", xsane_rc_pref_int, POFFSET(save_pdf_flatdecoded)}, + {"save-ps-flatedecoded", xsane_rc_pref_int, POFFSET(save_ps_flatedecoded)}, + {"save-pdf-flatedecoded", xsane_rc_pref_int, POFFSET(save_pdf_flatedecoded)}, {"save-pnm16-as-ascii", xsane_rc_pref_int, POFFSET( save_pnm16_as_ascii)}, {"reduce-16bit-to8bit", xsane_rc_pref_int, POFFSET(reduce_16bit_to_8bit)}, {"filename-counter-step", xsane_rc_pref_int, POFFSET(filename_counter_step)}, @@ -231,6 +237,9 @@ desc[] = {"show-resolution-list", xsane_rc_pref_int, POFFSET(show_resolution_list)}, {"length-unit", xsane_rc_pref_double, POFFSET(length_unit)}, {"main-window-fixed", xsane_rc_pref_int, POFFSET(main_window_fixed)}, + {"display-icm-profile", xsane_rc_pref_string, POFFSET(display_icm_profile)}, + {"custom-proofing-icm-profile", xsane_rc_pref_string, POFFSET(custom_proofing_icm_profile)}, + {"working-color-space-icm-profile", xsane_rc_pref_string, POFFSET(working_color_space_icm_profile)}, {"preview-own-cmap", xsane_rc_pref_int, POFFSET(preview_own_cmap)}, {"preview-oversampling", xsane_rc_pref_double, POFFSET(preview_oversampling)}, {"preview-gamma", xsane_rc_pref_double, POFFSET(preview_gamma)}, @@ -289,7 +298,11 @@ desc_printer[] = {"printer-gamma-red", xsane_rc_pref_double, PRTOFFSET(gamma_red)}, {"printer-gamma-green", xsane_rc_pref_double, PRTOFFSET(gamma_green)}, {"printer-gamma-blue", xsane_rc_pref_double, PRTOFFSET(gamma_blue)}, - {"printer-ps-flatdecoded", xsane_rc_pref_int, PRTOFFSET(ps_flatdecoded)} + {"printer-icm-profile", xsane_rc_pref_string, PRTOFFSET(icm_profile)}, + {"printer-ps-flatedecoded", xsane_rc_pref_int, PRTOFFSET(ps_flatedecoded)}, + {"printer-embed-csa", xsane_rc_pref_int, PRTOFFSET(embed_csa)}, + {"printer-embed-crd", xsane_rc_pref_int, PRTOFFSET(embed_crd)}, + {"printer-bpc", xsane_rc_pref_int, PRTOFFSET(blackpointcompensation)} }; /* --------------------------------------------------------------------- */ diff --git a/src/xsane-preferences.h b/src/xsane-preferences.h index 9f0e442..916df37 100644 --- a/src/xsane-preferences.h +++ b/src/xsane-preferences.h @@ -3,7 +3,7 @@ xsane-preferences.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -48,7 +48,11 @@ typedef struct double gamma_red; /* printer gamma red */ double gamma_green; /* printer gamma green */ double gamma_blue; /* printer gamma blue */ - int ps_flatdecoded; /* flatdecode (zlib compression), ps level 3 */ + char *icm_profile; /* printer ICM profile */ + int ps_flatedecoded; /* flatedecode (zlib compression), ps level 3 */ + int embed_csa; /* CSA = scanner ICM profile for postscript files */ + int embed_crd; /* CRD = printer ICM profile for postscript files */ + int blackpointcompensation; /* bpc */ } Preferences_printer_t; @@ -93,6 +97,9 @@ typedef struct char *working_directory; /* directory where xsane saves images etc */ char *filename; /* default filename */ char *filetype; /* default filetype */ + int cms_function; /* cms function (embed/srgb/working cs) */ + int cms_intent; /* cms rendering intent */ + int cms_bpc; /* cms black point compensation */ int image_umask; /* image umask (permisson mask) */ int directory_umask; /* directory umask (permisson mask) */ @@ -108,7 +115,7 @@ typedef struct double fax_leftoffset; /* left offset of fax paper in mm */ double fax_bottomoffset; /* bottom offset of fax paper in mm */ int fax_fine_mode; /* use fine or normal mode */ - int fax_ps_flatdecoded; /* use postscript level 3 zlib compression */ + int fax_ps_flatedecoded; /* use postscript level 3 zlib compression */ #ifdef XSANE_ACTIVATE_EMAIL char *email_from; /* email address of sender */ @@ -144,8 +151,8 @@ typedef struct int save_devprefs_at_exit; /* save device preferences at exit */ int overwrite_warning; /* warn if file exists */ int skip_existing_numbers; /* skip used filenames when automatically increase counter */ - int save_ps_flatdecoded; /* use zlib to for postscript compression (flatdecode) */ - int save_pdf_flatdecoded; /* use zlib to for pdf compression (flatdecode) */ + int save_ps_flatedecoded; /* use zlib to for postscript compression (flatedecode) */ + int save_pdf_flatedecoded; /* use zlib to for pdf compression (flatedecode) */ int save_pnm16_as_ascii; /* selection if pnm 16 bit is saved as ascii or binary file */ int reduce_16bit_to_8bit; /* reduce images with 16 bits/color to 8 bits/color */ int filename_counter_step; /* filename_counter += filename_counter_step; */ @@ -192,6 +199,10 @@ typedef struct int gtk_update_policy; int medium_nr; + char *display_icm_profile; + char *custom_proofing_icm_profile; + char *working_color_space_icm_profile; + int paper_orientation; /* image position on printer and page orientation */ int printernr; /* number of printers */ int printerdefinitions; diff --git a/src/xsane-preview.c b/src/xsane-preview.c index 46d8611..45679f1 100644 --- a/src/xsane-preview.c +++ b/src/xsane-preview.c @@ -3,7 +3,7 @@ xsane-preview.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -196,7 +196,9 @@ static void preview_establish_ratio(Preview *p); static void preview_ratio_callback(GtkWidget *widget, gpointer data); static void preview_autoselect_scanarea_callback(GtkWidget *window, gpointer data); +void preview_display_with_correction(Preview *p); void preview_do_gamma_correction(Preview *p); +int preview_do_color_correction(Preview *p); void preview_calculate_raw_histogram(Preview *p, SANE_Int *count_raw, SANE_Int *count_raw_red, SANE_Int *count_raw_green, SANE_Int *count_raw_blue); void preview_calculate_enh_histogram(Preview *p, SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue); void preview_gamma_correction(Preview *p, int gamma_input_bits, @@ -1276,7 +1278,7 @@ static void preview_display_image(Preview *p) assert(p->image_data_enh); } - preview_do_gamma_correction(p); + preview_display_with_correction(p); } /* ---------------------------------------------------------------------------------------------------------------------- */ @@ -1452,8 +1454,9 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio { SANE_Status status; Preview *p = data; - u_char buf[8192]; - guint16 *buf16 = (guint16 *) buf; + char buf[TEXTBUFSIZE]; + u_char imagebuf8[8192]; + guint16 *imagebuf16 = (guint16 *) imagebuf8; SANE_Handle dev; SANE_Int len; int i, j; @@ -1465,26 +1468,26 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio { if ((p->params.depth == 1) || (p->params.depth == 8)) { - status = sane_read(dev, buf, sizeof(buf), &len); + status = sane_read(dev, imagebuf8, sizeof(imagebuf8), &len); } else if (p->params.depth == 16) { if (p->read_offset_16) { - buf[0] = p->last_offset_16_byte; - /* use buf and sizeof(buf) here because sizeof(buf16) returns the size of a pointer */ - status = sane_read(dev, buf+1, sizeof(buf) - 1, &len); + imagebuf8[0] = p->last_offset_16_byte; + /* use imagebuf8 and sizeof(imagebuf8) here because sizeof(imagebuf16) returns the size of a pointer */ + status = sane_read(dev, imagebuf8+1, sizeof(imagebuf8) - 1, &len); len++; } else { - status = sane_read(dev, (SANE_Byte *) buf16, sizeof(buf), &len); + status = sane_read(dev, (SANE_Byte *) imagebuf16, sizeof(imagebuf8), &len); } if (len % 2) /* odd number of bytes */ { len--; - p->last_offset_16_byte = buf16[len]; + p->last_offset_16_byte = imagebuf16[len]; p->read_offset_16 = 1; } else /* even number of bytes */ @@ -1576,8 +1579,8 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio return; /* backend sends too much image data */ } - p->image_data_raw[p->image_offset] = buf[i] * 256; - p->image_data_enh[p->image_offset++] = buf[i]; + p->image_data_raw[p->image_offset] = imagebuf8[i] * 256; + p->image_data_enh[p->image_offset++] = imagebuf8[i]; if (p->image_offset%3 == 0) { @@ -1599,8 +1602,8 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio return; /* backend sends too much image data */ } - p->image_data_raw[p->image_offset] = buf16[i]; - p->image_data_enh[p->image_offset++] = (u_char) (buf16[i]/256); + p->image_data_raw[p->image_offset] = imagebuf16[i]; + p->image_data_enh[p->image_offset++] = (u_char) (imagebuf16[i]/256); if (p->image_offset%3 == 0) { @@ -1627,7 +1630,7 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio case 1: for (i = 0; i < len; ++i) { - u_char mask = buf[i]; + u_char mask = imagebuf8[i]; if (preview_test_image_y(p)) { @@ -1662,7 +1665,7 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio case 8: for (i = 0; i < len; ++i) { - u_char gray = buf[i]; + u_char gray = imagebuf8[i]; if (preview_test_image_y(p)) { @@ -1687,20 +1690,20 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio case 16: for (i = 0; i < len/2; ++i) { - u_char gray = buf16[i]/256; + u_char gray = imagebuf16[i]/256; if (preview_test_image_y(p)) { return; /* backend sends too much image data */ } - p->image_data_raw[p->image_offset] = buf16[i]; + p->image_data_raw[p->image_offset] = imagebuf16[i]; p->image_data_enh[p->image_offset++] = gray; - p->image_data_raw[p->image_offset] = buf16[i]; + p->image_data_raw[p->image_offset] = imagebuf16[i]; p->image_data_enh[p->image_offset++] = gray; - p->image_data_raw[p->image_offset] = buf16[i]; + p->image_data_raw[p->image_offset] = imagebuf16[i]; p->image_data_enh[p->image_offset++] = gray; if (++p->image_x >= p->image_width && preview_increment_image_y(p) < 0) @@ -1726,7 +1729,7 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio case 1: for (i = 0; i < len; ++i) { - u_char mask = buf[i]; + u_char mask = imagebuf8[i]; if (preview_test_image_y(p)) { @@ -1758,8 +1761,8 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio return; /* backend sends too much image data */ } - p->image_data_raw[p->image_offset] = buf[i] * 256; - p->image_data_enh[p->image_offset] = buf[i]; + p->image_data_raw[p->image_offset] = imagebuf8[i] * 256; + p->image_data_enh[p->image_offset] = imagebuf8[i]; p->image_offset += 3; if (++p->image_x >= p->image_width && preview_increment_image_y(p) < 0) @@ -1777,8 +1780,8 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio return; /* backend sends too much image data */ } - p->image_data_raw[p->image_offset] = buf16[i]; - p->image_data_enh[p->image_offset] = (u_char) (buf16[i]/256); + p->image_data_raw[p->image_offset] = imagebuf16[i]; + p->image_data_enh[p->image_offset] = (u_char) (imagebuf16[i]/256); p->image_offset += 3; if (++p->image_x >= p->image_width && preview_increment_image_y(p) < 0) @@ -1880,7 +1883,7 @@ static void preview_scan_done(Preview *p, int save_image) xsane_update_histogram(TRUE /* update_raw */); /* update histogram (necessary because overwritten by preview_update_surface) */ } - if ((preferences.auto_correct_colors) && (!xsane.medium_calibration)) + if ((preferences.auto_correct_colors) && (!xsane.medium_calibration) && (!xsane.enable_color_management)) { xsane_calculate_raw_histogram(); xsane_set_auto_enhancement(); @@ -2418,6 +2421,7 @@ void preview_create_batch_icon(Preview *p, Batch_Scan_Parameters *parameters) if (in) { quality = preview_create_batch_icon_from_file(xsane.preview, in, parameters, quality, &time); + fclose(in); } } } @@ -2426,19 +2430,14 @@ void preview_create_batch_icon(Preview *p, Batch_Scan_Parameters *parameters) { char filename[PATH_MAX]; - if (in) - { - fclose(in); - } - xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, "xsane-startimage", 0, ".pnm", XSANE_PATH_SYSTEM); in = fopen(filename, "rb"); /* read binary (b for win32) */ if (in) { preview_create_batch_icon_from_file(xsane.preview, in, parameters, -1, &time); + fclose(in); } } - fclose(in); } /* ---------------------------------------------------------------------------------------------------------------------- */ @@ -2767,7 +2766,7 @@ static void preview_display_zoom(Preview *p, int x, int y, int zoom) int r, g, b; int px, py; int i; - char *row; + u_char *row; DBG(DBG_proc, "preview_display_zoom"); @@ -4241,7 +4240,7 @@ Preview *preview_new(void) p->maximum_output_height = INF; /* full output height */ p->block_update_maximum_output_size_clipping = FALSE; - p->preview_colors = -1; + p->preview_channels = -1; p->invalid = TRUE; /* no valid preview */ p->ratio = 0.0; @@ -4563,7 +4562,6 @@ Preview *preview_new(void) gtk_widget_show(p->invalid_pixmap); gdk_drawable_unref(pixmap); - /* Start button */ p->start = gtk_button_new_with_label(BUTTON_PREVIEW_ACQUIRE); xsane_back_gtk_set_tooltip(xsane.tooltips, p->start, DESC_PREVIEW_ACQUIRE); @@ -4853,7 +4851,7 @@ void preview_update_surface(Preview *p, int surface_changed) DBG(DBG_info, "preview_update_surface: establish new surface\n"); preview_area_correct(p); /* calculate preview_width and height */ preview_area_resize(p); /* correct rulers */ - preview_do_gamma_correction(p); /* draw preview */ + preview_display_with_correction(p); /* draw preview */ xsane_update_histogram(TRUE /* update raw */); p->previous_selection.active = FALSE; @@ -5013,7 +5011,7 @@ void preview_scan(Preview *p) gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int)); - if ((xsane.xsane_colors > 1) || (xsane.no_preview_medium_gamma)) /* color scan or medium preview gamma disabled */ + if ((xsane.xsane_channels > 1) || (xsane.no_preview_medium_gamma)) /* color scan or medium preview gamma disabled */ { xsane_create_gamma_curve(gamma_data, 0, 1.0, 0.0, 0.0, 0.0, 100.0, 1.0, gamma_gray_size, gamma_gray_max); } @@ -5089,7 +5087,7 @@ void preview_scan(Preview *p) xsane.block_update_param = FALSE; - p->preview_colors = xsane.xsane_colors; + p->preview_channels = xsane.xsane_channels; p->scan_incomplete = FALSE; p->invalid = TRUE; /* no valid preview */ p->scanning = TRUE; @@ -6204,6 +6202,29 @@ static void preview_autoselect_scanarea_callback(GtkWidget *window, gpointer dat /* ---------------------------------------------------------------------------------------------------------------------- */ +void preview_display_with_correction(Preview *p) +{ +#ifdef HAVE_LIBLCMS + if (xsane.enable_color_management) + { + preview_do_color_correction(p); + gtk_widget_set_sensitive(p->pipette_white, FALSE); /* disable pipette buttons */ + gtk_widget_set_sensitive(p->pipette_gray, FALSE); /* disable pipette buttons */ + gtk_widget_set_sensitive(p->pipette_black, FALSE); /* disable pipette buttons */ + + } + else +#endif + { + preview_do_gamma_correction(p); + gtk_widget_set_sensitive(p->pipette_white, TRUE); /* enable pipette buttons */ + gtk_widget_set_sensitive(p->pipette_gray, TRUE); /* enable pipette buttons */ + gtk_widget_set_sensitive(p->pipette_black, TRUE); /* enable pipette buttons */ + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + void preview_do_gamma_correction(Preview *p) { int x,y; @@ -6212,7 +6233,7 @@ void preview_do_gamma_correction(Preview *p) guint16 *image_data_rawp = NULL; int rotate = 16 - preview_gamma_input_bits; - DBG(DBG_proc, "preview_do_gamma_correction\n"); + DBG(DBG_proc, "preview_display_with_correction\n"); if ((p->image_data_raw) && (p->params.depth > 1) && (preview_gamma_data_red)) { @@ -6239,7 +6260,7 @@ void preview_do_gamma_correction(Preview *p) { while (gtk_events_pending()) { - DBG(DBG_info, "preview_do_gamma_correction: calling gtk_main_iteration\n"); + DBG(DBG_info, "preview_display_with_correction: calling gtk_main_iteration\n"); gtk_main_iteration(); } } @@ -6288,6 +6309,167 @@ void preview_do_gamma_correction(Preview *p) /* ---------------------------------------------------------------------------------------------------------------------- */ +#ifdef HAVE_LIBLCMS +int preview_do_color_correction(Preview *p) +{ + int y; + u_char *image_data_enhp = NULL; + guint16 *image_data_rawp = NULL; + cmsHPROFILE hInProfile = NULL; + cmsHPROFILE hOutProfile = NULL; + cmsHPROFILE hProofProfile = NULL; + cmsHTRANSFORM hTransform = NULL; + DWORD input_format, output_format; + DWORD cms_flags = 0; + int proof = 0; + char *cms_proof_icm_profile = NULL; + int linesize = 0; + + + DBG(DBG_proc, "preview_do_color_correction\n"); + + cmsErrorAction(LCMS_ERROR_SHOW); + + if (preferences.cms_bpc) + { + cms_flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + + switch (p->cms_proofing) + { + default: + case 0: /* display */ + proof = 0; + break; + + case 1: /* proof printer */ + cms_proof_icm_profile = preferences.printer[preferences.printernr]->icm_profile; + proof = 1; + break; + + case 2: /* proof custom proofing */ + cms_proof_icm_profile = preferences.custom_proofing_icm_profile; + proof = 1; + break; + } + + if ( (xsane.param.format == SANE_FRAME_RGB) || /* color preview */ + (xsane.param.format == SANE_FRAME_RED) || + (xsane.param.format == SANE_FRAME_GREEN) || + (xsane.param.format == SANE_FRAME_BLUE) ) + { + input_format = TYPE_RGB_16; + output_format = TYPE_RGB_8; + linesize = p->image_width * 3; + } + else + { + input_format = TYPE_GRAY_16; + output_format = TYPE_GRAY_8; + linesize = p->image_width; + } + + hInProfile = cmsOpenProfileFromFile(xsane.scanner_default_color_icm_profile, "r"); + if (!hInProfile) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_SCANNER_ICM, xsane.scanner_default_color_icm_profile); + xsane_back_gtk_error(buf, TRUE); + return -1; + } + + hOutProfile = cmsOpenProfileFromFile(preferences.display_icm_profile, "r"); + if (!hOutProfile) + { + char buf[TEXTBUFSIZE]; + + cmsCloseProfile(hInProfile); + + snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_DISPLAY_ICM, preferences.display_icm_profile); + xsane_back_gtk_error(buf, TRUE); + return -1; + } + + if (proof == 0) + { + hTransform = cmsCreateTransform(hInProfile, input_format, + hOutProfile, output_format, + preferences.cms_intent, cms_flags); + } + else /* proof */ + { + cms_flags |= cmsFLAGS_SOFTPROOFING; + + if (p->cms_gamut_check) + { + cms_flags |= cmsFLAGS_GAMUTCHECK; + } + + hProofProfile = cmsOpenProfileFromFile(cms_proof_icm_profile, "r"); + if (!hProofProfile) + { + char buf[TEXTBUFSIZE]; + + cmsCloseProfile(hInProfile); + cmsCloseProfile(hOutProfile); + + snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_PROOF_ICM, cms_proof_icm_profile); + xsane_back_gtk_error(buf, TRUE); + return -1; + } + + hTransform = cmsCreateProofingTransform(hInProfile, input_format, + hOutProfile, output_format, + hProofProfile, + preferences.cms_intent, p->cms_proofing_intent, cms_flags); + } + + if (!hTransform) + { + char buf[TEXTBUFSIZE]; + + cmsCloseProfile(hInProfile); + cmsCloseProfile(hOutProfile); + if (proof) + { + cmsCloseProfile(hProofProfile); + } + + snprintf(buf, sizeof(buf), "%s\n%s\n", ERR_CMS_CONVERSION, ERR_CMS_CREATE_TRANSFORM); + xsane_back_gtk_error(buf, TRUE); + return -1; + } + + + for (y=0; y < p->image_height; y++) + { + image_data_rawp = p->image_data_raw + linesize * y; + image_data_enhp = p->image_data_enh + linesize * y; + + cmsDoTransform(hTransform, image_data_rawp, image_data_enhp, p->image_width); + + if (p->gamma_functions_interruptable) + { + while (gtk_events_pending()) + { + DBG(DBG_info, "preview_do_color_correction: calling gtk_main_iteration\n"); + gtk_main_iteration(); + } + } + } + + if (p->image_data_enh) + { + preview_display_partial_image(p); + } + + return 0; +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + void preview_calculate_raw_histogram(Preview *p, SANE_Int *count_raw, SANE_Int *count_raw_red, SANE_Int *count_raw_green, SANE_Int *count_raw_blue) { int x, y; @@ -6625,7 +6807,7 @@ void preview_gamma_correction(Preview *p, int gamma_input_bits, preview_gamma_input_bits = gamma_input_bits; - preview_do_gamma_correction(p); + preview_display_with_correction(p); preview_draw_selection(p); } @@ -7363,7 +7545,7 @@ void preview_display_valid(Preview *p) gtk_widget_hide(p->valid_pixmap); gtk_widget_hide(p->invalid_pixmap); } - else if ((xsane.medium_changed) || (xsane.xsane_colors != p->preview_colors) || (p->invalid) ) /* preview is not valid */ + else if ((xsane.medium_changed) || (xsane.xsane_channels != p->preview_channels) || (p->invalid) ) /* preview is not valid */ { DBG(DBG_info, "preview not vaild\n"); diff --git a/src/xsane-preview.h b/src/xsane-preview.h index d57870e..a488ce2 100644 --- a/src/xsane-preview.h +++ b/src/xsane-preview.h @@ -3,7 +3,7 @@ xsane-preview.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -122,7 +122,7 @@ typedef struct char last_offset_16_byte; int scan_incomplete; int invalid; - int preview_colors; + int preview_channels; time_t image_last_time_updated; gint input_tag; SANE_Parameters params; @@ -153,6 +153,13 @@ typedef struct int show_selection; +#ifdef HAVE_LIBLCMS + int cms_enable; + int cms_proofing; + int cms_proofing_intent; + int cms_gamut_check; +#endif + #if 0 Batch_selection *batch_selection; #endif diff --git a/src/xsane-rc-io.c b/src/xsane-rc-io.c index 4a0af86..39a29ef 100644 --- a/src/xsane-rc-io.c +++ b/src/xsane-rc-io.c @@ -3,7 +3,7 @@ xsane-rc-io.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -119,7 +119,7 @@ void xsane_rc_io_w_void(Wire *w) /* ---------------------------------------------------------------------------------------------------------------- */ -void xsane_rc_io_w_array(Wire *w, SANE_Word *len_ptr, void **v, WireCodecFunc w_element, size_t element_size) +void xsane_rc_io_w_array(Wire *w, SANE_Word *len_ptr, char **v, WireCodecFunc w_element, size_t element_size) { SANE_Word len; char *val; @@ -180,7 +180,7 @@ void xsane_rc_io_w_array(Wire *w, SANE_Word *len_ptr, void **v, WireCodecFunc w_ /* ---------------------------------------------------------------------------------------------------------------- */ -void xsane_rc_io_w_ptr(Wire *w, void **v, WireCodecFunc w_value, size_t value_size) +void xsane_rc_io_w_ptr(Wire *w, char **v, WireCodecFunc w_value, size_t value_size) { SANE_Word is_null; @@ -352,7 +352,7 @@ void xsane_rc_io_w_device_ptr(Wire *w, SANE_Device **v) { DBG(DBG_wire, "xsane_rc_io_w_device_ptr\n"); - xsane_rc_io_w_ptr(w, (void **) v, (WireCodecFunc) xsane_rc_io_w_device, sizeof (**v)); + xsane_rc_io_w_ptr(w, (char **) v, (WireCodecFunc) xsane_rc_io_w_device, sizeof (**v)); } /* ---------------------------------------------------------------------------------------------------------------- */ @@ -360,6 +360,7 @@ void xsane_rc_io_w_device_ptr(Wire *w, SANE_Device **v) void xsane_rc_io_w_option_descriptor(Wire *w, SANE_Option_Descriptor *v) { SANE_Word len; + char *data_ptr = NULL; DBG(DBG_wire, "xsane_rc_io_w_option_descriptor\n"); @@ -378,7 +379,8 @@ void xsane_rc_io_w_option_descriptor(Wire *w, SANE_Option_Descriptor *v) break; case SANE_CONSTRAINT_RANGE: - xsane_rc_io_w_ptr(w, (void **) &v->constraint.range, (WireCodecFunc) xsane_rc_io_w_range, sizeof (SANE_Range)); + data_ptr = (char *) v->constraint.range; + xsane_rc_io_w_ptr(w, &data_ptr, (WireCodecFunc) xsane_rc_io_w_range, sizeof (SANE_Range)); break; case SANE_CONSTRAINT_WORD_LIST: @@ -386,16 +388,18 @@ void xsane_rc_io_w_option_descriptor(Wire *w, SANE_Option_Descriptor *v) { len = v->constraint.word_list[0] + 1; } - xsane_rc_io_w_array(w, &len, (void **) &v->constraint.word_list, w->codec.w_word, sizeof(SANE_Word)); + data_ptr = (char *) v->constraint.word_list; + xsane_rc_io_w_array(w, &len, &data_ptr, w->codec.w_word, sizeof(SANE_Word)); break; case SANE_CONSTRAINT_STRING_LIST: if (w->direction != WIRE_DECODE) - { - for (len = 0; v->constraint.string_list[len]; ++len); - ++len; /* send NULL string, too */ - } - xsane_rc_io_w_array(w, &len, (void **) &v->constraint.string_list, w->codec.w_string, sizeof(SANE_String)); + { + for (len = 0; v->constraint.string_list[len]; ++len); + ++len; /* send NULL string, too */ + } + data_ptr = (char *) v->constraint.string_list; + xsane_rc_io_w_array(w, &len, &data_ptr, w->codec.w_string, sizeof(SANE_String)); break; } } @@ -406,7 +410,7 @@ void xsane_rc_io_w_option_descriptor_ptr(Wire *w, SANE_Option_Descriptor **v) { DBG(DBG_wire, "xsane_rc_io_w_option_descriptor_ptr\n"); - xsane_rc_io_w_ptr(w, (void **) v, (WireCodecFunc) xsane_rc_io_w_option_descriptor, sizeof (**v)); + xsane_rc_io_w_ptr(w, (char **) v, (WireCodecFunc) xsane_rc_io_w_option_descriptor, sizeof (**v)); } /* ---------------------------------------------------------------------------------------------------------------- */ diff --git a/src/xsane-rc-io.h b/src/xsane-rc-io.h index dab2555..bfd7a3c 100644 --- a/src/xsane-rc-io.h +++ b/src/xsane-rc-io.h @@ -3,7 +3,7 @@ xsane-rc-io.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -108,7 +108,7 @@ extern void xsane_rc_io_w_device_ptr(Wire *w, SANE_Device **v); extern void xsane_rc_io_w_option_descriptor(Wire *w, SANE_Option_Descriptor *v); extern void xsane_rc_io_w_option_descriptor_ptr(Wire *w, SANE_Option_Descriptor **v); extern void xsane_rc_io_w_parameters(Wire *w, SANE_Parameters *v); -extern void xsane_rc_io_w_array(Wire *w, SANE_Word *len, void **v, WireCodecFunc w_element, size_t element_size); +extern void xsane_rc_io_w_array(Wire *w, SANE_Word *len, char **v, WireCodecFunc w_element, size_t element_size); extern void xsane_rc_io_w_flush(Wire *w); extern void xsane_rc_io_w_set_dir(Wire *w, WireDirection dir); extern void xsane_rc_io_w_call(Wire *w, SANE_Word proc_num, WireCodecFunc w_arg, void *arg, WireCodecFunc w_reply, void *reply); diff --git a/src/xsane-save.c b/src/xsane-save.c index a56e2ce..cc5f934 100644 --- a/src/xsane-save.c +++ b/src/xsane-save.c @@ -3,7 +3,7 @@ xsane-save.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -430,6 +430,7 @@ void xsane_read_pnm_header(FILE *file, Image_info *image_info) image_info->resolution_x = 72.0; image_info->resolution_y = 72.0; image_info->reduce_to_lineart = FALSE; + image_info->enable_color_management = FALSE; while (strcmp(buf, "# XSANE data follows\n")) { @@ -483,6 +484,26 @@ void xsane_read_pnm_header(FILE *file, Image_info *image_info) &image_info->contrast_green, &image_info->contrast_blue); } + else if (!strncmp(buf, "# color-management=", 20)) + { + sscanf(buf+20, "%d", &image_info->enable_color_management); + } + else if (!strncmp(buf, "# cms-function =", 20)) + { + sscanf(buf+20, "%d", &image_info->cms_function); + } + else if (!strncmp(buf, "# cms-intent =", 20)) + { + sscanf(buf+20, "%d", &image_info->cms_intent); + } + else if (!strncmp(buf, "# cms-bpc =", 20)) + { + sscanf(buf+20, "%d", &image_info->cms_bpc); + } + else if (!strncmp(buf, "# icm-profile =", 20)) + { + sscanf(buf+20, "%s", image_info->icm_profile); + } else if (!strncmp(buf, "# reduce to lineart", 20)) { image_info->reduce_to_lineart = TRUE; @@ -510,11 +531,11 @@ void xsane_read_pnm_header(FILE *file, Image_info *image_info) fgetc(file); /* read exactly one newline character */ - image_info->colors = 1; + image_info->channels = 1; if (filetype_nr == 6) /* ppm RGB */ { - image_info->colors = 3; + image_info->channels = 3; } } #ifdef SUPPORT_RGBA @@ -534,12 +555,12 @@ void xsane_read_pnm_header(FILE *file, Image_info *image_info) image_info->depth = 16; } - image_info->colors = 4; + image_info->channels = 4; } #endif DBG(DBG_info, "xsane_read_pnm_header: width=%d, height=%d, depth=%d, colors=%d, resolution_x=%f, resolution_y=%f\n", - image_info->image_width, image_info->image_height, image_info->depth, image_info->colors, + image_info->image_width, image_info->image_height, image_info->depth, image_info->channels, image_info->resolution_x, image_info->resolution_y); } @@ -573,7 +594,7 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a } - if (image_info->colors == 1) + if (image_info->channels == 1) { if (image_info->depth == 1) { @@ -618,6 +639,11 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a "# gamma = %3.2f\n" "# brightness = %4.1f\n" "# contrast = %4.1f\n" + "# color-management= %d\n" + "# cms-function = %d\n" + "# cms-intent = %d\n" + "# cms-bpc = %d\n" + "# icm-profile = %s\n" "# XSANE data follows\n" "%05d %05d\n" "%d\n", @@ -627,11 +653,16 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a image_info->gamma, image_info->brightness, image_info->contrast, + image_info->enable_color_management, + image_info->cms_function, + image_info->cms_intent, + image_info->cms_bpc, + image_info->icm_profile, image_info->image_width, image_info->image_height, maxval); } } - else if (image_info->colors == 3) + else if (image_info->channels == 3) { fprintf(file, "P%d\n" "# XSane settings:\n" @@ -640,6 +671,11 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a "# gamma IRGB = %3.2f %3.2f %3.2f %3.2f\n" "# brightness IRGB = %4.1f %4.1f %4.1f %4.1f\n" "# contrast IRGB = %4.1f %4.1f %4.1f %4.1f\n" + "# color-management= %d\n" + "# cms-function = %d\n" + "# cms-intent = %d\n" + "# cms-bpc = %d\n" + "# icm-profile = %s\n" "# XSANE data follows\n" "%05d %05d\n" \ "%d\n", @@ -649,11 +685,16 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a image_info->gamma, image_info->gamma_red, image_info->gamma_green, image_info->gamma_blue, image_info->brightness, image_info->brightness_red, image_info->brightness_green, image_info->brightness_blue, image_info->contrast, image_info->contrast_red, image_info->contrast_green, image_info->contrast_blue, + image_info->enable_color_management, + image_info->cms_function, + image_info->cms_intent, + image_info->cms_bpc, + image_info->icm_profile, image_info->image_width, image_info->image_height, maxval); } #ifdef SUPPORT_RGBA - else if (image_info->colors == 4) + else if (image_info->channels == 4) { fprintf(file, "SANE_RGBA\n" \ "%d %d\n" \ @@ -793,6 +834,121 @@ int xsane_copy_file_by_name(char *output_filename, char *input_filename, GtkProg /* ---------------------------------------------------------------------------------------------------------------------- */ +#ifdef HAVE_LIBLCMS +cmsHTRANSFORM xsane_create_cms_transform(Image_info *image_info, int cms_function, int cms_intent, int cms_bpc) +{ + cmsHPROFILE hInProfile = NULL; + cmsHPROFILE hOutProfile = NULL; + cmsHTRANSFORM hTransform = NULL; + DWORD cms_input_format; + DWORD cms_output_format; + DWORD cms_flags = 0; + + if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) + { + return NULL; + } + + DBG(DBG_info, "Prepare CMS transform\n"); + + cmsErrorAction(LCMS_ERROR_SHOW); + + if (cms_bpc) + { + cms_flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + + if (image_info->channels == 1) /* == 1 (grayscale) */ + { + if (image_info->depth == 8) + { + cms_input_format = TYPE_GRAY_8; + cms_output_format = TYPE_GRAY_8; + } + else + { + cms_input_format = TYPE_GRAY_16; + cms_output_format = TYPE_GRAY_16; + } + } + else /* color */ + { + if (image_info->depth == 8) + { + cms_input_format = TYPE_RGB_8; + cms_output_format = TYPE_RGB_8; + } + else + { + cms_input_format = TYPE_RGB_16; + cms_output_format = TYPE_RGB_16; + } + } + + hInProfile = cmsOpenProfileFromFile(image_info->icm_profile, "r"); + if (!hInProfile) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_SCANNER_ICM, image_info->icm_profile); + xsane_back_gtk_error(buf, TRUE); + } +#if 0 +{ + LPGAMMATABLE Gamma = cmsBuildGamma(256, 3.0); + hOutProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma); + cmsFreeGamma(Gamma); +} +#endif + if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_SRGB) + { + hOutProfile = cmsCreate_sRGBProfile(); + } + else + { + hOutProfile = cmsOpenProfileFromFile(preferences.working_color_space_icm_profile, "r"); + if (!hOutProfile) + { + char buf[TEXTBUFSIZE]; + + cmsCloseProfile(hInProfile); + + snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_DISPLAY_ICM, preferences.display_icm_profile); + xsane_back_gtk_error(buf, TRUE); + } + } + + if (!hOutProfile) + { + char buf[TEXTBUFSIZE]; + + cmsCloseProfile(hInProfile); + + snprintf(buf, sizeof(buf), "%s\n", ERR_CMS_CONVERSION); + xsane_back_gtk_error(buf, TRUE); + } + + hTransform = cmsCreateTransform(hInProfile, cms_input_format, + hOutProfile, cms_output_format, + cms_intent, cms_flags); + + cmsCloseProfile(hInProfile); + cmsCloseProfile(hOutProfile); + + if (!hTransform) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s\n%s\n", ERR_CMS_CONVERSION, ERR_CMS_CREATE_TRANSFORM); + xsane_back_gtk_error(buf, TRUE); + } + + return hTransform; +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + int xsane_save_grayscale_image_as_lineart(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) { int x, y, bit; @@ -901,14 +1057,14 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in image_info->resolution_x *= x_scale; image_info->resolution_y *= y_scale; - original_line = malloc(original_image_width * image_info->colors * bytespp); + original_line = malloc(original_image_width * image_info->channels * bytespp); if (!original_line) { DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); return -1; } - new_line = malloc(new_image_width * image_info->colors * bytespp); + new_line = malloc(new_image_width * image_info->channels * bytespp); if (!new_line) { free(original_line); @@ -916,7 +1072,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in return -1; } - pixel_val = malloc(new_image_width * image_info->colors * sizeof(float)); + pixel_val = malloc(new_image_width * image_info->channels * sizeof(float)); if (!pixel_val) { free(original_line); @@ -925,7 +1081,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in return -1; } - pixel_norm = malloc(new_image_width * image_info->colors * sizeof(float)); + pixel_norm = malloc(new_image_width * image_info->channels * sizeof(float)); if (!pixel_norm) { free(original_line); @@ -939,8 +1095,8 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in read_line = TRUE; - memset(pixel_val, 0, new_image_width * image_info->colors * sizeof(float)); - memset(pixel_norm, 0, new_image_width * image_info->colors * sizeof(float)); + memset(pixel_val, 0, new_image_width * image_info->channels * sizeof(float)); + memset(pixel_norm, 0, new_image_width * image_info->channels * sizeof(float)); y_new = 0; y_go = 1.0 / y_scale; @@ -960,7 +1116,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in if (read_line) { DBG(DBG_info, "xsane_save_scaled_image: reading original line %d\n", (int) y); - fread(original_line, original_image_width, image_info->colors * bytespp, imagefile); /* read one line */ + fread(original_line, original_image_width, image_info->channels * bytespp, imagefile); /* read one line */ original_line16 = (guint16 *) original_line; } @@ -970,23 +1126,22 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in x_factor = 1.0; while ( (x < original_image_width) && (x_new < new_image_width) ) /* add this line to anti aliasing buffer */ - { factor = x_factor * y_factor; - for (c = 0; c < image_info->colors; c++) + for (c = 0; c < image_info->channels; c++) { if (bytespp == 1) { - color = original_line[((int) x) * image_info->colors + c]; + color = original_line[((int) x) * image_info->channels + c]; } else /* bytespp == 2 */ { - color = original_line16[((int) x) * image_info->colors + c]; + color = original_line16[((int) x) * image_info->channels + c]; } - pixel_val [x_new * image_info->colors + c] += factor * color; - pixel_norm[x_new * image_info->colors + c] += factor; + pixel_val [x_new * image_info->channels + c] += factor * color; + pixel_norm[x_new * image_info->channels + c] += factor; } x_go -= x_factor; @@ -1023,7 +1178,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in if (bytespp == 1) { - for (x_new = 0; x_new < new_image_width * image_info->colors; x_new++) + for (x_new = 0; x_new < new_image_width * image_info->channels; x_new++) { new_line[x_new] = (int) (pixel_val[x_new] / pixel_norm[x_new]); } @@ -1032,13 +1187,13 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in { guint16 *new_line16 = (guint16 *) new_line; - for (x_new = 0; x_new < new_image_width * image_info->colors; x_new++) + for (x_new = 0; x_new < new_image_width * image_info->channels; x_new++) { new_line16[x_new] = (int) (pixel_val[x_new] / pixel_norm[x_new]); } } - fwrite(new_line, new_image_width, image_info->colors * bytespp, outfile); /* write one line */ + fwrite(new_line, new_image_width, image_info->channels * bytespp, outfile); /* write one line */ if (ferror(outfile)) { @@ -1052,8 +1207,8 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in } /* reset values and norm factors */ - memset(pixel_val, 0, new_image_width * image_info->colors * sizeof(float)); - memset(pixel_norm, 0, new_image_width * image_info->colors * sizeof(float)); + memset(pixel_val, 0, new_image_width * image_info->channels * sizeof(float)); + memset(pixel_norm, 0, new_image_width * image_info->channels * sizeof(float)); y_new++; y_go = 1.0 / y_scale; @@ -1079,6 +1234,11 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in read_line = (oldy != (int) y); } + if (read_line) /* we have to write one more line */ + { + fwrite(new_line, new_image_width, image_info->channels * bytespp, outfile); /* write one line */ + } + free(original_line); free(new_line); free(pixel_val); @@ -1113,14 +1273,14 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in image_info->resolution_x *= x_scale; image_info->resolution_y *= y_scale; - original_line = malloc(original_image_width * image_info->colors * bytespp); + original_line = malloc(original_image_width * image_info->channels * bytespp); if (!original_line) { DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); return -1; } - new_line = malloc(new_image_width * image_info->colors * bytespp); + new_line = malloc(new_image_width * image_info->channels * bytespp); if (!new_line) { free(original_line); @@ -1143,18 +1303,18 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in for (; ((int) original_y) - old_original_y; old_original_y += 1) { - fread(original_line, original_image_width, image_info->colors * bytespp, imagefile); /* read one line */ + fread(original_line, original_image_width, image_info->channels * bytespp, imagefile); /* read one line */ } for (x = 0; x < new_image_width; x++) { - for (i = 0; i < image_info->colors * bytespp; i++) + for (i = 0; i < image_info->channels * bytespp; i++) { - new_line[x * image_info->colors * bytespp + i] = original_line[((int) (x / x_scale)) * image_info->colors * bytespp + i]; + new_line[x * image_info->channels * bytespp + i] = original_line[((int) (x / x_scale)) * image_info->channels * bytespp + i]; } } - fwrite(new_line, new_image_width, image_info->colors * bytespp, outfile); /* write one line */ + fwrite(new_line, new_image_width, image_info->channels * bytespp, outfile); /* write one line */ original_y += 1/y_scale; @@ -1187,7 +1347,7 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image guint16 *color_cache_ptr; int bytespp = 1; int color_radius; - int color_width = image_info->image_width * image_info->colors; + int color_width = image_info->image_width * image_info->channels; radius--; /* correct radius : 1 means nothing happens */ @@ -1196,7 +1356,7 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image radius = 1; } - color_radius = radius * image_info->colors; + color_radius = radius * image_info->channels; if (image_info->depth > 8) { @@ -1252,7 +1412,7 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image if (xmin < 0) { - xmin = x % image_info->colors; + xmin = x % image_info->channels; } if (xmax > color_width) @@ -1271,11 +1431,11 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image { line_cache_ptr = line_cache + (sy-ymin) * color_width + xmin; - for (sx = xmin; sx <= xmax; sx+=image_info->colors) /* x part */ + for (sx = xmin; sx <= xmax; sx+=image_info->channels) /* x part */ { *color_cache_ptr = *line_cache_ptr; color_cache_ptr++; - line_cache_ptr += image_info->colors; + line_cache_ptr += image_info->channels; } } @@ -1314,11 +1474,11 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image { line_cache16_ptr = line_cache16 + (sy-ymin) * color_width + xmin; - for (sx = xmin; sx <= xmax; sx+=image_info->colors) + for (sx = xmin; sx <= xmax; sx+=image_info->channels) { *color_cache_ptr = *line_cache16_ptr; color_cache_ptr++; - line_cache16_ptr += image_info->colors; + line_cache16_ptr += image_info->channels; } } @@ -1407,14 +1567,14 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info xsane_write_pnm_header(outfile, image_info, 0); - line_cache = malloc(image_info->image_width * image_info->colors * bytespp * (2 * intradius + 1)); + line_cache = malloc(image_info->image_width * image_info->channels * bytespp * (2 * intradius + 1)); if (!line_cache) { DBG(DBG_error, "xsane_blur_image: out of memory\n"); return -1; } - fread(line_cache, image_info->image_width * image_info->colors * bytespp, (2 * intradius + 1), imagefile); + fread(line_cache, image_info->image_width * image_info->channels * bytespp, (2 * intradius + 1), imagefile); for (y = 0; y < image_info->image_height; y++) { @@ -1424,22 +1584,22 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info gtk_main_iteration(); } - for (x = 0; x < image_info->image_width * image_info->colors; x++) + for (x = 0; x < image_info->image_width * image_info->channels; x++) { xmin_flag = xmax_flag = ymin_flag = ymax_flag = TRUE; - xmin = x - intradius * image_info->colors; - xmax = x + intradius * image_info->colors; + xmin = x - intradius * image_info->channels; + xmax = x + intradius * image_info->channels; if (xmin < 0) { - xmin = x % image_info->colors; + xmin = x % image_info->channels; xmin_flag = FALSE; } - if (xmax > image_info->image_width * image_info->colors) + if (xmax > image_info->image_width * image_info->channels) { - xmax = image_info->image_width * image_info->colors; + xmax = image_info->image_width * image_info->channels; xmax_flag = FALSE; } @@ -1467,7 +1627,7 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info { for (sy = ymin+1; sy <= ymax-1 ; sy++) { - val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->colors + xmin]; + val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->channels + xmin]; norm += outer_factor; } } @@ -1476,14 +1636,14 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info { for (sy = ymin+1; sy <= ymax-1 ; sy++) { - val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->colors + xmax]; + val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->channels + xmax]; norm += outer_factor; } } if (ymin_flag) /* integrate over top margin */ { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) + for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels ; sx += image_info->channels) { val += outer_factor * line_cache[sx]; norm += outer_factor; @@ -1492,18 +1652,18 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info if (ymax_flag) /* integrate over bottom margin */ { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) + for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels ; sx += image_info->channels) { - val += outer_factor * line_cache[(ymax-ymin) * image_info->image_width * image_info->colors + sx]; + val += outer_factor * line_cache[(ymax-ymin) * image_info->image_width * image_info->channels + sx]; norm += outer_factor; } } for (sy = ymin+1; sy <= ymax-1; sy++) /* integrate internal square */ { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors; sx+=image_info->colors) + for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels; sx+=image_info->channels) { - val += line_cache[(sy-ymin) * image_info->image_width * image_info->colors + sx]; + val += line_cache[(sy-ymin) * image_info->image_width * image_info->channels + sx]; norm += 1.0; } } @@ -1519,7 +1679,7 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info { for (sy = ymin+1; sy <= ymax-1 ; sy++) { - val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + xmin]; + val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->channels + xmin]; norm += outer_factor; } } @@ -1528,14 +1688,14 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info { for (sy = ymin+1; sy <= ymax-1 ; sy++) { - val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + xmax]; + val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->channels + xmax]; norm += outer_factor; } } if (ymin_flag) /* integrate over top margin */ { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) + for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels ; sx += image_info->channels) { val += outer_factor * line_cache16[sx]; norm += outer_factor; @@ -1544,18 +1704,18 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info if (ymax_flag) /* integrate over bottom margin */ { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) + for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels ; sx += image_info->channels) { - val += outer_factor * line_cache16[(ymax-ymin) * image_info->image_width * image_info->colors + sx]; + val += outer_factor * line_cache16[(ymax-ymin) * image_info->image_width * image_info->channels + sx]; norm += outer_factor; } } for (sy = ymin; sy <= ymax; sy++) /* integrate internal square */ { - for (sx = xmin; sx <= xmax; sx+=image_info->colors) + for (sx = xmin; sx <= xmax; sx+=image_info->channels) { - val += line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + sx]; + val += line_cache16[(sy-ymin) * image_info->image_width * image_info->channels + sx]; norm += 1.0; } } @@ -1581,10 +1741,10 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info if ((y > intradius) && (y < image_info->image_height - intradius)) { - memcpy(line_cache, line_cache + image_info->image_width * image_info->colors * bytespp, - image_info->image_width * image_info->colors * bytespp * 2 * intradius); - fread(line_cache + image_info->image_width * image_info->colors * bytespp * 2 * intradius, - image_info->image_width * image_info->colors * bytespp, 1, imagefile); + memcpy(line_cache, line_cache + image_info->image_width * image_info->channels * bytespp, + image_info->image_width * image_info->channels * bytespp * 2 * intradius); + fread(line_cache + image_info->image_width * image_info->channels * bytespp * 2 * intradius, + image_info->image_width * image_info->channels * bytespp, 1, imagefile); } } @@ -1616,14 +1776,14 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info xsane_write_pnm_header(outfile, image_info, 0); - line_cache = malloc(image_info->image_width * image_info->colors * bytespp * (2 * radius + 1)); + line_cache = malloc(image_info->image_width * image_info->channels * bytespp * (2 * radius + 1)); if (!line_cache) { DBG(DBG_error, "xsane_blur_image: out of memory\n"); return -1; } - fread(line_cache, image_info->image_width * image_info->colors * bytespp, (2 * radius + 1), imagefile); + fread(line_cache, image_info->image_width * image_info->channels * bytespp, (2 * radius + 1), imagefile); for (y = 0; y < image_info->image_height; y++) { @@ -1633,19 +1793,19 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info gtk_main_iteration(); } - for (x = 0; x < image_info->image_width * image_info->colors; x++) + for (x = 0; x < image_info->image_width * image_info->channels; x++) { - xmin = x - radius * image_info->colors; - xmax = x + radius * image_info->colors; + xmin = x - radius * image_info->channels; + xmax = x + radius * image_info->channels; if (xmin < 0) { - xmin = x % image_info->colors; + xmin = x % image_info->channels; } - if (xmax > image_info->image_width * image_info->colors) + if (xmax > image_info->image_width * image_info->channels) { - xmax = image_info->image_width * image_info->colors; + xmax = image_info->image_width * image_info->channels; } ymin = y - radius; @@ -1668,9 +1828,9 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info { for (sy = ymin; sy <= ymax; sy++) { - for (sx = xmin; sx <= xmax; sx+=image_info->colors) + for (sx = xmin; sx <= xmax; sx+=image_info->channels) { - val += line_cache[(sy-ymin) * image_info->image_width * image_info->colors + sx]; + val += line_cache[(sy-ymin) * image_info->image_width * image_info->channels + sx]; count++; } } @@ -1684,9 +1844,9 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info for (sy = ymin; sy <= ymax; sy++) { - for (sx = xmin; sx <= xmax; sx+=image_info->colors) + for (sx = xmin; sx <= xmax; sx+=image_info->channels) { - val += line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + sx]; + val += line_cache16[(sy-ymin) * image_info->image_width * image_info->channels + sx]; count++; } } @@ -1699,10 +1859,10 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info if ((y > radius) && (y < image_info->image_height - radius)) { - memcpy(line_cache, line_cache + image_info->image_width * image_info->colors * bytespp, - image_info->image_width * image_info->colors * bytespp * 2 * radius); - fread(line_cache + image_info->image_width * image_info->colors * bytespp * 2 * radius, - image_info->image_width * image_info->colors * bytespp, 1, imagefile); + memcpy(line_cache, line_cache + image_info->image_width * image_info->channels * bytespp, + image_info->image_width * image_info->channels * bytespp * 2 * radius); + fread(line_cache + image_info->image_width * image_info->channels * bytespp * 2 * radius, + image_info->image_width * image_info->channels * bytespp, 1, imagefile); } } @@ -1734,7 +1894,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in pos0 = ftell(imagefile); /* mark position to skip header */ - bytespp = image_info->colors; + bytespp = image_info->channels; if (image_info->depth > 8) { @@ -2227,7 +2387,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in /* ---------------------------------------------------------------------------------------------------------------------- */ -void xsane_save_ps_create_document_header(FILE *outfile, int pages, int flatdecode) +void xsane_save_ps_create_document_header(FILE *outfile, int pages, int flatedecode) { DBG(DBG_proc, "xsane_save_ps_create_document_header\n"); @@ -2236,7 +2396,7 @@ void xsane_save_ps_create_document_header(FILE *outfile, int pages, int flatdeco SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), SANE_VERSION_MINOR(xsane.sane_backend_versioncode)); fprintf(outfile, "%%%%DocumentData: Clean7Bit\n"); - if (flatdecode) + if (flatedecode) { fprintf(outfile, "%%%%LanguageLevel: 3\n"); } @@ -2288,7 +2448,7 @@ static void xsane_save_ps_create_page_header(FILE *outfile, int page, float width, float height, int paper_left_margin, int paper_bottom_margin, int paper_width, int paper_height, - int paper_orientation, int flatdecode, + int paper_orientation, int flatedecode, GtkProgressBar *progress_bar) { int degree, position_left, position_bottom, box_left, box_bottom, box_right, box_top, depth; @@ -2377,7 +2537,7 @@ static void xsane_save_ps_create_page_header(FILE *outfile, int page, if (depth > 8) { - depth = 8; + depth = 12; } fprintf(outfile, "\n"); @@ -2394,23 +2554,22 @@ static void xsane_save_ps_create_page_header(FILE *outfile, int page, fprintf(outfile, "%d rotate\n", degree); fprintf(outfile, "%d %d translate\n", position_left, position_bottom); fprintf(outfile, "%f %f scale\n", width, height); - fprintf(outfile, "%d %d %d\n", image_info->image_width, image_info->image_height, depth); - fprintf(outfile, "[%d %d %d %d %d %d]\n", image_info->image_width, 0, 0, -image_info->image_height, 0, image_info->image_height); - fprintf(outfile, "currentfile\n"); - fprintf(outfile, "/ASCII85Decode filter\n"); + fprintf(outfile, "<<\n"); + fprintf(outfile, " /ImageType 1\n"); + fprintf(outfile, " /Width %d\n", image_info->image_width); + fprintf(outfile, " /Height %d\n", image_info->image_height); + fprintf(outfile, " /BitsPerComponent %d\n", depth); + fprintf(outfile, " /Decode [0 1 0 1 0 1]\n"); + fprintf(outfile, " /ImageMatrix [%d %d %d %d %d %d]\n", image_info->image_width, 0, 0, -image_info->image_height, 0, image_info->image_height); + fprintf(outfile, " /DataSource currentfile /ASCII85Decode filter"); #ifdef HAVE_LIBZ - if (flatdecode) + if (flatedecode) { - fprintf(outfile, "/FlateDecode filter\n"); + fprintf(outfile, " /FlateDecode filter"); } #endif - - if (image_info->colors == 3) /* what about RGBA here ? */ - { - fprintf(outfile, "false 3 colorimage\n"); - fprintf(outfile, "\n"); - } - else + fprintf(outfile, "\n"); + fprintf(outfile, ">>\n"); { fprintf(outfile, "image\n"); fprintf(outfile, "\n"); @@ -2429,8 +2588,102 @@ static void xsane_save_ps_create_page_trailer(FILE *outfile) /* ---------------------------------------------------------------------------------------------------------------------- */ #ifdef HAVE_LIBZ +/* Utility function for the PDF output */ +static int xsane_write_flatedecode(FILE *outfile, unsigned char *line, int len, int finish) +{ + static unsigned char *cbuf = NULL; + static int cbuflen = 0; + static int linelen = 0; + int outlen; + static int init = 0; + static z_stream s; + int ret; + int flush; + static int count = 0; + + DBG(DBG_proc, "xsane_write_flatedecode\n"); + + if (linelen != len) + { + linelen = len; + if (cbuf != NULL) + { + free(cbuf); + } + /* buffer length = length + 0.1 * length + 12 (mandatory) */ + cbuflen = len + len / 10 + 12; + cbuf = malloc(cbuflen); + } + + if (cbuf == NULL) + { + DBG(DBG_error, "cbuf allocation failed\n"); + return 1; + } + + if (!init) + { + s.zalloc = Z_NULL; + s.zfree = Z_NULL; + s.opaque = Z_NULL; + + ret = deflateInit(&s, Z_DEFAULT_COMPRESSION); + + if (ret != Z_OK) + { + DBG(DBG_error, "deflateInit failed\n"); + free(cbuf); + return 1; + } + + init = 1; + } + + s.avail_in = len; + s.next_in = line; + + do + { + s.avail_out = cbuflen; + s.next_out = cbuf; + + flush = (finish) ? Z_FINISH : Z_NO_FLUSH; + + ret = deflate(&s, flush); + + if (ret == Z_STREAM_ERROR) + { + DBG(DBG_error, "deflate failed\n"); + free(cbuf); + return 1; + } + + outlen = cbuflen - s.avail_out; + + fwrite(cbuf, outlen, 1, outfile); + } while (s.avail_out == 0); + + if (finish) + { + DBG(DBG_info, "xsane_write_flatedecode finished\n"); + deflateEnd(&s); + free(cbuf); + cbuf = NULL; + init = 0; + cbuflen = 0; + linelen = 0; + count = 0; + } + + return 0; +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBZ /* Utility function for the PostScript output */ -static int xsane_write_compressed_a85_flatdecode(FILE *outfile, unsigned char *line, int len, int finish) +static int xsane_write_compressed_a85_flatedecode(FILE *outfile, unsigned char *line, int len, int finish) { static unsigned char *cbuf = NULL; static int cbuflen = 0; @@ -2446,7 +2699,7 @@ static int xsane_write_compressed_a85_flatdecode(FILE *outfile, unsigned char *l static unsigned char a85block[6] = {0, 0, 0, 0, 0, 0}; static int count = 0; - DBG(DBG_proc, "xsane_write_compressed_a85_flatdecode\n"); + DBG(DBG_proc, "xsane_write_compressed_a85_flatedecode\n"); if (linelen != len) { @@ -2741,7 +2994,91 @@ static int xsane_write_compressed_a85(FILE *outfile, unsigned char *line, int le /* ---------------------------------------------------------------------------------------------------------------------- */ -static int xsane_save_ps_pdf_bw(FILE *outfile, FILE *imagefile, Image_info *image_info, int flatdecode, GtkProgressBar *progress_bar, int *cancel_save) +#ifdef HAVE_LIBLCMS +static int xsane_write_CSA(FILE *outfile, char *input_profile, int intent) +{ + cmsHPROFILE hProfile; + size_t n; + char* buffer; + + hProfile = cmsOpenProfileFromFile(input_profile, "r"); + if (!hProfile) + { + return -1; + } + + n = cmsGetPostScriptCSA(hProfile, intent, NULL, 0); + if (n == 0) + { + return -2; + } + + buffer = (char*) malloc(n + 1); + if (!buffer) + { + return -3; + } + + cmsGetPostScriptCSA(hProfile, intent, buffer, n); + buffer[n] = 0; + + fprintf(outfile, "%s", buffer); + fprintf(outfile, "setcolorspace\n"); + + free(buffer); + cmsCloseProfile(hProfile); + + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_write_CRD(FILE *outfile, char *output_profile, int intent, int blackpointcompensation) +{ + cmsHPROFILE hProfile; + size_t n; + char* buffer; + DWORD flags = cmsFLAGS_NODEFAULTRESOURCEDEF; + + hProfile = cmsOpenProfileFromFile(output_profile, "r"); + if (!hProfile) + { + return -1; + } + + if (blackpointcompensation) + { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + + n = cmsGetPostScriptCRDEx(hProfile, intent, flags, NULL, 0); + if (n == 0) + { + return -2; + } + + buffer = (char*) malloc(n + 1); + if (!buffer) + { + return -3; + } + + cmsGetPostScriptCRDEx(hProfile, intent, flags, buffer, n); + buffer[n] = 0; + + fprintf(outfile, "%s", buffer); + fprintf(outfile, "setcolorrendering\n"); + + free(buffer); + cmsCloseProfile(hProfile); + + return 0; +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_save_ps_pdf_bw(FILE *outfile, FILE *imagefile, Image_info *image_info, int ascii85decode, int flatedecode, GtkProgressBar *progress_bar, int *cancel_save) { int x, y; int bytes_per_line = (image_info->image_width+7)/8; @@ -2778,15 +3115,26 @@ static int xsane_save_ps_pdf_bw(FILE *outfile, FILE *imagefile, Image_info *imag line[x] = fgetc(imagefile) ^ 255; } + if (ascii85decode) + { #ifdef HAVE_LIBZ - if (flatdecode) + if (flatedecode) + { + ret = xsane_write_compressed_a85_flatedecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); + } + else +#endif + { + ret = xsane_write_compressed_a85(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); + } + } + else if (flatedecode) { - ret = xsane_write_compressed_a85_flatdecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); + ret = xsane_write_flatedecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); } else -#endif { - ret = xsane_write_compressed_a85(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); + fwrite(line, bytes_per_line, 1, outfile); } if ((ret != 0) || (ferror(outfile))) @@ -2822,11 +3170,15 @@ static int xsane_save_ps_pdf_bw(FILE *outfile, FILE *imagefile, Image_info *imag /* ---------------------------------------------------------------------------------------------------------------------- */ -static int xsane_save_ps_pdf_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, int flatdecode, GtkProgressBar *progress_bar, int *cancel_save) +static int xsane_save_ps_pdf_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, int ascii85decode, int flatedecode, cmsHTRANSFORM hTransform, int embed_scanner_icm_profile, GtkProgressBar *progress_bar, int *cancel_save) { - int x, y; - int ret; - unsigned char *line; + int x, y; + int ret; + unsigned char *line; +#ifdef HAVE_LIBLCMS + unsigned char *line_raw = NULL; +#endif + DBG(DBG_proc, "xsane_save_ps_pdf_gray\n"); @@ -2865,15 +3217,26 @@ static int xsane_save_ps_pdf_gray(FILE *outfile, FILE *imagefile, Image_info *im } } + if (ascii85decode) + { #ifdef HAVE_LIBZ - if (flatdecode) + if (flatedecode) + { + ret = xsane_write_compressed_a85_flatedecode(outfile, line, image_info->image_width, (y == image_info->image_height - 1)); + } + else +#endif + { + ret = xsane_write_compressed_a85(outfile, line, image_info->image_width, (y == image_info->image_height - 1)); + } + } + else if (flatedecode) { - ret = xsane_write_compressed_a85_flatdecode(outfile, line, image_info->image_width, (y == image_info->image_height - 1)); + ret = xsane_write_flatedecode(outfile, line, image_info->image_width, (y == image_info->image_height - 1)); } else -#endif { - ret = xsane_write_compressed_a85(outfile, line, image_info->image_width, (y == image_info->image_height - 1)); + fwrite(line, image_info->image_width, 1, outfile); } if ((ret != 0) || (ferror(outfile))) @@ -2915,28 +3278,106 @@ static int xsane_save_ps_pdf_gray(FILE *outfile, FILE *imagefile, Image_info *im /* ---------------------------------------------------------------------------------------------------------------------- */ -static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *image_info, int flatdecode, GtkProgressBar *progress_bar, int *cancel_save) +static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *image_info, int ascii85decode, int flatedecode, + cmsHTRANSFORM hTransform, int do_transform, + GtkProgressBar *progress_bar, int *cancel_save) { int x, y; int ret; - unsigned char *line, *linep; + unsigned char *line = NULL, *linep = NULL, *line16 = NULL; + int bytes_per_line; + int bytes_per_line16 = 0; +#ifdef HAVE_LIBLCMS + unsigned char *line_raw = NULL; +#endif DBG(DBG_proc, "xsane_save_ps_pdf_color\n"); *cancel_save = 0; - line = (unsigned char *) malloc(image_info->image_width * 3); + if (image_info->depth > 8) /* reduce 16 bit images to 12 bit */ + { + bytes_per_line16 = image_info->image_width * 3 * 2; + + bytes_per_line = (image_info->image_width/2) * 3 * 3; + if (image_info->image_width & 1) + { + bytes_per_line += 5; + } + + DBG(DBG_info, "bytes_per_line16 = %d\n", bytes_per_line16); + DBG(DBG_info, "bytes_per_line = %d\n", bytes_per_line); + + line16 = (unsigned char *) malloc(bytes_per_line16); + + if (line16 == NULL) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s malloc for line16 failed", ERR_DURING_SAVE); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + return (*cancel_save); + } + DBG(DBG_info, "line16 allocated\n"); + } + else + { + bytes_per_line = image_info->image_width * 3; + bytes_per_line16 = image_info->image_width * 3; + DBG(DBG_info, "bytes_per_line = %d\n", bytes_per_line); + } + + line = (unsigned char *) malloc(bytes_per_line); if (line == NULL) { char buf[TEXTBUFSIZE]; - snprintf(buf, sizeof(buf), "%s malloc failed", ERR_DURING_SAVE); + snprintf(buf, sizeof(buf), "%s malloc for line failed", ERR_DURING_SAVE); DBG(DBG_error, "%s\n", buf); xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + + if (line16) + { + free(line16); + } + *cancel_save = 1; return (*cancel_save); } + DBG(DBG_info, "line allocated\n"); + +#ifdef HAVE_LIBLCMS + if (do_transform && (hTransform != NULL)) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + line_raw = (unsigned char *) malloc(bytes_per_line16); + + if (line_raw == NULL) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s malloc for line_raw failed", ERR_DURING_SAVE); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + + free(line); + + if (line16) + { + free(line16); + } + + *cancel_save = 1; + return (*cancel_save); + } + + DBG(DBG_info, "line_raw allocated\n"); + } +#endif for (y = 0; y < image_info->image_height; y++) { @@ -2948,39 +3389,101 @@ static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *i linep = line; - if (image_info->depth > 8) /* reduce 16 bit images */ + if (image_info->depth > 8) /* reduce 16 bit images to 12 bit */ { - guint16 val; +#ifdef HAVE_LIBLCMS + if (do_transform && (hTransform != NULL)) + { + fread(line_raw, 6, image_info->image_width, imagefile); + cmsDoTransform(hTransform, line_raw, line16, image_info->image_width); + } + else +#endif + { + fread(line16, 6, image_info->image_width, imagefile); + } - for (x = 0; x < image_info->image_width; x++) +#if __BYTE_ORDER == __LITTLE_ENDIAN + for (x = 0; x < image_info->image_width; x=x+2) { - fread(&val, 2, 1, imagefile); - *linep++ = val/256; - fread(&val, 2, 1, imagefile); - *linep++ = val/256; - fread(&val, 2, 1, imagefile); - *linep++ = val/256; + *linep++ = line16[6*x+1]; /* red high+middle */ + *linep++ = (line16[6*x+0] & 240) | (line16[6*x+3] >> 4); /* red low | green high */ + *linep++ = ((line16[6*x+3] & 15) << 4) | ((line16[6*x+2] & 240) >> 4); /* green middle | green low */ + + *linep++ = line16[6*x+5]; /* blue high+middle */ + + if (x == image_info->image_width-1) + { + *linep++ = (line16[6*x+4] & 240); /* blue low */ + break; + } + + *linep++ = (line16[6*x+4] & 240) | (line16[6*x+7] >> 4); /* blue low | red high */ + *linep++ = ((line16[6*x+7] & 15) << 4) | ((line16[6*x+6] & 240) >> 4); /* red middle | red low */ + + *linep++ = line16[6*x+9]; /* green high+middle */ + *linep++ = (line16[6*x+8] & 240) | (line16[6*x+11] >> 4); /* green low | blue high */ + *linep++ = ((line16[6*x+11] & 15) << 4) | ((line16[6*x+10] & 240) >> 4); /* blue middle | blue low */ } +#else + for (x = 0; x < image_info->image_width; x=x+2) + { + *linep++ = line16[6*x+0]; /* red high+middle */ + *linep++ = (line16[6*x+1] & 240) | (line16[6*x+2] >> 4); /* red low | green high */ + *linep++ = ((line16[6*x+2] & 15) << 4) | ((line16[6*x+3] & 240) >> 4); /* green middle | green low */ + + *linep++ = line16[6*x+4]; /* blue high+middle */ + + if (x == image_info->image_width-1) + { + *linep++ = (line16[6*x+5] & 240); /* blue low */ + break; + } + + *linep++ = (line16[6*x+5] & 240) | (line16[6*x+6] >> 4); /* blue low | red high */ + *linep++ = ((line16[6*x+6] & 15) << 4) | ((line16[6*x+7] & 240) >> 4); /* red middle | red low */ + + *linep++ = line16[6*x+8]; /* green high+middle */ + *linep++ = (line16[6*x+9] & 240) | (line16[6*x+10] >> 4); /* green low | blue high */ + *linep++ = ((line16[6*x+10] & 15) << 4) | ((line16[6*x+11] & 240) >> 4); /* blue middle | blue low */ + } +#endif } else /* 8 bits/sample */ { - for (x = 0; x < image_info->image_width; x++) +#ifdef HAVE_LIBLCMS + if (do_transform && (hTransform != NULL)) { - *linep++ = fgetc(imagefile); - *linep++ = fgetc(imagefile); - *linep++ = fgetc(imagefile); + fread(line_raw, 3, image_info->image_width, imagefile); + cmsDoTransform(hTransform, line_raw, line, image_info->image_width); + } + else +#endif + { + fread(line, 3, image_info->image_width, imagefile); } } + if (ascii85decode) + { #ifdef HAVE_LIBZ - if (flatdecode) + if (flatedecode) + { + ret = xsane_write_compressed_a85_flatedecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); + } + else +#endif + { + ret = xsane_write_compressed_a85(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); + } + } + else if (flatedecode) { - ret = xsane_write_compressed_a85_flatdecode(outfile, line, (image_info->image_width * 3), (y == image_info->image_height - 1)); + ret = xsane_write_flatedecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); } else -#endif { - ret = xsane_write_compressed_a85(outfile, line, (image_info->image_width * 3), (y == image_info->image_height - 1)); + fwrite(line, bytes_per_line, 1, outfile); } if ((ret != 0) || (ferror(outfile))) @@ -3009,6 +3512,18 @@ static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *i } } +#ifdef HAVE_LIBLCMS + if (line_raw) + { + free(line_raw); + } +#endif + + if (line16) + { + free(line16); + } + free(line); return (*cancel_save); @@ -3019,7 +3534,8 @@ static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *i int xsane_save_ps_page(FILE *outfile, int page, FILE *imagefile, Image_info *image_info, float width, float height, int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation, - int flatdecode, + int flatedecode, + cmsHTRANSFORM hTransform, int do_transform, GtkProgressBar *progress_bar, int *cancel_save) { DBG(DBG_proc, "xsane_save_ps_page\n"); @@ -3027,23 +3543,23 @@ int xsane_save_ps_page(FILE *outfile, int page, xsane_save_ps_create_page_header(outfile, page, image_info, width, height, paper_left_margin, paper_bottom_margin, paperwidth, paperheight, paper_orientation, - flatdecode, + flatedecode, progress_bar); - if (image_info->colors == 1) /* lineart, halftone, grayscale */ + if (image_info->channels == 1) /* lineart, halftone, grayscale */ { if (image_info->depth == 1) /* lineart, halftone */ { - xsane_save_ps_pdf_bw(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); + xsane_save_ps_pdf_bw(outfile, imagefile, image_info, TRUE, flatedecode, progress_bar, cancel_save); } else /* grayscale */ { - xsane_save_ps_pdf_gray(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); + xsane_save_ps_pdf_gray(outfile, imagefile, image_info, TRUE, flatedecode, hTransform, do_transform, progress_bar, cancel_save); } } else /* color RGB */ { - xsane_save_ps_pdf_color(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); + xsane_save_ps_pdf_color(outfile, imagefile, image_info, TRUE, flatedecode, hTransform, do_transform, progress_bar, cancel_save); } xsane_save_ps_create_page_trailer(outfile); @@ -3065,19 +3581,46 @@ int xsane_save_ps_page(FILE *outfile, int page, int xsane_save_ps(FILE *outfile, FILE *imagefile, Image_info *image_info, float width, float height, int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation, - int flatdecode, + int flatedecode, + cmsHTRANSFORM hTransform, int apply_ICM_profile, int embed_CSA, char *CSA_profile, + int embed_CRD, char *CRD_profile, int blackpointcompensation, int intent, GtkProgressBar *progress_bar, int *cancel_save) { DBG(DBG_proc, "xsane_save_ps\n"); *cancel_save = 0; - xsane_save_ps_create_document_header(outfile, 1 /* pages */, flatdecode); + xsane_save_ps_create_document_header(outfile, 1 /* pages */, flatedecode); + +#ifdef HAVE_LIBLCMS + if ((apply_ICM_profile) && (embed_CRD)) + { + xsane_write_CRD(outfile, CRD_profile, intent, blackpointcompensation); /* write printer profile to ps file */ + } + + + if ((apply_ICM_profile) && (embed_CSA)) + { + xsane_write_CSA(outfile, CSA_profile, intent); /* write scanner profile to ps file */ + } + else +#endif + { + if (image_info->channels == 1) /* lineart, halftone, grayscale */ + { + fprintf(outfile, "/DeviceGray setcolorspace\n"); + } + else + { + fprintf(outfile, "/DeviceRGB setcolorspace\n"); + } + } xsane_save_ps_page(outfile, 1 /* page */, imagefile, image_info, width, height, paper_left_margin, paper_bottom_margin, paperwidth, paperheight, paper_orientation, - flatdecode, + flatedecode, + hTransform, (apply_ICM_profile && (!embed_CSA) && (!embed_CRD)) /* do_transform */, progress_bar, cancel_save); xsane_save_ps_create_document_trailer(outfile, 0 /* we defined pages at beginning */); @@ -3097,7 +3640,93 @@ int xsane_save_ps(FILE *outfile, FILE *imagefile, Image_info *image_info, float /* ---------------------------------------------------------------------------------------------------------------------- */ -void xsane_save_pdf_create_document_header(FILE *outfile, struct pdf_xref *xref, int pages, int flatdecode) +static int xsane_embed_pdf_icm_profile(FILE *outfile, struct pdf_xref *xref, char *icm_filename, int flatedecode, int icc_object) +{ + FILE *icm_profile; + size_t size, embed_len; + unsigned char *embed_buffer; + int ret; + + DBG(DBG_proc, "xsane_embed_pdf_icm_profile(%s)\n", icm_filename); + + icm_profile = fopen(icm_filename, "rb"); + if (icm_profile == NULL) + { + DBG(DBG_error, "Could not open ICM profile \"%s\" for reading\n", icm_filename); + return -1; + } + + fseek(icm_profile, 0, SEEK_END); + size = ftell(icm_profile); + fseek(icm_profile, 0, SEEK_SET); + + embed_buffer = malloc(size + 1); + if (embed_buffer) + { + xref->obj[icc_object] = ftell(outfile); + fprintf(outfile, "%d 0 obj\n", icc_object); + fprintf(outfile, " << /N 3\n"); /* 3 channels */ + fprintf(outfile, " /Alternate /DeviceRGB\n"); +#ifdef HAVE_LIBZ + if (flatedecode) + { + fprintf(outfile, " /Filter /FlateDecode\n"); + } +#endif + + fprintf(outfile, " /Length >>\n"); + + /* Position of the stream length, to be written later on */ + xref->slenp = ftell(outfile) - 15; + + fprintf(outfile, "stream\n"); + + /* Start of the stream data */ + xref->slen = ftell(outfile); + + embed_len = fread(embed_buffer, 1, size, icm_profile); + embed_buffer[embed_len] = 0; + fclose(icm_profile); + +#ifdef HAVE_LIBZ + if (flatedecode) + { + ret = xsane_write_flatedecode(outfile, embed_buffer, size, TRUE); + } + else +#endif + { + fwrite(embed_buffer, size, 1, outfile); + ret = 0; + } + + /* Go back and write the length of the stream */ + xref->slen = ftell(outfile) - xref->slen; + fseek(outfile, xref->slenp, SEEK_SET); + fprintf(outfile, "%lu", xref->slen); + fseek(outfile, 0L, SEEK_END); + + fprintf(outfile, "endstream\n"); + fprintf(outfile, "endobj\n"); + fprintf(outfile, "\n"); + + free(embed_buffer); + } + else + { + DBG(DBG_info, "Embedding ICM profile \"%s\" to PDF: no mem\n", icm_filename); + fclose(icm_profile); + return -2; + } + + + DBG(DBG_info, "Embedding ICM profile \"%s\" to PDF file retuned with status %d\n", icm_filename, ret); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_pdf_create_document_header(FILE *outfile, struct pdf_xref *xref, int pages, int flatedecode) { int i; @@ -3126,7 +3755,7 @@ void xsane_save_pdf_create_document_header(FILE *outfile, struct pdf_xref *xref, fprintf(outfile, " /Kids [\n"); for (i=0; i < pages; i++) { - fprintf(outfile, " %d 0 R\n", i * 2 + 4); + fprintf(outfile, " %d 0 R\n", i * 2 + 6); } fprintf(outfile, " ]\n"); fprintf(outfile, " /Count %d\n", pages); @@ -3143,7 +3772,8 @@ static void xsane_save_pdf_create_page_header(FILE *outfile, struct pdf_xref *xr float width, float height, int paper_left_margin, int paper_bottom_margin, int paper_width, int paper_height, - int paper_orientation, int flatdecode, + int paper_orientation, + int flatedecode, int icc_object, GtkProgressBar *progress_bar) { int position_left, position_bottom, box_left, box_bottom, box_right, box_top, depth; @@ -3231,26 +3861,26 @@ static void xsane_save_pdf_create_page_header(FILE *outfile, struct pdf_xref *xr depth = image_info->depth; - if (depth > 8) + if (depth > 8) /* PDF does not support 16bits/sample in a standard image */ { depth = 8; } - xref->obj[page * 2 + 2] = ftell(outfile); - fprintf(outfile, "%d 0 obj\n", page * 2 + 2); + xref->obj[page * 2 + 4] = ftell(outfile); + fprintf(outfile, "%d 0 obj\n", page * 2 + 4); fprintf(outfile, " << /Type /Page\n"); fprintf(outfile, " /Parent 3 0 R\n"); fprintf(outfile, " /MediaBox [%d %d %d %d]\n", box_left, box_bottom, box_right, box_top); - fprintf(outfile, " /Contents %d 0 R\n", page * 2 + 3); - fprintf(outfile, " /Resources << /ProcSet %d 0 R >>\n", page * 2 + 4); + fprintf(outfile, " /Contents %d 0 R\n", page * 2 + 5); + fprintf(outfile, " /Resources << /ProcSet %d 0 R >>\n", page * 2 + 6); fprintf(outfile, " >>\n"); fprintf(outfile, "endobj\n"); fprintf(outfile, "\n"); /* Offset of object 5, for xref */ - xref->obj[page * 2 + 3] = ftell(outfile); + xref->obj[page * 2 + 5] = ftell(outfile); - fprintf(outfile, "%d 0 obj\n", page * 2 + 3); + fprintf(outfile, "%d 0 obj\n", page * 2 + 5); fprintf(outfile, " << /Length >>\n"); /* Position of the stream length, to be written later on */ @@ -3269,9 +3899,17 @@ static void xsane_save_pdf_create_page_header(FILE *outfile, struct pdf_xref *xr fprintf(outfile, " /W %d\n", image_info->image_width); fprintf(outfile, " /H %d\n", image_info->image_height); - if (image_info->colors == 3) /* what about RGBA here ? */ + if ((icc_object) && (image_info->depth != 1)) + { + fprintf(outfile, " /ColorSpace [/ICCBased %d 0 R]\n", icc_object); + } + + if (image_info->channels == 3) /* what about RGBA here ? */ { - fprintf(outfile, " /CS /RGB\n"); + if (icc_object == 0) + { + fprintf(outfile, " /CS /RGB\n"); + } fprintf(outfile, " /BPC %d\n", depth); } else if (image_info->depth == 1) /* BW */ @@ -3281,22 +3919,20 @@ static void xsane_save_pdf_create_page_header(FILE *outfile, struct pdf_xref *xr } else /* gray */ { - fprintf(outfile, " /CS /G\n"); - fprintf(outfile, " /BPC 8\n"); + if (icc_object == 0) + { + fprintf(outfile, " /CS /G\n"); + } + fprintf(outfile, " /BPC %d\n", depth); } #ifdef HAVE_LIBZ - if (flatdecode) - { - fprintf(outfile, " /F [/A85 /FlateDecode]\n"); - } - else + if (flatedecode) { - fprintf(outfile, " /F /A85\n"); + fprintf(outfile, " /F /FlateDecode\n"); } -#else - fprintf(outfile, " /F /A85\n"); #endif + fprintf(outfile, "ID\n"); } @@ -3311,17 +3947,17 @@ void xsane_save_pdf_create_document_trailer(FILE *outfile, struct pdf_xref *xref /* PDF document trailer */ /* Offset of object 6, for xref */ - xref->obj[pages * 2 + 4] = ftell(outfile); + xref->obj[pages * 2 + 6] = ftell(outfile); - fprintf(outfile, "%d 0 obj\n", pages * 2 + 4); + fprintf(outfile, "%d 0 obj\n", pages * 2 + 6); fprintf(outfile, " [/PDF]\n"); fprintf(outfile, "endobj\n"); fprintf(outfile, "\n"); /* Offset of object 7, for xref */ - xref->obj[pages * 2 + 5] = ftell(outfile); + xref->obj[pages * 2 + 7] = ftell(outfile); - fprintf(outfile, "%d 0 obj\n", pages * 2 + 5); + fprintf(outfile, "%d 0 obj\n", pages * 2 + 7); fprintf(outfile, " << /Title (XSane scanned image)\n"); fprintf(outfile, " /Creator (XSane version %s (sane %d.%d) - by Oliver Rauch)\n", VERSION, @@ -3342,19 +3978,19 @@ void xsane_save_pdf_create_document_trailer(FILE *outfile, struct pdf_xref *xref xref->xref = ftell(outfile); fprintf(outfile, "xref\n"); - fprintf(outfile, "0 %d\n", pages * 2 + 6); + fprintf(outfile, "0 %d\n", pages * 2 + 8); fprintf(outfile, "0000000000 65535 f \n"); - for (i=1; i <= pages * 2 + 5; i++) + for (i=1; i <= pages * 2 + 7; i++) { fprintf(outfile, "%010lu 00000 n \n", xref->obj[i]); } fprintf(outfile, "\n"); fprintf(outfile, "trailer\n"); - fprintf(outfile, " << /Size %d\n", pages * 2 + 6); + fprintf(outfile, " << /Size %d\n", pages * 2 + 8); fprintf(outfile, " /Root 1 0 R\n"); - fprintf(outfile, " /Info %d 0 R\n", pages * 2 + 5); + fprintf(outfile, " /Info %d 0 R\n", pages * 2 + 7); fprintf(outfile, " >>\n"); fprintf(outfile, "startxref\n"); fprintf(outfile, "%lu\n", xref->xref); @@ -3370,7 +4006,7 @@ static void xsane_save_pdf_create_page_trailer(FILE *outfile, struct pdf_xref *x fprintf(outfile, "Q\n"); /* Go back and write the length of the stream */ - xref->slen = ftell(outfile) - xref->slen - 1; + xref->slen = ftell(outfile) - xref->slen; /* we had a "-1" at the end but I do not understand the reason for -1, without looks better */ fseek(outfile, xref->slenp, SEEK_SET); fprintf(outfile, "%lu", xref->slen); fseek(outfile, 0L, SEEK_END); @@ -3385,7 +4021,8 @@ static void xsane_save_pdf_create_page_trailer(FILE *outfile, struct pdf_xref *x int xsane_save_pdf_page(FILE *outfile, struct pdf_xref *xref, int page, FILE *imagefile, Image_info *image_info, float width, float height, int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation, - int flatdecode, + int flatedecode, + cmsHTRANSFORM hTransform, int do_transform, int icc_object, GtkProgressBar *progress_bar, int *cancel_save) { @@ -3394,23 +4031,23 @@ int xsane_save_pdf_page(FILE *outfile, struct pdf_xref *xref, int page, xsane_save_pdf_create_page_header(outfile, xref, page, image_info, width, height, paper_left_margin, paper_bottom_margin, paperwidth, paperheight, paper_orientation, - flatdecode, + flatedecode, icc_object, progress_bar); - if (image_info->colors == 1) /* lineart, halftone, grayscale */ + if (image_info->channels == 1) /* lineart, halftone, grayscale */ { if (image_info->depth == 1) /* lineart, halftone */ { - xsane_save_ps_pdf_bw(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); + xsane_save_ps_pdf_bw(outfile, imagefile, image_info, FALSE, flatedecode, progress_bar, cancel_save); } else /* grayscale */ { - xsane_save_ps_pdf_gray(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); + xsane_save_ps_pdf_gray(outfile, imagefile, image_info, FALSE, flatedecode, hTransform, do_transform, progress_bar, cancel_save); } } else /* color RGB */ { - xsane_save_ps_pdf_color(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); + xsane_save_ps_pdf_color(outfile, imagefile, image_info, FALSE, flatedecode, hTransform, do_transform, progress_bar, cancel_save); } xsane_save_pdf_create_page_trailer(outfile, xref); @@ -3432,21 +4069,33 @@ int xsane_save_pdf_page(FILE *outfile, struct pdf_xref *xref, int page, int xsane_save_pdf(FILE *outfile, FILE *imagefile, Image_info *image_info, float width, float height, int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation, - int flatdecode, + int flatedecode, + cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, GtkProgressBar *progress_bar, int *cancel_save) { - struct pdf_xref xref; + struct pdf_xref xref; + int icc_object = 0; DBG(DBG_proc, "xsane_save_pdf\n"); *cancel_save = 0; - xsane_save_pdf_create_document_header(outfile, &xref, 1, flatdecode); + xsane_save_pdf_create_document_header(outfile, &xref, 1, flatedecode); + + xref.obj[4] = ftell(outfile); + xref.obj[5] = ftell(outfile); + + if (apply_ICM_profile && (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE)) + { + icc_object = 4; + xsane_embed_pdf_icm_profile(outfile, &xref, image_info->icm_profile, flatedecode, icc_object); + } xsane_save_pdf_page(outfile, &xref, 1, imagefile, image_info, width, height, paper_left_margin, paper_bottom_margin, paperwidth, paperheight, paper_orientation, - flatdecode, + flatedecode, + hTransform, apply_ICM_profile && ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE)) /* do_transform */, icc_object, progress_bar, cancel_save); xsane_save_pdf_create_document_trailer(outfile, &xref, 1); @@ -3465,8 +4114,8 @@ int xsane_save_pdf(FILE *outfile, FILE *imagefile, Image_info *image_info, float } /* ---------------------------------------------------------------------------------------------------------------------- */ -#ifdef HAVE_LIBJPEG +#ifdef HAVE_LIBJPEG typedef struct { struct jpeg_error_mgr pub;/* "public" fields */ @@ -3494,7 +4143,110 @@ static void xsane_jpeg_error_exit(j_common_ptr cinfo) *xsane_jpeg_error_mgr_data->cancel_save = 1; } -int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int quality, GtkProgressBar *progress_bar, int *cancel_save) +/* ---------------------------------------------------------- */ + +#ifdef HAVE_LIBLCMS +static void xsane_jpeg_write_icm_profile(j_compress_ptr cinfo_ptr, const JOCTET *icm_data_ptr, unsigned int icm_data_len) +{ +#define ICM_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICM */ +#define ICM_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ +#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ +#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICM_OVERHEAD_LEN) + + unsigned int num_markers; /* total number of markers we'll write */ + int cur_marker = 1; /* per spec, counting starts at 1 */ + unsigned int length; /* number of bytes to write in this marker */ + + /* Calculate the number of markers we'll need, rounding up of course */ + num_markers = icm_data_len / MAX_DATA_BYTES_IN_MARKER; + if (num_markers * MAX_DATA_BYTES_IN_MARKER != icm_data_len) + { + num_markers++; + } + + while (icm_data_len > 0) + { + length = icm_data_len; /* length of profile to put in this marker */ + if (length > MAX_DATA_BYTES_IN_MARKER) + { + length = MAX_DATA_BYTES_IN_MARKER; + } + icm_data_len -= length; + + /* Write the JPEG marker header (APP2 code and marker length) */ + jpeg_write_m_header(cinfo_ptr, ICM_MARKER, (unsigned int) (length + ICM_OVERHEAD_LEN)); + + /* Write the marker identifying string "ICC_PROFILE" (null-terminated). + * We code it in this less-than-transparent way so that the code works + * even if the local character set is not ASCII. + */ + jpeg_write_m_byte(cinfo_ptr, 0x49); + jpeg_write_m_byte(cinfo_ptr, 0x43); + jpeg_write_m_byte(cinfo_ptr, 0x43); + jpeg_write_m_byte(cinfo_ptr, 0x5F); + jpeg_write_m_byte(cinfo_ptr, 0x50); + jpeg_write_m_byte(cinfo_ptr, 0x52); + jpeg_write_m_byte(cinfo_ptr, 0x4F); + jpeg_write_m_byte(cinfo_ptr, 0x46); + jpeg_write_m_byte(cinfo_ptr, 0x49); + jpeg_write_m_byte(cinfo_ptr, 0x4C); + jpeg_write_m_byte(cinfo_ptr, 0x45); + jpeg_write_m_byte(cinfo_ptr, 0x0); + + /* Add the sequencing info */ + jpeg_write_m_byte(cinfo_ptr, cur_marker); + jpeg_write_m_byte(cinfo_ptr, (int) num_markers); + + /* Add the profile data */ + while (length--) + { + jpeg_write_m_byte(cinfo_ptr, *icm_data_ptr); + icm_data_ptr++; + } + cur_marker++; + } +} + +/* ---------------------------------------------------------- */ + +static void xsane_jpeg_embed_scanner_icm_profile(j_compress_ptr cinfo_ptr, const char *icm_filename) +{ + FILE *icm_profile; + size_t size, embed_len; + LPBYTE embed_buffer; + + DBG(DBG_proc, "xsane_jpeg_embed_scanner_icm_profile(%s)\n", icm_filename); + + icm_profile = fopen(icm_filename, "rb"); + if (icm_profile == NULL) + { + return; + } + + fseek(icm_profile, 0, SEEK_END); + size = ftell(icm_profile); + fseek(icm_profile, 0, SEEK_SET); + + embed_buffer = (LPBYTE) malloc(size + 1); + if (embed_buffer) + { + embed_len = fread(embed_buffer, 1, size, icm_profile); + fclose(icm_profile); + embed_buffer[embed_len] = 0; + + xsane_jpeg_write_icm_profile(cinfo_ptr, embed_buffer, embed_len); + free(embed_buffer); + + DBG(DBG_info, "ICM profile %s has been embedded to jpeg file\n", icm_filename); + } +} +#endif + +/* ---------------------------------------------------------- */ + +int xsane_save_jpeg(FILE *outfile, int quality, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, + GtkProgressBar *progress_bar, int *cancel_save) { unsigned char *data; char buf[TEXTBUFSIZE]; @@ -3504,12 +4256,15 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int struct jpeg_compress_struct cinfo; xsane_jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; +#ifdef HAVE_LIBLCMS + unsigned char *data_raw = NULL; +#endif DBG(DBG_proc, "xsane_save_jpeg\n"); *cancel_save = 0; - if (image_info->colors == 3) + if (image_info->channels == 3) { components = 3; } @@ -3528,6 +4283,24 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int return -1; /* error */ } +#ifdef HAVE_LIBLCMS + if (apply_ICM_profile && (cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL)) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info->image_width * components * bytespp); + + if (!data_raw) + { + free(data); + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + } +#endif + cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = xsane_jpeg_error_exit; jerr.cancel_save = cancel_save; @@ -3537,7 +4310,7 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int cinfo.image_width = image_info->image_width; cinfo.image_height = image_info->image_height; cinfo.input_components = components; - if (image_info->colors == 3) + if (image_info->channels == 3) { cinfo.in_color_space = JCS_RGB; } @@ -3560,6 +4333,20 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int jpeg_start_compress(&cinfo, TRUE); +#ifdef HAVE_LIBLCMS + if (apply_ICM_profile) + { + if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) + { + xsane_jpeg_embed_scanner_icm_profile(&cinfo, image_info->icm_profile); + } + else if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS) + { + xsane_jpeg_embed_scanner_icm_profile(&cinfo, preferences.working_color_space_icm_profile); + } + } +#endif + for (y = 0; y < image_info->image_height; y++) { gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); @@ -3596,7 +4383,18 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int else if (image_info->depth > 8) /* jpeg does not support 16 bits/sample, so we reduce it at first */ { guint16 *data16 = (guint16 *) data; - fread(data, components * 2, image_info->image_width, imagefile); +#ifdef HAVE_LIBLCMS + if (apply_ICM_profile && (cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL)) + { + fread(data_raw, components * 2, image_info->image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, components * 2, image_info->image_width, imagefile); + } + for (x = 0; x < image_info->image_width * components; x++) { data[x] = data16[x] / 256; @@ -3605,7 +4403,17 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int } else /* 8 bits/sample */ { - fread(data, components, image_info->image_width, imagefile); +#ifdef HAVE_LIBLCMS + if (apply_ICM_profile && (cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL)) + { + fread(data_raw, components, image_info->image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, components, image_info->image_width, imagefile); + } } row_pointer[0] = data; @@ -3619,6 +4427,13 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int } jpeg_finish_compress(&cinfo); + +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif free(data); return (*cancel_save); @@ -3628,9 +4443,58 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int /* ---------------------------------------------------------------------------------------------------------------------- */ #ifdef HAVE_LIBTIFF +#ifdef HAVE_LIBLCMS +static void xsane_tiff_embed_scanner_icm_profile(TIFF *tiffile, const char *icm_filename) +{ + FILE *icm_profile; + size_t size; + char *icm_profile_buffer; + + DBG(DBG_proc, "xsane_tiff_embed_scanner_icm_profile(%s)\n", icm_filename); + if((icm_profile = fopen(icm_filename, "rb"))) + { + fseek(icm_profile, 0, SEEK_END); + size = ftell(icm_profile); + fseek(icm_profile, 0, SEEK_SET); + + icm_profile_buffer = (char *) malloc(size + 1); + + if (icm_profile_buffer) + { + if (fread(icm_profile_buffer, 1, size, icm_profile) == size) + { + icm_profile_buffer[size] = 0; + + TIFFSetField(tiffile, TIFFTAG_ICCPROFILE, size, icm_profile_buffer); + } + else + { + DBG(DBG_error, "Can not read ICM profile data\n"); + } + + free(icm_profile_buffer); + } + else + { + DBG(DBG_error, "Can not get enogh memory for ICM profile\n"); + } + + + fclose(icm_profile); + } + else + { + DBG(DBG_error, "Can not embed ICM profile\n"); + } +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + /* pages = 0 => single page tiff, page = 0 */ /* pages > 0 => page = [1 .. pages] */ -int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Image_info *image_info, int quality, +int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, int quality, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, GtkProgressBar *progress_bar, int *cancel_save) { char *data; @@ -3641,6 +4505,9 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im int bytes; struct tm *ptm; time_t now; +#ifdef HAVE_LIBLCMS + char *data_raw = NULL; +#endif DBG(DBG_proc, "xsane_save_tiff_page(%d/%d\n", page, pages); @@ -3660,7 +4527,7 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im } - if (image_info->colors == 3) + if (image_info->channels == 3) { components = 3; } @@ -3686,6 +4553,25 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im xsane_back_gtk_error(buf, TRUE); return -1; /* error */ } + +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL)) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = (char *) malloc(image_info->image_width * components * bytes); + + if (!data_raw) + { + _TIFFfree(data); + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + } +#endif + TIFFSetField(tiffile, TIFFTAG_IMAGEWIDTH, image_info->image_width); TIFFSetField(tiffile, TIFFTAG_IMAGELENGTH, image_info->image_height); @@ -3717,7 +4603,7 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im TIFFSetField(tiffile, TIFFTAG_JPEGQUALITY, quality); } - if (image_info->colors == 3) + if (image_info->channels == 3) { if (compression == COMPRESSION_JPEG) { @@ -3728,6 +4614,20 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im { TIFFSetField(tiffile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); } + +#ifdef HAVE_LIBLCMS + if (apply_ICM_profile) + { + if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) + { + xsane_tiff_embed_scanner_icm_profile(tiffile, image_info->icm_profile); + } + else if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS) + { + xsane_tiff_embed_scanner_icm_profile(tiffile, preferences.working_color_space_icm_profile); + } + } +#endif } else { @@ -3760,7 +4660,17 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im gtk_main_iteration(); } - fread(data, 1, w, imagefile); +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL)) + { + fread(data_raw, 1, w, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, 1, w, imagefile); + } if (TIFFWriteScanline(tiffile, data, y, 0) != 1) { @@ -3784,6 +4694,13 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im TIFFWriteDirectory(tiffile); } +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif + _TIFFfree(data); return (*cancel_save); } @@ -3791,9 +4708,60 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im /* ---------------------------------------------------------------------------------------------------------------------- */ +#if defined(PNG_iCCP_SUPPORTED) +#ifdef HAVE_LIBLCMS +static void xsane_png_embed_scanner_icm_profile(png_structp png_ptr, png_infop png_info_ptr, const char *icm_filename) +{ + FILE *icm_profile; + gchar *profile_buffer; + size_t size; + + DBG(DBG_proc, "xsane_png_embed_scanner_icm_profile(%s)\n", icm_filename); + icm_profile = fopen(icm_filename, "rb"); + + if (icm_profile) + { + fseek(icm_profile, 0, SEEK_END); + size = ftell(icm_profile); + fseek(icm_profile, 0, SEEK_SET); + + profile_buffer = malloc(size); + + if (profile_buffer) + { + if (fread(profile_buffer, 1, size, icm_profile) == size) + { + png_set_iCCP(png_ptr, png_info_ptr, "ICC profile", 0, profile_buffer, size); + } + else + { + DBG(DBG_error, "can not read ICC profile data\n"); + } + + free(profile_buffer); + } + else + { + DBG(DBG_error, "can not allocate profile_buffer\n"); + } + + fclose(icm_profile); + } + else + { + DBG(DBG_error, "can not open ICM-profile\n"); + } +} +#endif +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + #ifdef HAVE_LIBPNG #ifdef HAVE_LIBZ -int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int compression, GtkProgressBar *progress_bar, int *cancel_save) +int xsane_save_png(FILE *outfile, int compression, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, + GtkProgressBar *progress_bar, int *cancel_save) { png_structp png_ptr; png_infop png_info_ptr; @@ -3803,6 +4771,9 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c char buf[TEXTBUFSIZE]; int colortype, components, byte_width; int y; +#ifdef HAVE_LIBLCMS + unsigned char *data_raw = NULL; +#endif DBG(DBG_proc, "xsane_save_png\n"); @@ -3834,12 +4805,12 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c byte_width = image_info->image_width; - if (image_info->colors == 4) /* RGBA */ + if (image_info->channels == 4) /* RGBA */ { components = 4; colortype = PNG_COLOR_TYPE_RGB_ALPHA; } - else if (image_info->colors == 3) /* RGB */ + else if (image_info->channels == 3) /* RGB */ { components = 3; colortype = PNG_COLOR_TYPE_RGB; @@ -3855,13 +4826,13 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c png_set_IHDR(png_ptr, png_info_ptr, image_info->image_width, image_info->image_height, image_info->depth, colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - if (image_info->colors >=3) + if (image_info->channels >=3) { sig_bit.red = image_info->depth; sig_bit.green = image_info->depth; sig_bit.blue = image_info->depth; - if (image_info->colors == 4) + if (image_info->channels == 4) { sig_bit.alpha = image_info->depth; } @@ -3884,6 +4855,23 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c image_info->resolution_x * 100.0 / 2.54, image_info->resolution_y * 100.0 / 2.54, PNG_RESOLUTION_METER); #endif + +#if defined(PNG_iCCP_SUPPORTED) +#ifdef HAVE_LIBLCMS + if (apply_ICM_profile) + { + if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) + { + xsane_png_embed_scanner_icm_profile(png_ptr, png_info_ptr, image_info->icm_profile); + } + else if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS) + { + xsane_png_embed_scanner_icm_profile(png_ptr, png_info_ptr, preferences.working_color_space_icm_profile); + } + } +#endif +#endif + png_write_info(png_ptr, png_info_ptr); png_set_shift(png_ptr, &sig_bit); @@ -3897,6 +4885,25 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c return -1; /* error */ } +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL)) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info->image_width * components); + + if (!data_raw) + { + free(data); + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + png_destroy_write_struct(&png_ptr, (png_infopp) 0); + return -1; /* error */ + } + } +#endif + for (y = 0; y < image_info->image_height; y++) { gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); @@ -3905,7 +4912,17 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c gtk_main_iteration(); } - fread(data, components, byte_width, imagefile); +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL)) + { + fread(data_raw, components, byte_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, components, byte_width, imagefile); + } row_ptr = data; png_write_rows(png_ptr, &row_ptr, 1); /* errors are caught by test sor setjmp(...) */ @@ -3916,6 +4933,12 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c } } +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif free(data); png_write_end(png_ptr, png_info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp) 0); @@ -3929,7 +4952,9 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c #ifdef HAVE_LIBPNG #ifdef HAVE_LIBZ -int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, int compression, GtkProgressBar *progress_bar, int *cancel_save) +int xsane_save_png_16(FILE *outfile, int compression, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, + GtkProgressBar *progress_bar, int *cancel_save) { png_structp png_ptr; png_infop png_info_ptr; @@ -3938,8 +4963,10 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in unsigned char *data; char buf[TEXTBUFSIZE]; int colortype, components; - int x,y; - guint16 val; + int y; +#ifdef HAVE_LIBLCMS + unsigned char *data_raw = NULL; +#endif DBG(DBG_proc, "xsane_save_png16\n"); @@ -3969,12 +4996,12 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in return -1; /* error */ } - if (image_info->colors == 4) /* RGBA */ + if (image_info->channels == 4) /* RGBA */ { components = 4; colortype = PNG_COLOR_TYPE_RGB_ALPHA; } - else if (image_info->colors == 3) /* RGB */ + else if (image_info->channels == 3) /* RGB */ { components = 3; colortype = PNG_COLOR_TYPE_RGB; @@ -3997,6 +5024,29 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in sig_bit.gray = image_info->depth; png_set_sBIT(png_ptr, png_info_ptr, &sig_bit); + +#if defined(PNG_pHYs_SUPPORTED) + png_set_pHYs(png_ptr, png_info_ptr, + image_info->resolution_x * 100.0 / 2.54, + image_info->resolution_y * 100.0 / 2.54, PNG_RESOLUTION_METER); +#endif + +#if defined(PNG_iCCP_SUPPORTED) +#ifdef HAVE_LIBLCMS + if (apply_ICM_profile) + { + if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) + { + xsane_png_embed_scanner_icm_profile(png_ptr, png_info_ptr, image_info->icm_profile); + } + else if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS) + { + xsane_png_embed_scanner_icm_profile(png_ptr, png_info_ptr, preferences.working_color_space_icm_profile); + } + } +#endif +#endif + png_write_info(png_ptr, png_info_ptr); png_set_shift(png_ptr, &sig_bit); png_set_packing(png_ptr); @@ -4011,6 +5061,25 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in return -1; /* error */ } +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL)) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info->image_width * components * 2); + + if (!data_raw) + { + free(data); + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + png_destroy_write_struct(&png_ptr, (png_infopp) 0); + return -1; /* error */ + } + } +#endif + for (y = 0; y < image_info->image_height; y++) { gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); @@ -4019,13 +5088,34 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in gtk_main_iteration(); } - for (x = 0; x < image_info->image_width * components; x++) /* this must be changed in dependance of endianess */ +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL)) + { + fread(data_raw, components * 2, image_info->image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif { - fread(&val, 2, 1, imagefile); /* get data in machine order */ - data[x*2+0] = val / 256; /* write data in network order (MSB first) */ - data[x*2+1] = val & 255; + fread(data, components * 2, image_info->image_width, imagefile); } +#if __BYTE_ORDER == __LITTLE_ENDIAN + /* we have to write data in network order (MSB first), so when we run on a low endian machine then we have to swap bytes */ + { + int x; + + for (x = 0; x < image_info->image_width * components; x++) + { + unsigned char help; + + help = data[x*2+1]; + data[x*2+0] = data[x*2+1]; + data[x*2+1] = help; + } + } +#endif /* LITTLE_ENDIAN */ + row_ptr = data; png_write_rows(png_ptr, &row_ptr, 1); if (*cancel_save) @@ -4034,6 +5124,12 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in } } +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif free(data); png_write_end(png_ptr, png_info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp) 0); @@ -4045,22 +5141,69 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in /* ---------------------------------------------------------------------------------------------------------------------- */ -static int xsane_save_pnm_16_ascii_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) +static int xsane_save_pnm_16_ascii_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, + GtkProgressBar *progress_bar, int *cancel_save) { int x,y; - guint16 val; + guint16 *data; int count = 0; +#ifdef HAVE_LIBLCMS + guint16 *data_raw = NULL; +#endif DBG(DBG_proc, "xsane_save_pnm_16_ascii_gray\n"); *cancel_save = 0; + data = malloc(image_info->image_width * 2); + + if (!data) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + +#ifdef HAVE_LIBLCMS + if ((apply_ICM_profile) && (hTransform != NULL)) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info->image_width * 2); + + if (!data_raw) + { + char buf[TEXTBUFSIZE]; + + free(data); + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + } +#endif + for (y = 0; y < image_info->image_height; y++) { +#ifdef HAVE_LIBLCMS + if ((apply_ICM_profile) && (hTransform != NULL)) + { + fread(data_raw, 2, image_info->image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, 2, image_info->image_width, imagefile); + } + for (x = 0; x < image_info->image_width; x++) { - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fprintf(outfile, "%d ", val); + fprintf(outfile, "%d ", data[x]); if (++count >= 10) { @@ -4068,6 +5211,7 @@ static int xsane_save_pnm_16_ascii_gray(FILE *outfile, FILE *imagefile, Image_in count = 0; } } + fprintf(outfile, "\n"); if (ferror(outfile)) @@ -4094,33 +5238,85 @@ static int xsane_save_pnm_16_ascii_gray(FILE *outfile, FILE *imagefile, Image_in } } +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif + free(data); + return (*cancel_save); } /* ---------------------------------------------------------------------------------------------------------------------- */ -static int xsane_save_pnm_16_ascii_color(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) +static int xsane_save_pnm_16_ascii_color(FILE *outfile, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, + GtkProgressBar *progress_bar, int *cancel_save) { int x,y; - guint16 val; + guint16 *data; int count = 0; +#ifdef HAVE_LIBLCMS + guint16 *data_raw = NULL; +#endif DBG(DBG_proc, "xsane_save_pnm_16_ascii_color\n"); *cancel_save = 0; - for (y = 0; y < image_info->image_height; y++) + + data = malloc(image_info->image_width * 6); + + if (!data) { - for (x = 0; x < image_info->image_width; x++) + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + +#ifdef HAVE_LIBLCMS + if ((apply_ICM_profile) && (hTransform != NULL)) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info->image_width * 6); + + if (!data_raw) { - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fprintf(outfile, "%d ", val); + char buf[TEXTBUFSIZE]; + + free(data); - fread(&val, 2, 1, imagefile); - fprintf(outfile, "%d ", val); + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + } +#endif - fread(&val, 2, 1, imagefile); - fprintf(outfile, "%d ", val); + for (y = 0; y < image_info->image_height; y++) + { +#ifdef HAVE_LIBLCMS + if ((apply_ICM_profile) && (hTransform != NULL)) + { + fread(data_raw, 6, image_info->image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, 6, image_info->image_width, imagefile); + } + + for (x = 0; x < image_info->image_width; x++) + { + fprintf(outfile, "%d ", data[3*x+0]); + fprintf(outfile, "%d ", data[3*x+1]); + fprintf(outfile, "%d ", data[3*x+2]); if (++count >= 3) { @@ -4155,27 +5351,82 @@ static int xsane_save_pnm_16_ascii_color(FILE *outfile, FILE *imagefile, Image_i } } +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif + free(data); + return (*cancel_save); } /* ---------------------------------------------------------------------------------------------------------------------- */ -static int xsane_save_pnm_16_binary_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) +static int xsane_save_pnm_16_binary_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, + GtkProgressBar *progress_bar, int *cancel_save) { int x,y; - guint16 val; + guint16 *data; +#ifdef HAVE_LIBLCMS + guint16 *data_raw = NULL; +#endif DBG(DBG_proc, "xsane_save_pnm_16_binary_gray\n"); *cancel_save = 0; + data = malloc(image_info->image_width * 2); + + if (!data) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info->image_width * 2); + + if (!data_raw) + { + char buf[TEXTBUFSIZE]; + + free(data); + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + } +#endif + for (y = 0; y < image_info->image_height; y++) { +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + fread(data_raw, 2, image_info->image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, 2, image_info->image_width, imagefile); + } + for (x = 0; x < image_info->image_width; x++) { - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fputc(val / 256, outfile); /* MSB fist */ - fputc(val & 255, outfile); /* LSB */ + fputc(data[3*x+0] / 256, outfile); + fputc(data[3*x+0] & 255, outfile); } gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); @@ -4201,38 +5452,289 @@ static int xsane_save_pnm_16_binary_gray(FILE *outfile, FILE *imagefile, Image_i } } +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif + free(data); + return (*cancel_save); } /* ---------------------------------------------------------------------------------------------------------------------- */ -static int xsane_save_pnm_16_binary_color(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) +static int xsane_save_pnm_16_binary_color(FILE *outfile, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, + GtkProgressBar *progress_bar, int *cancel_save) { int x,y; - guint16 val; + guint16 *data; +#ifdef HAVE_LIBLCMS + guint16 *data_raw = NULL; +#endif DBG(DBG_proc, "xsane_save_pnm_16_binary_color\n"); *cancel_save = 0; + data = malloc(image_info->image_width * 6); + + if (!data) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info->image_width * 6); + + if (!data_raw) + { + char buf[TEXTBUFSIZE]; + + free(data); + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + } +#endif + for (y = 0; y < image_info->image_height; y++) { +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + fread(data_raw, 6, image_info->image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, 6, image_info->image_width, imagefile); + } + for (x = 0; x < image_info->image_width; x++) { - /* red */ - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fputc(val / 256, outfile); /* MSB fist */ - fputc(val & 255, outfile); /* LSB */ + fputc(data[3*x+0] / 256, outfile); + fputc(data[3*x+0] & 255, outfile); + fputc(data[3*x+1] / 256, outfile); + fputc(data[3*x+1] & 255, outfile); + fputc(data[3*x+2] / 256, outfile); + fputc(data[3*x+2] & 255, outfile); + } + + gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + + if (ferror(outfile)) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + + if (*cancel_save) + { + break; + } + } + +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif + free(data); + + return (*cancel_save); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_save_pnm_8_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, + GtkProgressBar *progress_bar, int *cancel_save) +{ + int x,y; + guint8 *data; +#ifdef HAVE_LIBLCMS + guint8 *data_raw = NULL; +#endif + + DBG(DBG_proc, "xsane_save_pnm_8_gray\n"); + + *cancel_save = 0; + + data = malloc(image_info->image_width); + + if (!data) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info->image_width); + + if (!data_raw) + { + char buf[TEXTBUFSIZE]; - /* green */ - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fputc(val / 256, outfile); /* MSB fist */ - fputc(val & 255, outfile); /* LSB */ + free(data); - /* blue */ - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fputc(val / 256, outfile); /* MSB fist */ - fputc(val & 255, outfile); /* LSB */ + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + } +#endif + + for (y = 0; y < image_info->image_height; y++) + { +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + fread(data_raw, 1, image_info->image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, 1, image_info->image_width, imagefile); + } + + for (x = 0; x < image_info->image_width; x++) + { + fputc(data[x], outfile); + } + + gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + + if (ferror(outfile)) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + + if (*cancel_save) + { + break; + } + } + +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif + free(data); + + return (*cancel_save); +} +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_save_pnm_8_color(FILE *outfile, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, + GtkProgressBar *progress_bar, int *cancel_save) +{ + int x,y; + guint8 *data; +#ifdef HAVE_LIBLCMS + guint8 *data_raw = NULL; +#endif + + DBG(DBG_proc, "xsane_save_pnm_8_color\n"); + + *cancel_save = 0; + + data = malloc(image_info->image_width * 3); + + if (!data) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info->image_width * 3); + + if (!data_raw) + { + char buf[TEXTBUFSIZE]; + + free(data); + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + } +#endif + + for (y = 0; y < image_info->image_height; y++) + { +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + fread(data_raw, 3, image_info->image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info->image_width); + } + else +#endif + { + fread(data, 3, image_info->image_width, imagefile); + } + + for (x = 0; x < image_info->image_width; x++) + { + fputc(data[3*x+0], outfile); + fputc(data[3*x+1], outfile); + fputc(data[3*x+2], outfile); } gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); @@ -4259,12 +5761,46 @@ static int xsane_save_pnm_16_binary_color(FILE *outfile, FILE *imagefile, Image_ } } +#ifdef HAVE_LIBLCMS + if (data_raw) + { + free(data_raw); + } +#endif + free(data); + + return (*cancel_save); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_save_pnm_8(FILE *outfile, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, + GtkProgressBar *progress_bar, int *cancel_save) +{ + DBG(DBG_proc, "xsane_save_pnm_8\n"); + + *cancel_save = 0; + + xsane_write_pnm_header(outfile, image_info, preferences.save_pnm16_as_ascii); + + if (image_info->channels > 1) + { + xsane_save_pnm_8_color(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save); + } + else + { + xsane_save_pnm_8_gray(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save); + } + return (*cancel_save); } /* ---------------------------------------------------------------------------------------------------------------------- */ -int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) +int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, + cmsHTRANSFORM hTransform, int apply_ICM_profile, + GtkProgressBar *progress_bar, int *cancel_save) { DBG(DBG_proc, "xsane_save_pnm_16\n"); @@ -4272,26 +5808,26 @@ int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, Gt xsane_write_pnm_header(outfile, image_info, preferences.save_pnm16_as_ascii); - if (image_info->colors > 1) + if (image_info->channels > 1) { if (preferences.save_pnm16_as_ascii) { - xsane_save_pnm_16_ascii_color(outfile, imagefile, image_info, progress_bar, cancel_save); + xsane_save_pnm_16_ascii_color(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save); } else { - xsane_save_pnm_16_binary_color(outfile, imagefile, image_info, progress_bar, cancel_save); + xsane_save_pnm_16_binary_color(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save); } } else { if (preferences.save_pnm16_as_ascii) { - xsane_save_pnm_16_ascii_gray(outfile, imagefile, image_info, progress_bar, cancel_save); + xsane_save_pnm_16_ascii_gray(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save); } else { - xsane_save_pnm_16_binary_gray(outfile, imagefile, image_info, progress_bar, cancel_save); + xsane_save_pnm_16_binary_gray(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save); } } @@ -4299,7 +5835,6 @@ int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, Gt } /* ---------------------------------------------------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------------------------------------------------------- */ /* 0=ok, <0=error, 1=canceled */ int xsane_save_image_as_lineart(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save) @@ -4524,14 +6059,17 @@ int xsane_save_image_as_text(char *output_filename, char *input_filename, GtkPro /* ---------------------------------------------------------------------------------------------------------------------- */ /* save image in destination file format. lineart images that are stored as grayscale image are reduced to lineart! */ -int xsane_save_image_as(char *output_filename, char *input_filename, int output_format, GtkProgressBar *progress_bar, int *cancel_save) +int xsane_save_image_as(char *output_filename, char *input_filename, int output_format, + int apply_ICM_profile, int cms_function, int cms_intent, int cms_bpc, + GtkProgressBar *progress_bar, int *cancel_save) { FILE *outfile; FILE *infile; char buf[TEXTBUFSIZE]; Image_info image_info; - char lineart_filename[PATH_MAX]; + char temporary_filename[PATH_MAX]; int remove_input_file = FALSE; + cmsHTRANSFORM hTransform = NULL; DBG(DBG_proc, "xsane_save_image_as(output_file=%s, input_file=%s, type=%d)\n", output_filename, input_filename, output_format); @@ -4553,7 +6091,7 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_ { DBG(DBG_info, "original image is a lineart => reduce to lineart\n"); fclose(infile); - xsane_back_gtk_make_path(sizeof(lineart_filename), lineart_filename, 0, 0, "xsane-conversion-", xsane.dev_name, ".pbm", XSANE_PATH_TMP); + xsane_back_gtk_make_path(sizeof(temporary_filename), temporary_filename, 0, 0, "xsane-conversion-", xsane.dev_name, ".pbm", XSANE_PATH_TMP); snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_PACKING_DATA, output_filename); @@ -4565,9 +6103,9 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_ gtk_main_iteration(); } - xsane_save_image_as_lineart(lineart_filename, input_filename, progress_bar, cancel_save); + xsane_save_image_as_lineart(temporary_filename, input_filename, progress_bar, cancel_save); - input_filename = lineart_filename; + input_filename = temporary_filename; remove_input_file = TRUE; infile = fopen(input_filename, "rb"); /* read binary (b for win32) */ @@ -4583,8 +6121,23 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_ xsane_read_pnm_header(infile, &image_info); } - snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_SAVING_DATA, output_filename); +#ifdef HAVE_LIBLCMS + if (apply_ICM_profile && ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) || ((output_format == XSANE_PNM) || (output_format == XSANE_PNM16)))) + { + hTransform = xsane_create_cms_transform(&image_info, cms_function, cms_intent, cms_bpc); + } +#endif + + if (1) + { + snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_SAVING_DATA, output_filename); + } + else + { + snprintf(buf, sizeof(buf), "%s", PROGRESS_SAVING_DATA); + } + gtk_progress_bar_set_ellipsize(GTK_PROGRESS_BAR(progress_bar), PANGO_ELLIPSIZE_START); /* this is new API, can be removed for old GTK versions */ gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), buf); gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); @@ -4614,7 +6167,7 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_ return -1; /* error */ } - xsane_save_tiff_page(tiffile, 0, 0, infile, &image_info, preferences.jpeg_quality, progress_bar, cancel_save); + xsane_save_tiff_page(tiffile, 0, 0, preferences.jpeg_quality, infile, &image_info, hTransform, apply_ICM_profile, cms_function, progress_bar, cancel_save); TIFFClose(tiffile); } @@ -4641,13 +6194,13 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_ } else { - xsane_copy_file(outfile, infile, progress_bar, cancel_save); + xsane_save_pnm_8(outfile, infile, &image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save); } break; #ifdef HAVE_LIBJPEG case XSANE_JPEG: - xsane_save_jpeg(outfile, infile, &image_info, preferences.jpeg_quality, progress_bar, cancel_save); + xsane_save_jpeg(outfile, preferences.jpeg_quality, infile, &image_info, hTransform, apply_ICM_profile, cms_function, progress_bar, cancel_save); break; /* switch format == XSANE_JPEG */ #endif @@ -4656,18 +6209,18 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_ case XSANE_PNG: if (image_info.depth <= 8) { - xsane_save_png(outfile, infile, &image_info, preferences.png_compression, progress_bar, cancel_save); + xsane_save_png(outfile, preferences.png_compression, infile, &image_info, hTransform, apply_ICM_profile, cms_function, progress_bar, cancel_save); } else { - xsane_save_png_16(outfile, infile, &image_info, preferences.png_compression, progress_bar, cancel_save); + xsane_save_png_16(outfile, preferences.png_compression, infile, &image_info, hTransform, apply_ICM_profile, cms_function, progress_bar, cancel_save); } break; /* switch format == XSANE_PNG */ #endif #endif case XSANE_PNM16: - xsane_save_pnm_16(outfile, infile, &image_info, progress_bar, cancel_save); + xsane_save_pnm_16(outfile, infile, &image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save); break; /* switch fomat == XSANE_PNM16 */ case XSANE_PS: /* save postscript, use original size */ @@ -4685,7 +6238,11 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_ (int) imagewidth, /* paper_width */ (int) imageheight, /* paper_height */ 0 /* portrait top left */, - preferences.save_ps_flatdecoded, + preferences.save_ps_flatedecoded, + hTransform, apply_ICM_profile, + (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE), image_info.icm_profile, + 0, NULL, 0, /* no CRD */ + 0 /* intent */, progress_bar, cancel_save); } @@ -4706,7 +6263,8 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_ (int) imagewidth, /* paper_width */ (int) imageheight, /* paper_height */ 0 /* portrait top left */, - preferences.save_pdf_flatdecoded, + preferences.save_pdf_flatedecoded, + hTransform, apply_ICM_profile, cms_function, progress_bar, cancel_save); } @@ -4771,6 +6329,13 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_ fclose (infile); +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + cmsDeleteTransform(hTransform); + } +#endif + if (remove_input_file) { remove(input_filename); /* remove lineart pbm file */ @@ -5098,8 +6663,9 @@ void null_print_func(gchar *msg) } /* ---------------------------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------------------------- */ -int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, int *cancel_save) +int xsane_transfer_to_gimp(char *input_filename, int apply_ICM_profile, int cms_function, GtkProgressBar *progress_bar, int *cancel_save) { int remaining; size_t tile_size; @@ -5114,6 +6680,13 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i int i, x, y; Image_info image_info; FILE *imagefile; + int bytes; + unsigned char *data = NULL; + guint16 *data16 = NULL; +#ifdef HAVE_LIBLCMS + unsigned char *data_raw = NULL; + cmsHTRANSFORM hTransform = NULL; +#endif DBG(DBG_info, "xsane_transer_to_gimp\n"); @@ -5131,18 +6704,64 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i xsane_read_pnm_header(imagefile, &image_info); + if (image_info.depth == 16) + { + bytes = 2; + } + else + { + bytes = 1; + } + + data = malloc(image_info.image_width * 3 * bytes); + data16 = (guint16 *) data; + + if (!data) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (image_info.depth != 1)) + { + hTransform = xsane_create_cms_transform(&image_info, cms_function, preferences.cms_intent, preferences.cms_bpc); + } + + if (hTransform != NULL) + { + DBG(DBG_info, "Doing CMS color conversion\n"); + + data_raw = malloc(image_info.image_width * 3 * bytes); + + if (!data_raw) + { + char buf[TEXTBUFSIZE]; + + free(data); + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return -1; /* error */ + } + } +#endif + x = 0; y = 0; tile_offset = 0; tile_size = image_info.image_width * gimp_tile_height(); - if (image_info.colors == 3) /* RGB */ + if (image_info.channels == 3) /* RGB */ { tile_size *= 3; /* 24 bits/pixel RGB */ image_type = GIMP_RGB; drawable_type = GIMP_RGB_IMAGE; } - else if (image_info.colors == 4) /* RGBA */ + else if (image_info.channels == 4) /* RGBA */ { tile_size *= 4; /* 32 bits/pixel RGBA */ image_type = GIMP_RGB; @@ -5151,6 +6770,55 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i /* colors == 0/1 is predefined */ image_ID = gimp_image_new(image_info.image_width, image_info.image_height, image_type); + +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_CONVERT_TO_SRGB) && apply_ICM_profile) /* embed profile */ + { + GimpParasite *parasite; + FILE *icm_profile; + guchar *profile_buffer; + gint32 size; + + DBG(DBG_error, "Opening ICM profile %s\n", image_info.icm_profile); + icm_profile = fopen(image_info.icm_profile, "rb"); + + if (icm_profile) + { + fseek(icm_profile, 0, SEEK_END); + size = ftell(icm_profile); + fseek(icm_profile, 0, SEEK_SET); + + profile_buffer = malloc(size); + + if (profile_buffer) + { + if (fread(profile_buffer, 1, size, icm_profile) == size) + { + parasite = gimp_parasite_new("icc-profile", 0, size, profile_buffer); + gimp_image_parasite_attach(image_ID, parasite); + gimp_parasite_free(parasite); + } + else + { + DBG(DBG_error, "can not read profile data\n"); + } + + free(profile_buffer); + } + else + { + DBG(DBG_error, "can not allocate profile_buffer\n"); + } + + fclose(icm_profile); + } + else + { + DBG(DBG_error, "can not open ICM-profile\n"); + } + } +#endif + /* the following is supported since gimp-1.1.? */ #ifdef GIMP_HAVE_RESOLUTION_INFO @@ -5168,7 +6836,7 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i tile = g_new(guchar, tile_size); - if (image_info.colors == 1) /* gray */ + if (image_info.channels == 1) /* gray */ { switch (image_info.depth) { @@ -5217,30 +6885,79 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i break; /* leave switch depth 1 */ case 8: /* 8 bit gray */ - case 16: /* 16 bit gray already has been reduced to 8 bit */ - for (i = 0; i < image_info.image_width * image_info.image_height; ++i) + for (y = 1; y <= image_info.image_height; y++) { - tile[tile_offset++] = fgetc(imagefile); - x++; + int tile_height = gimp_tile_height(); - if (x >= image_info.image_width) +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (hTransform != NULL)) { - int tile_height = gimp_tile_height(); + fread(data_raw, 1, image_info.image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info.image_width); + } + else +#endif + { + fread(data, 1, image_info.image_width, imagefile); + } - x = 0; - y++; + for (x = 0; x < image_info.image_width; x++) + { + tile[tile_offset++] = data[x]; + } - if (y % tile_height == 0) - { - gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); - tile_offset = 0; - } + if (y % tile_height == 0) + { + gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); + tile_offset = 0; + } - gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ - while (gtk_events_pending()) - { - gtk_main_iteration(); - } + gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (*cancel_save) + { + break; + } + } + break; /* case 8 */ + + + case 16: /* 16 bit gray has to be reduced to 8 bit */ + for (y = 1; y <= image_info.image_height; y++) + { + int tile_height = gimp_tile_height(); + +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (hTransform != NULL)) + { + fread(data_raw, 2, image_info.image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info.image_width); + } + else +#endif + { + fread(data, 2, image_info.image_width, imagefile); + } + + for (x = 0; x < image_info.image_width; x++) + { + tile[tile_offset++] = data16[x]/256; + } + + if (y % tile_height == 0) + { + gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); + tile_offset = 0; + } + + gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ + while (gtk_events_pending()) + { + gtk_main_iteration(); } if (*cancel_save) @@ -5248,44 +6965,51 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i break; } } - break; /* leave switch depth */ + break; /* case 16 */ default: /* bad depth */ break; /* default */ } } - else if (image_info.colors == 3) /* RGB */ + else if (image_info.channels == 3) /* RGB */ { switch (image_info.depth) { case 8: /* 8 bit RGB */ - case 16: /* 16 bit RGB already has been reduced to 8 bit */ - for (i = 0; i < image_info.image_width * image_info.image_height*3; ++i) + + for (y = 1; y <= image_info.image_height; y++) { - tile[tile_offset++] = fgetc(imagefile); - if (tile_offset % 3 == 0) - { - x++; + int tile_height = gimp_tile_height(); - if (x >= image_info.image_width) - { - int tile_height = gimp_tile_height(); +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (hTransform != NULL)) + { + fread(data_raw, 3, image_info.image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info.image_width); + } + else +#endif + { + fread(data, 3, image_info.image_width, imagefile); + } - x = 0; - y++; + for (x = 0; x < image_info.image_width; x++) + { + tile[tile_offset++] = data[3*x+0]; + tile[tile_offset++] = data[3*x+1]; + tile[tile_offset++] = data[3*x+2]; + } - if (y % tile_height == 0) - { - gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); - tile_offset = 0; - } + if (y % tile_height == 0) + { + gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); + tile_offset = 0; + } - gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } + gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ + while (gtk_events_pending()) + { + gtk_main_iteration(); } if (*cancel_save) @@ -5295,12 +7019,57 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i } break; /* case 8 */ + + case 16: /* 16 bit RGB has to be reduced to 8 bit */ + + for (y = 1; y <= image_info.image_height; y++) + { + int tile_height = gimp_tile_height(); + +#ifdef HAVE_LIBLCMS + if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (hTransform != NULL)) + { + fread(data_raw, 6, image_info.image_width, imagefile); + cmsDoTransform(hTransform, data_raw, data, image_info.image_width); + } + else +#endif + { + fread(data, 6, image_info.image_width, imagefile); + } + + for (x = 0; x < image_info.image_width; x++) + { + tile[tile_offset++] = data16[3*x+0]/256; + tile[tile_offset++] = data16[3*x+1]/256; + tile[tile_offset++] = data16[3*x+2]/256; + } + + if (y % tile_height == 0) + { + gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); + tile_offset = 0; + } + + gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (*cancel_save) + { + break; + } + } + break; /* case 16 */ + default: /* bad depth */ break; /* default */ } } #ifdef SUPPORT_RGBA - else if (image_info.colors == 4) /* RGBA */ + else if (image_info.channels == 4) /* RGBA */ { int i; @@ -5370,6 +7139,19 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i fclose(imagefile); +#ifdef HAVE_LIBLCMS + if (hTransform != NULL) + { + cmsDeleteTransform(hTransform); + } + + if (data_raw) + { + free(data_raw); + } +#endif + free(data); + return 0; } #endif /* HAVE_ANY_GIMP */ @@ -5414,7 +7196,7 @@ static void write_3chars_as_base64(unsigned char c1, unsigned char c2, unsigned /* ---------------------------------------------------------------------------------------------------------------------- */ -void write_string_base64(int fd_socket, unsigned char *string, int len) +void write_string_base64(int fd_socket, char *string, int len) { int i; int pad; @@ -5422,9 +7204,9 @@ void write_string_base64(int fd_socket, unsigned char *string, int len) for (i = 0; i < len; i+=3) { - c1 = string[i]; - c2 = string[i+1]; - c3 = string[i+2]; + c1 = (unsigned char) string[i]; + c2 = (unsigned char) string[i+1]; + c3 = (unsigned char) string[i+2]; pad = i - len + 3; @@ -5477,7 +7259,7 @@ void write_base64(int fd_socket, FILE *infile) pos += 4; if (pos > 71) { - write(fd_socket, "\n", 1); + write(fd_socket, "\r\n", 2); pos = 0; } @@ -5492,7 +7274,7 @@ void write_base64(int fd_socket, FILE *infile) if (pos) { - write(fd_socket, "\n", 1); + write(fd_socket, "\r\n", 2); } xsane.email_progress_val = 1.0; @@ -5505,33 +7287,33 @@ void write_email_header(int fd_socket, char *from, char *reply_to, char *to, cha { char buf[1024]; - snprintf(buf, sizeof(buf), "From: %s\n", from); + snprintf(buf, sizeof(buf), "From: %s\r\n", from); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Reply-To: %s\n", reply_to); + snprintf(buf, sizeof(buf), "Reply-To: %s\r\n", reply_to); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "To: %s\n", to); + snprintf(buf, sizeof(buf), "To: %s\r\n", to); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Subject: %s\n", subject); + snprintf(buf, sizeof(buf), "Subject: %s\r\n", subject); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "MIME-Version: 1.0\n"); + snprintf(buf, sizeof(buf), "MIME-Version: 1.0\r\n"); write(fd_socket, buf, strlen(buf)); if (related) /* related means that we need a special link in the html part to display the image */ { - snprintf(buf, sizeof(buf), "Content-Type: multipart/related;\n"); + snprintf(buf, sizeof(buf), "Content-Type: multipart/related;\r\n"); write(fd_socket, buf, strlen(buf)); } else { - snprintf(buf, sizeof(buf), "Content-Type: multipart/mixed;\n"); + snprintf(buf, sizeof(buf), "Content-Type: multipart/mixed;\r\n"); write(fd_socket, buf, strlen(buf)); } - snprintf(buf, sizeof(buf), " boundary=\"%s\"\n\n", boundary); + snprintf(buf, sizeof(buf), " boundary=\"%s\"\r\n\r\n", boundary); write(fd_socket, buf, strlen(buf)); } @@ -5541,7 +7323,7 @@ void write_email_footer(int fd_socket, char *boundary) { char buf[1024]; - snprintf(buf, sizeof(buf), "--%s--\n", boundary); + snprintf(buf, sizeof(buf), "--%s--\r\n", boundary); write(fd_socket, buf, strlen(buf)); } @@ -5551,16 +7333,16 @@ void write_email_mime_ascii(int fd_socket, char *boundary) { char buf[1024]; - snprintf(buf, sizeof(buf), "--%s\n", boundary); + snprintf(buf, sizeof(buf), "--%s\r\n", boundary); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Type: text/plain;\n"); + snprintf(buf, sizeof(buf), "Content-Type: text/plain;\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), " charset=\"iso-8859-1\"\n"); + snprintf(buf, sizeof(buf), " charset=\"iso-8859-1\"\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 8bit\n\n"); + snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 8bit\r\n\r\n"); write(fd_socket, buf, strlen(buf)); } @@ -5570,22 +7352,22 @@ void write_email_mime_html(int fd_socket, char *boundary) { char buf[1024]; - snprintf(buf, sizeof(buf), "--%s\n", boundary); + snprintf(buf, sizeof(buf), "--%s\r\n", boundary); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Type: text/html;\n"); + snprintf(buf, sizeof(buf), "Content-Type: text/html;\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), " charset=\"us-ascii\"\n"); + snprintf(buf, sizeof(buf), " charset=\"us-ascii\"\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 7bit\n\n"); + snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 7bit\r\n\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">\n"); + snprintf(buf, sizeof(buf), "<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "<html>\n"); + snprintf(buf, sizeof(buf), "<html>\r\n"); write(fd_socket, buf, strlen(buf)); } @@ -5595,28 +7377,28 @@ void write_email_attach_image(int fd_socket, char *boundary, char *content_id, c { char buf[1024]; - snprintf(buf, sizeof(buf), "--%s\n", boundary); + snprintf(buf, sizeof(buf), "--%s\r\n", boundary); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Type: %s\n", content_type); + snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", content_type); write(fd_socket, buf, strlen(buf)); if (content_id) { - snprintf(buf, sizeof(buf), "Content-ID: <%s>\n", content_id); + snprintf(buf, sizeof(buf), "Content-ID: <%s>\r\n", content_id); write(fd_socket, buf, strlen(buf)); } - snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\n"); + snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Disposition: inline;\n"); + snprintf(buf, sizeof(buf), "Content-Disposition: inline;\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), " filename=\"%s\"\n", filename); + snprintf(buf, sizeof(buf), " filename=\"%s\"\r\n", filename); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "\n"); + snprintf(buf, sizeof(buf), "\r\n"); write(fd_socket, buf, strlen(buf)); write_base64(fd_socket, infile); @@ -5628,25 +7410,25 @@ void write_email_attach_file(int fd_socket, char *boundary, FILE *infile, char * { char buf[1024]; - snprintf(buf, sizeof(buf), "--%s\n", boundary); + snprintf(buf, sizeof(buf), "--%s\r\n", boundary); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Type: application/octet-stream\n"); + snprintf(buf, sizeof(buf), "Content-Type: application/octet-stream\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), " name=\"%s\"\n", filename); + snprintf(buf, sizeof(buf), " name=\"%s\"\r\n", filename); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\n"); + snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Disposition: attachment;\n"); + snprintf(buf, sizeof(buf), "Content-Disposition: attachment;\r\n"); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), " filename=\"%s\"\n", filename); + snprintf(buf, sizeof(buf), " filename=\"%s\"\r\n", filename); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "\n"); + snprintf(buf, sizeof(buf), "\r\n"); write(fd_socket, buf, strlen(buf)); write_base64(fd_socket, infile); diff --git a/src/xsane-save.c.orig b/src/xsane-save.c.orig deleted file mode 100644 index a495e1c..0000000 --- a/src/xsane-save.c.orig +++ /dev/null @@ -1,5801 +0,0 @@ -/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend - - xsane-save.c - - Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch - This file is part of the XSANE package. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#include "xsane.h" -#include "xsane-back-gtk.h" -#include "xsane-front-gtk.h" -#include <time.h> -#include <sys/wait.h> - -/* the following test is always false */ -#ifdef _native_WIN32 -# include <winsock.h> -#else -# include <sys/socket.h> -# include <netinet/in.h> -# include <netdb.h> -#endif - -#ifdef HAVE_LIBJPEG -#include <jpeglib.h> -#endif - -#ifdef HAVE_LIBZ -#include <zlib.h> -#endif - -#ifdef HAVE_LIBPNG -#include <png.h> -#endif - -#ifdef HAVE_LIBTIFF -#include <tiffio.h> -#endif - -#ifdef HAVE_MMAP -#include <sys/mman.h> -#endif - -#ifdef HAVE_OS2_H -#include <process.h> -#endif - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef HAVE_ANY_GIMP - -#include <libgimp/gimp.h> - -static void xsane_gimp_query(void); -#ifdef HAVE_GIMP_2 -static void xsane_gimp_run(const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); -#else -static void xsane_gimp_run(char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals); -#endif - -GimpPlugInInfo PLUG_IN_INFO = -{ - NULL, /* init_proc */ - NULL, /* quit_proc */ - xsane_gimp_query, /* query_proc */ - xsane_gimp_run, /* run_proc */ -}; - - -static int xsane_decode_devname(const char *encoded_devname, int n, -char *buf); -static int xsane_encode_devname(const char *devname, int n, char *buf); -void null_print_func(gchar *msg); - -#endif /* HAVE_ANY_GIMP */ - -/* ---------------------------------------------------------------------------------------------------------------------- */ -/* why this routine ? - Problem: link attack - Bad user wants to overwrite a file (mywork.txt) of good user. - File permissions of mywork.txt is 700 so that bad user can not - change or overwrite the file. Directory permissions allow bad user - to write into directory. Bad user sets symlink from a file that good - user will write soon (image.pnm) to mywork.txt. - ==> Good user overwrites his own file, he is allowed to do so. - - Solution: remove file. - Create outputfile and make sure that it does not exist while creation. - - The file is created with the requested image-file permissions. - - Note: This case is a bit curious because it is only a small part of a larger problem: - When other users have write access to the directory they simply can move - mywork.txt to image.pnm. If they do it in the right moment the file is - overwritten without any notice of good user. If they do it long before xsane - wants to write image.pnm then xsane will possibly ask if image.pnm shall be - overwritten. So the real solution is to make the direcoty permissions safe!!! - But some users asked for this and so I added this. - - - This routine shall not be called for temporary files because temp files shall not - be removed after they have been created safe. (Although a temporary file should - not be a symlink so there should be no problem with this) -*/ - -int xsane_create_secure_file(const char *filename) -/* returns 0 on success, -1 on error */ -{ - int fd; - - DBG(DBG_proc, "xsane_create_secure_file\n"); - - remove(filename); /* we need to remove the file because open(..., O_EXCL) will fail otherwise */ - umask((mode_t) preferences.image_umask); /* define image file permissions */ - fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666); - umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ - - if (fd > 0) - { - DBG(DBG_info, "file %s is created and secure\n", filename); - close(fd); - fd = 0; - } - else - { - DBG(DBG_info, "could not create secure file %s\n", filename); - } - - return fd; /* -1 means file is not safe !!! otherwise 0 */ -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_cancel_save(int *cancel_save) -{ - DBG(DBG_proc, "xsane_cancel_save\n"); - *cancel_save = 1; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_convert_text_to_filename(char **text) -{ - DBG(DBG_proc, "xsane_convert_text_to_filename\n"); - - if (text) - { - char *filename = *text; - char buf[256]; - int buflen=0; - int txtlen=0; - - while((filename[txtlen] != 0) && (buflen<253)) - { - switch (filename[txtlen]) - { - case ' ': - buf[buflen++] = ':'; - buf[buflen++] = '_'; - txtlen++; - break; - - case '/': - buf[buflen++] = ':'; - buf[buflen++] = '%'; - txtlen++; - break; - - case '*': - buf[buflen++] = ':'; - buf[buflen++] = '#'; - txtlen++; - break; - - case '?': - buf[buflen++] = ':'; - buf[buflen++] = 'q'; - txtlen++; - break; - - case '\\': - buf[buflen++] = ':'; - buf[buflen++] = '='; - txtlen++; - break; - - case ';': - buf[buflen++] = ':'; - buf[buflen++] = '!'; - txtlen++; - break; - - case '&': - buf[buflen++] = ':'; - buf[buflen++] = '+'; - txtlen++; - break; - - case '<': - buf[buflen++] = ':'; - buf[buflen++] = 's'; - txtlen++; - break; - - case '>': - buf[buflen++] = ':'; - buf[buflen++] = 'g'; - txtlen++; - break; - - case '|': - buf[buflen++] = ':'; - buf[buflen++] = 'p'; - txtlen++; - break; - - case ':': - buf[buflen++] = ':'; - buf[buflen++] = ':'; - txtlen++; - break; - - default: - buf[buflen++] = filename[txtlen++]; - break; - } - } - buf[buflen] = 0; - free(filename); - *text = strdup(buf); - DBG(DBG_info, "filename = \"%s\"\n", *text); - } -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_get_filesize(char *filename) -{ - FILE *infile; - int pos; - int size; - - infile = fopen(filename, "rb"); /* read binary (b for win32) */ - if (infile == NULL) - { - return 0; - } - - pos = ftell(infile); - fseek(infile, 0, SEEK_END); /* get size */ - size = ftell(infile); - fseek(infile, pos, SEEK_SET); /* go to previous position */ - - fclose(infile); - - return size; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_ensure_counter_in_filename(char **filename, int counter_len) -{ - char *position_point = NULL; - char *position; - int counter = 1; - - DBG(DBG_proc, "xsane_ensure_counter_in_filename\n"); - - if (!counter_len) - { - counter_len = 1; - } - - position_point = strrchr(*filename, '.'); - - if (!position_point) /* nothing usable ? */ - { - position_point = *filename + strlen(*filename); /* position_point - 1 is last character */ - } - - if (position_point) - { - position = position_point-1; - if ( (position < *filename) || (*position < '0') || (*position >'9') ) /* we have no counter */ - { - char buf[PATH_MAX]; - int len; - - len = position_point - (*filename); /* length until "." or end of string */ - strncpy(buf, *filename, len); - snprintf(buf+len, sizeof(buf)-len, "-%0*d%s", counter_len, counter, position_point); - *filename = strdup(buf); - } - } -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_update_counter_in_filename(char **filename, int skip, int step, int min_counter_len) -{ - FILE *testfile; - char *position_point = NULL; - char *position_counter; - char buf[PATH_MAX]; - int counter; - int counter_len; - int set_counter_len = min_counter_len; - - DBG(DBG_proc, "xsane_update_counter_in_filename\n"); - - if ( (!step) && (!min_counter_len) ) - { - return; /* do not touch counter */ - } - - while (1) /* loop because we may have to skip existing files */ - { - position_point = strrchr(*filename, '.'); - - if (!position_point) /* nothing usable ? */ - { - position_point = *filename + strlen(*filename); /* here is no point, but position - 1 is last character */ - } - - if (position_point) - { - position_counter = position_point-1; /* go to last number of counter (if counter exists) */ - - /* search non numeric char */ - while ( (position_counter >= *filename) && (*position_counter >= '0') && (*position_counter <='9') ) - { - position_counter--; /* search fisrt numeric character */ - } - - position_counter++; /* go to first numeric charcter */ - - counter_len = position_point - position_counter; - - if (counter_len) /* we have a counter */ - { - sscanf(position_counter, "%d", &counter); - counter = counter + step; /* update counter */ - - if (counter < 0) - { - counter = 0; - xsane_back_gtk_warning(WARN_COUNTER_UNDERRUN, TRUE); - break; /* last available number ("..999") */ - } - - *position_counter = 0; /* set end of string mark to counter start */ - - if (set_counter_len == 0) - { - set_counter_len = counter_len; - } - - snprintf(buf, sizeof(buf), "%s%0*d%s", *filename, set_counter_len, counter, position_point); - - DBG(DBG_info, "filename = \"%s\"\n", buf); - - free(*filename); - *filename = strdup(buf); - - if (skip) /* test if filename already used */ - { - if (preferences.filetype) /* add filetype to filename */ - { - snprintf(buf, sizeof(buf), "%s%s", *filename, preferences.filetype); - testfile = fopen(buf, "rb"); /* read binary (b for win32) */ - } - else /* filetype in filename */ - { - testfile = fopen(*filename, "rb"); /* read binary (b for win32) */ - } - - if (testfile) /* filename used: skip */ - { - fclose(testfile); - } - else - { - break; /* filename not used, ok */ - } - } - else /* do not test if filename already used */ - { - break; /* filename ok */ - } - } - else /* no counter */ - { - break; /* no counter */ - } - } - } -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_read_pnm_header(FILE *file, Image_info *image_info) -{ - int max_val, filetype_nr; - char buf[256]; - - fgets(buf, sizeof(buf)-1, file); - DBG(DBG_info, "filetype header :%s", buf); - - if (buf[0] == 'P') - { - filetype_nr = atoi(buf+1); /* get filetype number */ - - image_info->resolution_x = 72.0; - image_info->resolution_y = 72.0; - image_info->reduce_to_lineart = FALSE; - - while (strcmp(buf, "# XSANE data follows\n")) - { - fgets(buf, sizeof(buf)-1, file); - - if (!strncmp(buf, "# resolution_x =", 20)) - { - sscanf(buf+20, "%lf", &image_info->resolution_x); - } - else if (!strncmp(buf, "# resolution_y =", 20)) - { - sscanf(buf+20, "%lf", &image_info->resolution_y); - } - else if (!strncmp(buf, "# threshold =", 20)) - { - sscanf(buf+20, "%lf", &image_info->threshold); - } - else if (!strncmp(buf, "# gamma =", 20)) - { - sscanf(buf+20, "%lf", &image_info->gamma); - } - else if (!strncmp(buf, "# gamma IRGB =", 20)) - { - sscanf(buf+20, "%lf %lf %lf %lf", - &image_info->gamma, - &image_info->gamma_red, - &image_info->gamma_green, - &image_info->gamma_blue); - } - else if (!strncmp(buf, "# brightness =", 20)) - { - sscanf(buf+20, "%lf", &image_info->brightness); - } - else if (!strncmp(buf, "# brightness IRGB =", 20)) - { - sscanf(buf+20, "%lf %lf %lf %lf", - &image_info->brightness, - &image_info->brightness_red, - &image_info->brightness_green, - &image_info->brightness_blue); - } - else if (!strncmp(buf, "# contrast =", 20)) - { - sscanf(buf+20, "%lf", &image_info->contrast); - } - else if (!strncmp(buf, "# contrast IRGB =", 20)) - { - sscanf(buf+20, "%lf %lf %lf %lf", - &image_info->contrast, - &image_info->contrast_red, - &image_info->contrast_green, - &image_info->contrast_blue); - } - else if (!strncmp(buf, "# reduce to lineart", 20)) - { - image_info->reduce_to_lineart = TRUE; - } - } - - fscanf(file, "%d %d", &image_info->image_width, &image_info->image_height); - - image_info->depth = 1; - - if (filetype_nr != 4) /* P4 = lineart */ - { - fscanf(file, "%d", &max_val); - - if (max_val == 255) - { - image_info->depth = 8; - } - else if (max_val == 65535) - { - image_info->depth = 16; - } - } - - fgetc(file); /* read exactly one newline character */ - - - image_info->colors = 1; - - if (filetype_nr == 6) /* ppm RGB */ - { - image_info->colors = 3; - } - } -#ifdef SUPPORT_RGBA - else if (buf[0] == 'S') /* RGBA format */ - { - fscanf(file, "%d %d\n%d", &image_info->image_width, &image_info->image_height, &max_val); - fgetc(file); /* read exactly one newline character */ - - image_info->depth = 1; - - if (max_val == 255) - { - image_info->depth = 8; - } - else if (max_val == 65535) - { - image_info->depth = 16; - } - - image_info->colors = 4; - } -#endif - - DBG(DBG_info, "xsane_read_pnm_header: width=%d, height=%d, depth=%d, colors=%d, resolution_x=%f, resolution_y=%f\n", - image_info->image_width, image_info->image_height, image_info->depth, image_info->colors, - image_info->resolution_x, image_info->resolution_y); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_as_ascii) -{ - int maxval; - int magic; - - fflush(file); - rewind(file); - - if (image_info->depth > 8) - { - maxval = 65535; - - if (save_pnm16_as_ascii) - { - magic = 2; /* thats the magic number for grayscale ascii, 3 = color ascii */ - } - else /* save pnm as binary */ - { - magic = 5; /* that is the magic number for grayscake binary, 6 = color binary */ - } - } - else - { - maxval = 255; - magic = 5; /* 8 bit images are always saved in binary mode */ - } - - - if (image_info->colors == 1) - { - if (image_info->depth == 1) - { - /* do not touch the texts and length here, the reading routine needs to know the exact texts */ - fprintf(file, "P4\n" - "# XSane settings:\n" - "# resolution_x = %6.1f\n" - "# resolution_y = %6.1f\n" - "# threshold = %4.1f\n" - "# XSANE data follows\n" - "%05d %05d\n", - image_info->resolution_x, - image_info->resolution_y, - image_info->threshold, - image_info->image_width, image_info->image_height); - } - else if (image_info->reduce_to_lineart) - { - /* do not touch the texts and length here, the reading routine needs to know the exact texts */ - fprintf(file, "P%d\n" - "# XSane settings:\n" - "# resolution_x = %6.1f\n" - "# resolution_y = %6.1f\n" - "# threshold = %4.1f\n" - "# reduce to lineart\n" - "# XSANE data follows\n" - "%05d %05d\n" - "%d\n", - magic, /* P5 for binary, P2 for ascii */ - image_info->resolution_x, - image_info->resolution_y, - image_info->threshold, - image_info->image_width, image_info->image_height, - maxval); - } - else - { - fprintf(file, "P%d\n" - "# XSane settings:\n" - "# resolution_x = %6.1f\n" - "# resolution_y = %6.1f\n" - "# gamma = %3.2f\n" - "# brightness = %4.1f\n" - "# contrast = %4.1f\n" - "# XSANE data follows\n" - "%05d %05d\n" - "%d\n", - magic, /* P5 for binary, P2 for ascii */ - image_info->resolution_x, - image_info->resolution_y, - image_info->gamma, - image_info->brightness, - image_info->contrast, - image_info->image_width, image_info->image_height, - maxval); - } - } - else if (image_info->colors == 3) - { - fprintf(file, "P%d\n" - "# XSane settings:\n" - "# resolution_x = %6.1f\n" - "# resolution_y = %6.1f\n" - "# gamma IRGB = %3.2f %3.2f %3.2f %3.2f\n" - "# brightness IRGB = %4.1f %4.1f %4.1f %4.1f\n" - "# contrast IRGB = %4.1f %4.1f %4.1f %4.1f\n" - "# XSANE data follows\n" - "%05d %05d\n" \ - "%d\n", - magic+1, /* P6 for binary, P3 for ascii */ - image_info->resolution_x, - image_info->resolution_y, - image_info->gamma, image_info->gamma_red, image_info->gamma_green, image_info->gamma_blue, - image_info->brightness, image_info->brightness_red, image_info->brightness_green, image_info->brightness_blue, - image_info->contrast, image_info->contrast_red, image_info->contrast_green, image_info->contrast_blue, - image_info->image_width, image_info->image_height, - maxval); - } -#ifdef SUPPORT_RGBA - else if (image_info->colors == 4) - { - fprintf(file, "SANE_RGBA\n" \ - "%d %d\n" \ - "%d\n", - image_info->image_width, image_info->image_height, maxval); - } -#endif -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_copy_file(FILE *outfile, FILE *infile, GtkProgressBar *progress_bar, int *cancel_save) -{ - long size; - long bytes_sum = 0; - size_t bytes; - unsigned char buf[65536]; - - DBG(DBG_proc, "copying file\n"); - - fseek(infile, 0, SEEK_END); - size = ftell(infile); - fseek(infile, 0, SEEK_SET); - - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - while (!feof(infile)) - { - bytes = fread(buf, 1, sizeof(buf), infile); - if (bytes > 0) - { - fwrite(buf, 1, bytes, outfile); - bytes_sum += bytes; - } - - gtk_progress_bar_update(progress_bar, (float) bytes_sum / size); /* update progress bar */ - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - if (ferror(infile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_READ, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - - fflush(outfile); - - if (size != bytes_sum) - { - DBG(DBG_info, "copy errro, not complete, %ld bytes of %ld bytes copied\n", bytes_sum, size); - *cancel_save = 1; - return (*cancel_save); - } - - DBG(DBG_info, "copy complete, %ld bytes copied\n", bytes_sum); - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_copy_file_by_name(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save) -{ - FILE *infile; - FILE *outfile; - - DBG(DBG_proc, "copying file %s to %s\n", input_filename, output_filename); - - outfile = fopen(output_filename, "wb"); /* b = binary mode for win32 */ - - if (outfile == 0) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, output_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - return -2; - } - - infile = fopen(input_filename, "rb"); /* read binary (b for win32) */ - if (infile == 0) - { - char buf[256]; - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, input_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - - fclose(outfile); - remove(output_filename); /* remove already created output file */ - return -1; - } - - xsane_copy_file(outfile, infile, progress_bar, cancel_save); - - fclose(infile); - fclose(outfile); - - gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_grayscale_image_as_lineart(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x, y, bit; - u_char bitval, packed; - - *cancel_save = 0; - - image_info->depth = 1; - - xsane_write_pnm_header(outfile, image_info, 0); - - for (y = 0; y < image_info->image_height; y++) - { - bit = 128; - packed = 0; - - for (x = 0; x < image_info->image_width; x++) - { - bitval = fgetc(imagefile); - - if (!bitval) /* white gets 0 bit, black gets 1 bit */ - { - packed |= bit; - } - - if (bit == 1) - { - fputc(packed, outfile); - bit = 128; - packed = 0; - } - else - { - bit >>= 1; - } - } - - if (bit != 128) - { - fputc(packed, outfile); - bit = 128; - packed = 0; - } - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); /* update progress bar */ - while (gtk_events_pending()) /* give gtk the chance to display the changes */ - { - gtk_main_iteration(); - } - - if (*cancel_save) - { - break; - } - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_info, float x_scale, float y_scale, GtkProgressBar *progress_bar, int *cancel_save) -{ - int original_image_width = image_info->image_width; - int original_image_height = image_info->image_height; - int new_image_width = image_info->image_width * x_scale + 0.5; - int new_image_height = image_info->image_height * y_scale + 0.5; - unsigned char *original_line; - guint16 *original_line16 = NULL; - unsigned char *new_line; - float *pixel_val; - float *pixel_norm; - int bytespp = 1; - float x, y; - int c; - int oldy; - int x_new, y_new; - float x_go, y_go; - float factor, x_factor, y_factor; - guint16 color; - int read_line; - - DBG(DBG_proc, "xsane_save_scaled_image\n"); - - *cancel_save = 0; - - if (image_info->depth > 8) - { - bytespp = 2; - } - - image_info->image_width = new_image_width; - image_info->image_height = new_image_height; - image_info->resolution_x *= x_scale; - image_info->resolution_y *= y_scale; - - original_line = malloc(original_image_width * image_info->colors * bytespp); - if (!original_line) - { - DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); - return -1; - } - - new_line = malloc(new_image_width * image_info->colors * bytespp); - if (!new_line) - { - free(original_line); - DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); - return -1; - } - - pixel_val = malloc(new_image_width * image_info->colors * sizeof(float)); - if (!pixel_val) - { - free(original_line); - free(new_line); - DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); - return -1; - } - - pixel_norm = malloc(new_image_width * image_info->colors * sizeof(float)); - if (!pixel_norm) - { - free(original_line); - free(new_line); - free(pixel_val); - DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); - return -1; - } - - xsane_write_pnm_header(outfile, image_info, 0); - - read_line = TRUE; - - memset(pixel_val, 0, new_image_width * image_info->colors * sizeof(float)); - memset(pixel_norm, 0, new_image_width * image_info->colors * sizeof(float)); - - y_new = 0; - y_go = 1.0 / y_scale; - y_factor = 1.0; - y = 0.0; - - while (y < original_image_height) - { - DBG(DBG_info2, "xsane_save_scaled_image: original line %d, new line %d\n", (int) y, y_new); - - gtk_progress_bar_update(progress_bar, (float) y / original_image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - if (read_line) - { - DBG(DBG_info, "xsane_save_scaled_image: reading original line %d\n", (int) y); - fread(original_line, original_image_width, image_info->colors * bytespp, imagefile); /* read one line */ - original_line16 = (guint16 *) original_line; - } - - x_new = 0; - x_go = 1.0 / x_scale; - x = 0.0; - x_factor = 1.0; - - while ( (x < original_image_width) && (x_new < new_image_width) ) /* add this line to anti aliasing buffer */ - - { - factor = x_factor * y_factor; - - for (c = 0; c < image_info->colors; c++) - { - if (bytespp == 1) - { - color = original_line[((int) x) * image_info->colors + c]; - } - else /* bytespp == 2 */ - { - color = original_line16[((int) x) * image_info->colors + c]; - } - - pixel_val [x_new * image_info->colors + c] += factor * color; - pixel_norm[x_new * image_info->colors + c] += factor; - } - - x_go -= x_factor; - - if (x_go <= 0.0) /* change of pixel in new image */ - { - x_new++; - x_go = 1.0 / x_scale; - - x_factor = x - (int) x; /* use pixel rest */ - if (x_factor > x_go) - { - x_factor = x_go; - } - } - else - { - x_factor = x_go; - } - - if (x_factor > 1.0) - { - x_factor = 1.0; - } - - x += x_factor; - } - - y_go -= y_factor; - - if (y_go <= 0.0) /* normalize one line and write to destination image file */ - { - DBG(DBG_info2, "xsane_save_scaled_image: writing new line %d\n", y_new); - - if (bytespp == 1) - { - for (x_new = 0; x_new < new_image_width * image_info->colors; x_new++) - { - new_line[x_new] = (int) (pixel_val[x_new] / pixel_norm[x_new]); - } - } - else /* bytespp == 2 */ - { - guint16 *new_line16 = (guint16 *) new_line; - - for (x_new = 0; x_new < new_image_width * image_info->colors; x_new++) - { - new_line16[x_new] = (int) (pixel_val[x_new] / pixel_norm[x_new]); - } - } - - fwrite(new_line, new_image_width, image_info->colors * bytespp, outfile); /* write one line */ - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - /* reset values and norm factors */ - memset(pixel_val, 0, new_image_width * image_info->colors * sizeof(float)); - memset(pixel_norm, 0, new_image_width * image_info->colors * sizeof(float)); - - y_new++; - y_go = 1.0 / y_scale; - - y_factor = y - (int) y; - if (y_factor > y_go) - { - y_factor = y_go; - } - } - else - { - y_factor = y_go; - } - - if (y_factor > 1.0) - { - y_factor = 1.0; - } - - oldy = (int) y; - y += y_factor; - read_line = (oldy != (int) y); - } - - free(original_line); - free(new_line); - free(pixel_val); - free(pixel_norm); - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ -#if 0 -int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_info, float x_scale, float y_scale, GtkProgressBar *progress_bar, int *cancel_save) -{ - float original_y; - int old_original_y; - int x, y, i; - int original_image_width = image_info->image_width; - int new_image_width = image_info->image_width * x_scale; - int new_image_height = image_info->image_height * y_scale; - unsigned char *original_line; - unsigned char *new_line; - int bytespp = 1; - - DBG(DBG_proc, "xsane_save_scaled_image\n"); - - if (image_info->depth > 8) - { - bytespp = 2; - } - - image_info->image_width = new_image_width; - image_info->image_height = new_image_height; - image_info->resolution_x *= x_scale; - image_info->resolution_y *= y_scale; - - original_line = malloc(original_image_width * image_info->colors * bytespp); - if (!original_line) - { - DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); - return -1; - } - - new_line = malloc(new_image_width * image_info->colors * bytespp); - if (!new_line) - { - free(original_line); - DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); - return -1; - } - - xsane_write_pnm_header(outfile, image_info, 0); - - original_y = 0.0; - old_original_y = -1; - - for (y = 0; y < new_image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (; ((int) original_y) - old_original_y; old_original_y += 1) - { - fread(original_line, original_image_width, image_info->colors * bytespp, imagefile); /* read one line */ - } - - for (x = 0; x < new_image_width; x++) - { - for (i = 0; i < image_info->colors * bytespp; i++) - { - new_line[x * image_info->colors * bytespp + i] = original_line[((int) (x / x_scale)) * image_info->colors * bytespp + i]; - } - } - - fwrite(new_line, new_image_width, image_info->colors * bytespp, outfile); /* write one line */ - - original_y += 1/y_scale; - - if (*cancel_save) - { - break; - } - } - - free(original_line); - free(new_line); - - fflush(outfile); - - return (*cancel_save); -} -#endif - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image_info, int radius, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x, y, sx, sy, i; - int xmin, xmax; - int ymin, ymax; - int count; - unsigned char *line_cache; - unsigned char *line_cache_ptr; - guint16 *color_cache; - guint16 *color_cache_ptr; - int bytespp = 1; - int color_radius; - int color_width = image_info->image_width * image_info->colors; - - radius--; /* correct radius : 1 means nothing happens */ - - if (radius < 1) - { - radius = 1; - } - - color_radius = radius * image_info->colors; - - if (image_info->depth > 8) - { - bytespp = 2; - } - - xsane_write_pnm_header(outfile, image_info, 0); - - line_cache = malloc(color_width * bytespp * (2 * radius + 1)); - if (!line_cache) - { - DBG(DBG_error, "xsane_despeckle_image: out of memory\n"); - return -1; - } - - fread(line_cache, color_width * bytespp, (2 * radius + 1), imagefile); - - color_cache = malloc((size_t) sizeof(guint16) * (2*radius+1)*(2*radius+1)); - - if (!color_cache) - { - free(line_cache); - DBG(DBG_error, "xsane_despeckle_image: out of memory\n"); - return -1; - } - - for (y = 0; y < image_info->image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - ymin = y - radius; - ymax = y + radius; - - if (ymin < 0) - { - ymin = 0; - } - - if (ymax > image_info->image_height) - { - ymax = image_info->image_height; - } - - for (x = 0; x < color_width; x++) - { - xmin = x - color_radius; - xmax = x + color_radius; - - if (xmin < 0) - { - xmin = x % image_info->colors; - } - - if (xmax > color_width) - { - xmax = color_width; - } - - count = 0; - - color_cache_ptr = color_cache; - - - if (bytespp == 1) - { - for (sy = ymin; sy <= ymax; sy++) /* search area defined by radius - y part */ - { - line_cache_ptr = line_cache + (sy-ymin) * color_width + xmin; - - for (sx = xmin; sx <= xmax; sx+=image_info->colors) /* x part */ - { - *color_cache_ptr = *line_cache_ptr; - color_cache_ptr++; - line_cache_ptr += image_info->colors; - } - } - - /* sort color_cache */ - - count = color_cache_ptr - color_cache; - - if (count > 1) - { - int d, j, val; - - for (d = count / 2; d > 0; d = d / 2) - { - for (i = d; i < count; i++) - { - for (j = i - d, color_cache_ptr = color_cache + j; j >= 0 && color_cache_ptr[0] > color_cache_ptr[d]; j -= d, color_cache_ptr -= d) - { - val = color_cache_ptr[0]; - color_cache_ptr[0] = color_cache_ptr[d]; - color_cache_ptr[d] = val; - }; - } - } - } - - fputc((char) (color_cache[count/2]), outfile); - } - else /* 16 bit/color */ - { - guint16 val16; - guint16 *line_cache16 = (guint16 *) line_cache; - guint16 *line_cache16_ptr; - char *bytes16 = (char *) &val16; - - for (sy = ymin; sy <= ymax; sy++) - { - line_cache16_ptr = line_cache16 + (sy-ymin) * color_width + xmin; - - for (sx = xmin; sx <= xmax; sx+=image_info->colors) - { - *color_cache_ptr = *line_cache16_ptr; - color_cache_ptr++; - line_cache16_ptr += image_info->colors; - } - } - - /* sort color_cache */ - - count = color_cache_ptr - color_cache; - - if (count > 1) - { - int d,j, val; - - for (d = count / 2; d > 0; d = d / 2) - { - for (i = d; i < count; i++) - { - for (j = i - d, color_cache_ptr = color_cache + j; j >= 0 && color_cache_ptr[0] > color_cache_ptr[d]; j -= d, color_cache_ptr -= d) - { - val = color_cache_ptr[0]; - color_cache_ptr[0] = color_cache_ptr[d]; - color_cache_ptr[d] = val; - }; - } - } - } - - val16 = color_cache[count/2]; - fputc(bytes16[0], outfile); /* write bytes in machine byte order */ - fputc(bytes16[1], outfile); - } - } - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if ((y > radius) && (y < image_info->image_height - radius)) - { - memcpy(line_cache, line_cache + color_width * bytespp, - color_width * bytespp * 2 * radius); - fread(line_cache + color_width * bytespp * 2 * radius, - color_width * bytespp, 1, imagefile); - } - } - - fflush(outfile); - - free(line_cache); - free(color_cache); - - return 0; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info, float radius, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x, y, sx, sy; - int xmin, xmax; - int ymin, ymax; - double val, norm, outer_factor; - unsigned char *line_cache; - int bytespp = 1; - int intradius; - int xmin_flag; - int xmax_flag; - int ymin_flag; - int ymax_flag; - - *cancel_save = 0; - - intradius = (int) radius; - - outer_factor = radius - (int) radius; - - if (image_info->depth > 8) - { - bytespp = 2; - } - - xsane_write_pnm_header(outfile, image_info, 0); - - line_cache = malloc(image_info->image_width * image_info->colors * bytespp * (2 * intradius + 1)); - if (!line_cache) - { - DBG(DBG_error, "xsane_blur_image: out of memory\n"); - return -1; - } - - fread(line_cache, image_info->image_width * image_info->colors * bytespp, (2 * intradius + 1), imagefile); - - for (y = 0; y < image_info->image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (x = 0; x < image_info->image_width * image_info->colors; x++) - { - xmin_flag = xmax_flag = ymin_flag = ymax_flag = TRUE; - - xmin = x - intradius * image_info->colors; - xmax = x + intradius * image_info->colors; - - if (xmin < 0) - { - xmin = x % image_info->colors; - xmin_flag = FALSE; - } - - if (xmax > image_info->image_width * image_info->colors) - { - xmax = image_info->image_width * image_info->colors; - xmax_flag = FALSE; - } - - ymin = y - intradius; - ymax = y + intradius; - - if (ymin < 0) - { - ymin = 0; - ymin_flag = FALSE; - } - - if (ymax > image_info->image_height) - { - ymax = image_info->image_height; - ymax_flag = FALSE; - } - - val = 0.0; - norm = 0.0; - - if (bytespp == 1) - { - if (xmin_flag) /* integrate over left margin */ - { - for (sy = ymin+1; sy <= ymax-1 ; sy++) - { - val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->colors + xmin]; - norm += outer_factor; - } - } - - if (xmax_flag) /* integrate over right margin */ - { - for (sy = ymin+1; sy <= ymax-1 ; sy++) - { - val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->colors + xmax]; - norm += outer_factor; - } - } - - if (ymin_flag) /* integrate over top margin */ - { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) - { - val += outer_factor * line_cache[sx]; - norm += outer_factor; - } - } - - if (ymax_flag) /* integrate over bottom margin */ - { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) - { - val += outer_factor * line_cache[(ymax-ymin) * image_info->image_width * image_info->colors + sx]; - norm += outer_factor; - } - } - - for (sy = ymin+1; sy <= ymax-1; sy++) /* integrate internal square */ - { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors; sx+=image_info->colors) - { - val += line_cache[(sy-ymin) * image_info->image_width * image_info->colors + sx]; - norm += 1.0; - } - } - fputc((char) ((int) (val/norm)), outfile); - } - else /* bytespp == 2 */ - { - guint16 *line_cache16 = (guint16 *) line_cache; - guint16 val16; - char *bytes16 = (char *) &val16; - - if (xmin_flag) /* integrate over left margin */ - { - for (sy = ymin+1; sy <= ymax-1 ; sy++) - { - val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + xmin]; - norm += outer_factor; - } - } - - if (xmax_flag) /* integrate over right margin */ - { - for (sy = ymin+1; sy <= ymax-1 ; sy++) - { - val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + xmax]; - norm += outer_factor; - } - } - - if (ymin_flag) /* integrate over top margin */ - { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) - { - val += outer_factor * line_cache16[sx]; - norm += outer_factor; - } - } - - if (ymax_flag) /* integrate over bottom margin */ - { - for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) - { - val += outer_factor * line_cache16[(ymax-ymin) * image_info->image_width * image_info->colors + sx]; - norm += outer_factor; - } - } - - for (sy = ymin; sy <= ymax; sy++) /* integrate internal square */ - { - for (sx = xmin; sx <= xmax; sx+=image_info->colors) - { - val += line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + sx]; - norm += 1.0; - } - } - - val16 = val / norm; - fputc(bytes16[0], outfile); /* write bytes in machine byte order */ - fputc(bytes16[1], outfile); - } - } - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - /* reset values and norm factors */ - - if ((y > intradius) && (y < image_info->image_height - intradius)) - { - memcpy(line_cache, line_cache + image_info->image_width * image_info->colors * bytespp, - image_info->image_width * image_info->colors * bytespp * 2 * intradius); - fread(line_cache + image_info->image_width * image_info->colors * bytespp * 2 * intradius, - image_info->image_width * image_info->colors * bytespp, 1, imagefile); - } - } - - fflush(outfile); - free(line_cache); - - return 0; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#if 0 -int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info, int radius, GtkProgressBar *progress_bar) -{ - int x, y, sx, sy; - int xmin, xmax; - int ymin, ymax; - int pos0; - int val, count; - unsigned char *line_cache; - int bytespp = 1; - - if (image_info->depth > 8) - { - bytespp = 2; - } - - pos0 = ftell(imagefile); /* mark position to skip header */ - - xsane_write_pnm_header(outfile, image_info, 0); - - line_cache = malloc(image_info->image_width * image_info->colors * bytespp * (2 * radius + 1)); - if (!line_cache) - { - DBG(DBG_error, "xsane_blur_image: out of memory\n"); - return -1; - } - - fread(line_cache, image_info->image_width * image_info->colors * bytespp, (2 * radius + 1), imagefile); - - for (y = 0; y < image_info->image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (x = 0; x < image_info->image_width * image_info->colors; x++) - { - xmin = x - radius * image_info->colors; - xmax = x + radius * image_info->colors; - - if (xmin < 0) - { - xmin = x % image_info->colors; - } - - if (xmax > image_info->image_width * image_info->colors) - { - xmax = image_info->image_width * image_info->colors; - } - - ymin = y - radius; - ymax = y + radius; - - if (ymin < 0) - { - ymin = 0; - } - - if (ymax > image_info->image_height) - { - ymax = image_info->image_height; - } - - val = 0; - count = 0; - - if (bytespp == 1) - { - for (sy = ymin; sy <= ymax; sy++) - { - for (sx = xmin; sx <= xmax; sx+=image_info->colors) - { - val += line_cache[(sy-ymin) * image_info->image_width * image_info->colors + sx]; - count++; - } - } - fputc((char) (val/count), outfile); - } - else - { - guint16 *line_cache16 = (guint16 *) line_cache; - guint16 val16; - char *bytes16 = (char *) &val16; - - for (sy = ymin; sy <= ymax; sy++) - { - for (sx = xmin; sx <= xmax; sx+=image_info->colors) - { - val += line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + sx]; - count++; - } - } - - val16 = val / count; - fputc(bytes16[0], outfile); /* write bytes in machine byte order */ - fputc(bytes16[1], outfile); - } - } - - if ((y > radius) && (y < image_info->image_height - radius)) - { - memcpy(line_cache, line_cache + image_info->image_width * image_info->colors * bytespp, - image_info->image_width * image_info->colors * bytespp * 2 * radius); - fread(line_cache + image_info->image_width * image_info->colors * bytespp * 2 * radius, - image_info->image_width * image_info->colors * bytespp, 1, imagefile); - } - } - - fflush(outfile); - free(line_cache); - - return 0; -} -#endif - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_info, int rotation, GtkProgressBar *progress_bar, int *cancel_save) -/* returns true if operation was cancelled */ -{ - int x, y, pos0, bytespp, i; - int pixel_width = image_info->image_width; - int pixel_height = image_info->image_height; - float resolution_x = image_info->resolution_x; - float resolution_y = image_info->resolution_y; - -#ifdef HAVE_MMAP - char *mmaped_imagefile = NULL; -#endif - - DBG(DBG_proc, "xsane_save_rotate_image\n"); - - *cancel_save = 0; - - pos0 = ftell(imagefile); /* mark position to skip header */ - - bytespp = image_info->colors; - - if (image_info->depth > 8) - { - bytespp *= 2; - } - - if (image_info->depth < 8) /* lineart images are expanded to grayscale until transformation is done */ - { - image_info->depth = 8; /* so we have at least 8 bits/pixel here */ - } - -#ifdef HAVE_MMAP - mmaped_imagefile = mmap(NULL, pixel_width * pixel_height * bytespp + pos0, PROT_READ, MAP_PRIVATE, fileno(imagefile), 0); - if (mmaped_imagefile == (char *) -1) /* mmap failed */ - { - DBG(DBG_info, "xsane_save_rotate_image: unable to memory map image file, using standard file access\n"); - mmaped_imagefile = NULL; - } - else - { - DBG(DBG_info, "xsane_save_rotate_image: using memory mapped image file\n"); - } -#endif - - switch (rotation) - { - default: - break; - - case 0: /* 0 degree */ - xsane_write_pnm_header(outfile, image_info, 0); - - for (y = 0; y < pixel_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / pixel_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (x = 0; x < pixel_width; x++) - { -#ifdef HAVE_MMAP - if (mmaped_imagefile) - { - char *p = mmaped_imagefile + pos0 + bytespp * (x + y * pixel_width); /* calculate correct position */ - - for (i=0; i<bytespp; i++) - { - fputc(*p++, outfile); - } - } - else -#endif - { - for (i = 0; i < bytespp; i++) - { - fputc(fgetc(imagefile), outfile); - } - } - } - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - break; - - case 1: /* 90 degree */ - image_info->image_width = pixel_height; - image_info->image_height = pixel_width; - - image_info->resolution_x = resolution_y; - image_info->resolution_y = resolution_x; - - xsane_write_pnm_header(outfile, image_info, 0); - - for (x=0; x<pixel_width; x++) - { - gtk_progress_bar_update(progress_bar, (float) x / pixel_width); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (y=pixel_height-1; y>=0; y--) - { -#ifdef HAVE_MMAP - if (mmaped_imagefile) - { - char *p = mmaped_imagefile + pos0 + bytespp * (x + y * pixel_width); /* calculate correct position */ - - for (i=0; i<bytespp; i++) - { - fputc(*p++, outfile); - } - } - else -#endif - { - fseek(imagefile, pos0 + bytespp * (x + y * pixel_width), SEEK_SET); /* go to the correct position */ - for (i=0; i<bytespp; i++) - { - fputc(fgetc(imagefile), outfile); - } - } - } - - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - - break; - - case 2: /* 180 degree */ - xsane_write_pnm_header(outfile, image_info, 0); - - for (y = pixel_height-1; y >= 0; y--) - { - gtk_progress_bar_update(progress_bar, (float) (pixel_height - y) / pixel_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (x = pixel_width-1; x >= 0; x--) - { -#ifdef HAVE_MMAP - if (mmaped_imagefile) - { - char *p = mmaped_imagefile + pos0 + bytespp * (x + y * pixel_width); /* calculate correct position */ - - for (i = 0; i < bytespp; i++) - { - fputc(*p++, outfile); - } - } - else -#endif - { - fseek(imagefile, pos0 + bytespp * (x + y * pixel_width), SEEK_SET); /* go to the correct position */ - for (i = 0; i < bytespp; i++) - { - fputc(fgetc(imagefile), outfile); - } - } - } - - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - break; - - case 3: /* 270 degree */ - image_info->image_width = pixel_height; - image_info->image_height = pixel_width; - - image_info->resolution_x = resolution_y; - image_info->resolution_y = resolution_x; - - xsane_write_pnm_header(outfile, image_info, 0); - - for (x = pixel_width-1; x >= 0; x--) - { - gtk_progress_bar_update(progress_bar, (float) (pixel_width - x) / pixel_width); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (y = 0; y < pixel_height; y++) - { -#ifdef HAVE_MMAP - if (mmaped_imagefile) - { - char *p = mmaped_imagefile + pos0 + bytespp * (x + y * pixel_width); /* calculate correct position */ - - for (i = 0; i < bytespp; i++) - { - fputc(*p++, outfile); - } - } - else -#endif - { - fseek(imagefile, pos0 + bytespp * (x + y * pixel_width), SEEK_SET); /* go to the correct position */ - for (i = 0; i < bytespp; i++) - { - fputc(fgetc(imagefile), outfile); - } - } - } - - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - break; - - case 4: /* 0 degree, x mirror */ - xsane_write_pnm_header(outfile, image_info, 0); - - for (y = 0; y < pixel_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / pixel_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (x = pixel_width-1; x >= 0; x--) - { -#ifdef HAVE_MMAP - if (mmaped_imagefile) - { - char *p = mmaped_imagefile + pos0 + bytespp * (x + y * pixel_width); /* calculate correct position */ - - for (i = 0; i < bytespp; i++) - { - fputc(*p++, outfile); - } - } - else -#endif - { - fseek(imagefile, pos0 + bytespp * (x + y * pixel_width), SEEK_SET); /* go to the correct position */ - for (i = 0; i < bytespp; i++) - { - fputc(fgetc(imagefile), outfile); - } - } - } - - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - break; - - case 5: /* 90 degree, x mirror */ - image_info->image_width = pixel_height; - image_info->image_height = pixel_width; - - image_info->resolution_x = resolution_y; - image_info->resolution_y = resolution_x; - - xsane_write_pnm_header(outfile, image_info, 0); - - for (x = 0; x < pixel_width; x++) - { - gtk_progress_bar_update(progress_bar, (float) x / pixel_width); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (y = 0; y < pixel_height; y++) - { -#ifdef HAVE_MMAP - if (mmaped_imagefile) - { - char *p = mmaped_imagefile + pos0 + bytespp * (x + y * pixel_width); /* calculate correct position */ - - for (i=0; i<bytespp; i++) - { - fputc(*p++, outfile); - } - } - else -#endif - { - fseek(imagefile, pos0 + bytespp * (x + y * pixel_width), SEEK_SET); /* go to the correct position */ - for (i = 0; i < bytespp; i++) - { - fputc(fgetc(imagefile), outfile); - } - } - } - - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - - break; - - case 6: /* 180 degree, x mirror */ - xsane_write_pnm_header(outfile, image_info, 0); - - for (y = pixel_height-1; y >= 0; y--) - { - gtk_progress_bar_update(progress_bar, (float) (pixel_height - y) / pixel_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (x = 0; x < pixel_width; x++) - { -#ifdef HAVE_MMAP - if (mmaped_imagefile) - { - char *p = mmaped_imagefile + pos0 + bytespp * (x + y * pixel_width); /* calculate correct position */ - - for (i = 0; i < bytespp; i++) - { - fputc(*p++, outfile); - } - } - else -#endif - { - fseek(imagefile, pos0 + bytespp * (x + y * pixel_width), SEEK_SET); /* go to the correct position */ - for (i = 0; i < bytespp; i++) - { - fputc(fgetc(imagefile), outfile); - } - } - } - - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - break; - - case 7: /* 270 degree, x mirror */ - image_info->image_width = pixel_height; - image_info->image_height = pixel_width; - - image_info->resolution_x = resolution_y; - image_info->resolution_y = resolution_x; - - xsane_write_pnm_header(outfile, image_info, 0); - - for (x = pixel_width-1; x >= 0; x--) - { - gtk_progress_bar_update(progress_bar, (float) (pixel_width - x) / pixel_width); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (y = pixel_height-1; y >= 0; y--) - { -#ifdef HAVE_MMAP - if (mmaped_imagefile) - { - char *p = mmaped_imagefile + pos0 + bytespp * (x + y * pixel_width); /* calculate correct position */ - - for (i = 0; i < bytespp; i++) - { - fputc(*p++, outfile); - } - } - else -#endif - { - fseek(imagefile, pos0 + bytespp * (x + y * pixel_width), SEEK_SET); /* go to the correct position */ - for (i = 0; i < bytespp; i++) - { - fputc(fgetc(imagefile), outfile); - } - } - } - - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - break; - } - -#ifdef HAVE_MMAP - if (mmaped_imagefile) - { - munmap(mmaped_imagefile, pos0 + pixel_width * pixel_height * bytespp); - } -#endif - - fflush(outfile); - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_save_ps_create_document_header(FILE *outfile, int pages, int flatdecode) -{ - DBG(DBG_proc, "xsane_save_ps_create_document_header\n"); - - fprintf(outfile, "%%!PS-Adobe-3.0\n"); - fprintf(outfile, "%%%%Creator: XSane version %s (sane %d.%d) - by Oliver Rauch\n", VERSION, - SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), - SANE_VERSION_MINOR(xsane.sane_backend_versioncode)); - fprintf(outfile, "%%%%DocumentData: Clean7Bit\n"); - if (flatdecode) - { - fprintf(outfile, "%%%%LanguageLevel: 3\n"); - } - else - { - fprintf(outfile, "%%%%LanguageLevel: 2\n"); - } - - if (pages) - { - fprintf(outfile, "%%%%Pages: %d\n", pages); - } - else - { - fprintf(outfile, "%%%%Pages: (atend)\n"); - } - - fprintf(outfile, "%%%%EndComments\n"); - fprintf(outfile, "\n"); - fprintf(outfile, "/origstate save def\n"); - fprintf(outfile, "20 dict begin\n"); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_save_ps_create_document_trailer(FILE *outfile, int pages) -{ - DBG(DBG_proc, "xsane_save_ps_create_document_trailer\n"); - - fprintf(outfile, "end\n"); - fprintf(outfile, "origstate restore\n"); - - if (pages) - { - fprintf(outfile, "%%%%Trailer\n"); - fprintf(outfile, "%%%%Pages: %d\n", pages); - } - - fprintf(outfile, "%%%%EOF\n"); - fprintf(outfile, "\n"); - -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* page = [1 .. pages] */ -static void xsane_save_ps_create_page_header(FILE *outfile, int page, - Image_info *image_info, - float width, float height, - int paper_left_margin, int paper_bottom_margin, - int paper_width, int paper_height, - int paper_orientation, int flatdecode, - GtkProgressBar *progress_bar) -{ - int degree, position_left, position_bottom, box_left, box_bottom, box_right, box_top, depth; - int left, bottom; - - DBG(DBG_proc, "xsane_save_ps_create_page_header\n"); - - switch (paper_orientation) - { - default: - case 0: /* top left portrait */ - left = 0.0; - bottom = paper_height - height; - break; - - case 1: /* top right portrait */ - left = paper_width - width; - bottom = paper_height - height; - break; - - case 2: /* bottom right portrait */ - left = paper_width - width; - bottom = 0.0; - break; - - case 3: /* bottom left portrait */ - left = 0.0; - bottom = 0.0; - break; - - case 4: /* center portrait */ - left = paper_width / 2.0 - width / 2.0; - bottom = paper_height / 2.0 - height / 2.0; - break; - - - case 8: /* top left landscape */ - left = 0.0; - bottom = paper_width - height; - break; - - case 9: /* top right landscape */ - left = paper_height - width; - bottom = paper_width - height; - break; - - case 10: /* bottom right landscape */ - left = paper_height - width; - bottom = 0.0; - break; - - case 11: /* bottom left landscape */ - left = 0.0; - bottom = 0.0; - break; - - case 12: /* center landscape */ - left = paper_height / 2.0 - width / 2.0; - bottom = paper_width / 2.0 - height / 2.0; - break; - } - - - if (paper_orientation >= 8) /* rotate with 90 degrees - landscape mode */ - { - degree = 90; - position_left = left + paper_bottom_margin; - position_bottom = bottom - paper_width - paper_left_margin; - box_left = paper_width - paper_left_margin - bottom - height; - box_bottom = left + paper_bottom_margin; - box_right = box_left + ceil(height); - box_top = box_bottom + ceil(width); - } - else /* do not rotate, portrait mode */ - { - degree = 0; - position_left = left + paper_left_margin; - position_bottom = bottom + paper_bottom_margin; - box_left = left + paper_left_margin; - box_bottom = bottom + paper_bottom_margin; - box_right = box_left + ceil(width); - box_top = box_bottom + ceil(height); - } - - depth = image_info->depth; - - if (depth > 8) - { - depth = 8; - } - - fprintf(outfile, "\n"); - fprintf(outfile, "%%%%Page: %d %d\n", page, page); - fprintf(outfile, "%%%%PageBoundingBox: %d %d %d %d\n", box_left, box_bottom, box_right, box_top); - - if (depth == 1) - { - fprintf(outfile, "/grays %d string def\n", image_info->image_width); - fprintf(outfile, "/npixels 0 def\n"); - fprintf(outfile, "/rgbindx 0 def\n"); - } - - fprintf(outfile, "%d rotate\n", degree); - fprintf(outfile, "%d %d translate\n", position_left, position_bottom); - fprintf(outfile, "%f %f scale\n", width, height); - fprintf(outfile, "%d %d %d\n", image_info->image_width, image_info->image_height, depth); - fprintf(outfile, "[%d %d %d %d %d %d]\n", image_info->image_width, 0, 0, -image_info->image_height, 0, image_info->image_height); - fprintf(outfile, "currentfile\n"); - fprintf(outfile, "/ASCII85Decode filter\n"); -#ifdef HAVE_LIBZ - if (flatdecode) - { - fprintf(outfile, "/FlateDecode filter\n"); - } -#endif - - if (image_info->colors == 3) /* what about RGBA here ? */ - { - fprintf(outfile, "false 3 colorimage\n"); - fprintf(outfile, "\n"); - } - else - { - fprintf(outfile, "image\n"); - fprintf(outfile, "\n"); - } -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static void xsane_save_ps_create_page_trailer(FILE *outfile) -{ - fprintf(outfile, "\n"); - fprintf(outfile, "showpage\n"); - fprintf(outfile, "%%%%PageTrailer\n"); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef HAVE_LIBZ -/* Utility function for the PostScript output */ -static int xsane_write_compressed_a85_flatdecode(FILE *outfile, unsigned char *line, int len, int finish) -{ - static unsigned char *cbuf = NULL; - static int cbuflen = 0; - static int linelen = 0; - int i, j; - int outlen; - static int init = 0; - static z_stream s; - int ret; - int flush; - static int a85count = 0; - static guint32 a85tuple = 0; - static unsigned char a85block[6] = {0, 0, 0, 0, 0, 0}; - static int count = 0; - - DBG(DBG_proc, "xsane_write_compressed_a85_flatdecode\n"); - - if (linelen != len) - { - linelen = len; - if (cbuf != NULL) - { - free(cbuf); - } - /* buffer length = length + 0.1 * length + 12 (mandatory) */ - cbuflen = len + len / 10 + 12; - cbuf = malloc(cbuflen); - } - - if (cbuf == NULL) - { - DBG(DBG_error, "cbuf allocation failed\n"); - return 1; - } - - if (!init) - { - s.zalloc = Z_NULL; - s.zfree = Z_NULL; - s.opaque = Z_NULL; - - ret = deflateInit(&s, Z_DEFAULT_COMPRESSION); - - if (ret != Z_OK) - { - DBG(DBG_error, "deflateInit failed\n"); - free(cbuf); - return 1; - } - - init = 1; - } - - s.avail_in = len; - s.next_in = line; - - do - { - s.avail_out = cbuflen; - s.next_out = cbuf; - - flush = (finish) ? Z_FINISH : Z_NO_FLUSH; - - ret = deflate(&s, flush); - - if (ret == Z_STREAM_ERROR) - { - DBG(DBG_error, "deflate failed\n"); - free(cbuf); - return 1; - } - - outlen = cbuflen - s.avail_out; - - /* ASCII85 (base 85) encoding */ - for (i = 0; i < outlen; i++) - { - switch (a85count) - { - case 0: - a85tuple |= (cbuf[i] << 24); - a85count++; - break; - - case 1: - a85tuple |= (cbuf[i] << 16); - a85count++; - break; - - case 2: - a85tuple |= (cbuf[i] << 8); - a85count++; - break; - - case 3: - a85tuple |= (cbuf[i] << 0); - - if (count == 40) - { - fprintf(outfile, "\n"); - count = 0; - } - - if (a85tuple == 0) - { - fprintf(outfile, "z"); - count++; - } - else - { - /* The ASCII chars must be written in reverse order, hence -> a85block[4-j] */ - for (j = 0; j < 5; j++) - { - a85block[4-j] = a85tuple % 85 + '!'; - a85tuple /= 85; - } - - for (j = 0; j < 5; j++) - { - fprintf(outfile, "%c", a85block[j]); - count++; - if (count == 40) - { - fprintf(outfile, "\n"); - count = 0; - } - } - } - - a85count = 0; - a85tuple = 0; - break; - - default: - break; - } - } - } while (s.avail_out == 0); - - if (finish) - { - DBG(DBG_info, "finish\n"); - if (a85count > 0) - { - a85count++; - for (j = 0; j <= a85count; j++) - { - a85block[j] = a85tuple % 85 + '!'; - a85tuple /= 85; - } - /* Reverse order */ - for (j--; j > 0; j--) - { - if (count == 40) - { - fprintf(outfile, "\n"); - count = 0; - } - fprintf(outfile, "%c", a85block[j]); - count++; - } - } - - /* ASCII85 EOD marker + newline*/ - if (count + 2 > 40) - { - fprintf(outfile, "\n"); - } - fprintf(outfile, "~>\n"); - deflateEnd(&s); - free(cbuf); - cbuf = NULL; - init = 0; - a85tuple = 0; - a85count = 0; - cbuflen = 0; - linelen = 0; - count = 0; - } - - return 0; -} -#endif - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* Utility function for the PostScript output */ -static int xsane_write_compressed_a85(FILE *outfile, unsigned char *line, int len, int finish) -{ - static unsigned char *cbuf = NULL; - static int cbuflen = 0; - static int linelen = 0; - int i, j; - int outlen; - static int a85count = 0; - static guint32 a85tuple = 0; - static unsigned char a85block[6] = {0, 0, 0, 0, 0, 0}; - static int count = 0; - - DBG(DBG_proc, "xsane_write_compressed_a85\n"); - - cbuf = line; - outlen = len; - - /* ASCII85 (base 85) encoding */ - for (i = 0; i < outlen; i++) - { - switch (a85count) - { - case 0: - a85tuple |= (cbuf[i] << 24); - a85count++; - break; - - case 1: - a85tuple |= (cbuf[i] << 16); - a85count++; - break; - - case 2: - a85tuple |= (cbuf[i] << 8); - a85count++; - break; - - case 3: - a85tuple |= (cbuf[i] << 0); - - if (count == 40) - { - fprintf(outfile, "\n"); - count = 0; - } - - if (a85tuple == 0) - { - fprintf(outfile, "z"); - count++; - } - else - { - /* The ASCII chars must be written in reverse order, hence -> a85block[4-j] */ - for (j = 0; j < 5; j++) - { - a85block[4-j] = a85tuple % 85 + '!'; - a85tuple /= 85; - } - - for (j = 0; j < 5; j++) - { - fprintf(outfile, "%c", a85block[j]); - count++; - if (count == 40) - { - fprintf(outfile, "\n"); - count = 0; - } - } - } - - a85count = 0; - a85tuple = 0; - break; - - default: - break; - } - } - - if (finish) - { - DBG(DBG_info, "finish\n"); - if (a85count > 0) - { - a85count++; - for (j = 0; j <= a85count; j++) - { - a85block[j] = a85tuple % 85 + '!'; - a85tuple /= 85; - } - /* Reverse order */ - for (j--; j > 0; j--) - { - if (count == 40) - { - fprintf(outfile, "\n"); - count = 0; - } - fprintf(outfile, "%c", a85block[j]); - count++; - } - } - - /* ASCII85 EOD marker + newline*/ - if (count + 2 > 40) - { - fprintf(outfile, "\n"); - } - fprintf(outfile, "~>\n"); - a85tuple = 0; - a85count = 0; - cbuflen = 0; - linelen = 0; - count = 0; - } - - return 0; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_save_ps_pdf_bw(FILE *outfile, FILE *imagefile, Image_info *image_info, int flatdecode, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x, y; - int bytes_per_line = (image_info->image_width+7)/8; - int ret; - unsigned char *line; - - DBG(DBG_proc, "xsane_save_ps_pdf_bw\n"); - - *cancel_save = 0; - - line = (unsigned char *) malloc(bytes_per_line); - - if (line == NULL) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s malloc failed", ERR_DURING_SAVE); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - return (*cancel_save); - } - - for (y = 0; y < image_info->image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (x = 0; x < bytes_per_line; x++) - { - line[x] = fgetc(imagefile) ^ 255; - } - -#ifdef HAVE_LIBZ - if (flatdecode) - { - ret = xsane_write_compressed_a85_flatdecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); - } - else -#endif - { - ret = xsane_write_compressed_a85(outfile, line, bytes_per_line, (y == image_info->image_height - 1)); - } - - if ((ret != 0) || (ferror(outfile))) - { - char buf[255]; - - if (ret == 0) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - } - else - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_ZLIB); - } - - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - - break; - } - - if (*cancel_save) - { - break; - } - } - - free(line); - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_save_ps_pdf_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, int flatdecode, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x, y; - int ret; - unsigned char *line; - - DBG(DBG_proc, "xsane_save_ps_pdf_gray\n"); - - *cancel_save = 0; - - line = (unsigned char *) malloc(image_info->image_width); - - if (line == NULL) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s malloc failed", ERR_DURING_SAVE); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - return (*cancel_save); - } - - for (y = 0; y < image_info->image_height; y++) - { - if (image_info->depth > 8) /* reduce 16 bit images */ - { - guint16 val; - - for (x = 0; x < image_info->image_width; x++) - { - fread(&val, 2, 1, imagefile); - line[x] = val/256; - } - } - else /* 8 bits/sample */ - { - for (x = 0; x < image_info->image_width; x++) - { - line[x] = fgetc(imagefile); - } - } - -#ifdef HAVE_LIBZ - if (flatdecode) - { - ret = xsane_write_compressed_a85_flatdecode(outfile, line, image_info->image_width, (y == image_info->image_height - 1)); - } - else -#endif - { - ret = xsane_write_compressed_a85(outfile, line, image_info->image_width, (y == image_info->image_height - 1)); - } - - if ((ret != 0) || (ferror(outfile))) - { - char buf[255]; - - if (ret == 0) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - } - else - { - snprintf(buf, sizeof(buf), "%s zlib error or memory allocation problem", ERR_DURING_SAVE); - } - - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - - break; - } - - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - if (*cancel_save) - { - break; - } - } - - free(line); - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *image_info, int flatdecode, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x, y; - int ret; - unsigned char *line, *linep; - - DBG(DBG_proc, "xsane_save_ps_pdf_color\n"); - - *cancel_save = 0; - - line = (unsigned char *) malloc(image_info->image_width * 3); - - if (line == NULL) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s malloc failed", ERR_DURING_SAVE); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - return (*cancel_save); - } - - for (y = 0; y < image_info->image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - linep = line; - - if (image_info->depth > 8) /* reduce 16 bit images */ - { - guint16 val; - - for (x = 0; x < image_info->image_width; x++) - { - fread(&val, 2, 1, imagefile); - *linep++ = val/256; - fread(&val, 2, 1, imagefile); - *linep++ = val/256; - fread(&val, 2, 1, imagefile); - *linep++ = val/256; - } - } - else /* 8 bits/sample */ - { - for (x = 0; x < image_info->image_width; x++) - { - *linep++ = fgetc(imagefile); - *linep++ = fgetc(imagefile); - *linep++ = fgetc(imagefile); - } - } - -#ifdef HAVE_LIBZ - if (flatdecode) - { - ret = xsane_write_compressed_a85_flatdecode(outfile, line, (image_info->image_width * 3), (y == image_info->image_height - 1)); - } - else -#endif - { - ret = xsane_write_compressed_a85(outfile, line, (image_info->image_width * 3), (y == image_info->image_height - 1)); - } - - if ((ret != 0) || (ferror(outfile))) - { - char buf[255]; - - if (ret == 0) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - } - else - { - snprintf(buf, sizeof(buf), "%s zlib error or memory allocation problem", ERR_DURING_SAVE); - } - - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - - break; - } - - if (*cancel_save) - { - break; - } - } - - free(line); - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_ps_page(FILE *outfile, int page, - FILE *imagefile, Image_info *image_info, float width, float height, - int paper_left_margin, int paper_bottom_margin, int paperheight, int paperwidth, int paper_orientation, - int flatdecode, - GtkProgressBar *progress_bar, int *cancel_save) -{ - DBG(DBG_proc, "xsane_save_ps_page\n"); - - xsane_save_ps_create_page_header(outfile, page, - image_info, width, height, - paper_left_margin, paper_bottom_margin, paperheight, paperwidth, paper_orientation, - flatdecode, - progress_bar); - - if (image_info->colors == 1) /* lineart, halftone, grayscale */ - { - if (image_info->depth == 1) /* lineart, halftone */ - { - xsane_save_ps_pdf_bw(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); - } - else /* grayscale */ - { - xsane_save_ps_pdf_gray(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); - } - } - else /* color RGB */ - { - xsane_save_ps_pdf_color(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); - } - - xsane_save_ps_create_page_trailer(outfile); - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_ps(FILE *outfile, FILE *imagefile, Image_info *image_info, float width, float height, - int paper_left_margin, int paper_bottom_margin, int paperheight, int paperwidth, int paper_orientation, - int flatdecode, - GtkProgressBar *progress_bar, int *cancel_save) -{ - DBG(DBG_proc, "xsane_save_ps\n"); - - *cancel_save = 0; - - xsane_save_ps_create_document_header(outfile, 1 /* pages */, flatdecode); - - xsane_save_ps_page(outfile, 1 /* page */, - imagefile, image_info, width, height, - paper_left_margin, paper_bottom_margin, paperheight, paperwidth, paper_orientation, - flatdecode, - progress_bar, cancel_save); - - xsane_save_ps_create_document_trailer(outfile, 0 /* we defined pages at beginning */); - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* The pdf_xref struct holds byte offsets from the beginning of the PDF - * file to each object of the PDF file -- used to build the xref table - */ -struct pdf_xref -{ - unsigned long obj5; /* obj 5 0 */ - unsigned long obj6; /* obj 6 0 */ - unsigned long obj7; /* obj 7 0 */ - unsigned long xref; /* xref table */ - unsigned long slen; /* length of image stream */ - unsigned long slenp; /* position of image stream length */ -}; - -static void xsane_save_pdf_create_header(FILE *outfile, Image_info *image_info, - float width, float height, - int paper_left_margin, int paper_bottom_margin, - int paper_width, int paper_height, - int paper_orientation, int flatdecode, - GtkProgressBar *progress_bar, struct pdf_xref *xref) -{ - int position_left, position_bottom, box_left, box_bottom, box_right, box_top, depth; - int left, bottom; - float rad; - - DBG(DBG_proc, "xsane_save_pdf_create_header\n"); - - switch (paper_orientation) - { - default: - case 0: /* top left portrait */ - left = 0.0; - bottom = paper_height - height; - break; - - case 1: /* top right portrait */ - left = paper_width - width; - bottom = paper_height - height; - break; - - case 2: /* bottom right portrait */ - left = paper_width - width; - bottom = 0.0; - break; - - case 3: /* bottom left portrait */ - left = 0.0; - bottom = 0.0; - break; - - case 4: /* center portrait */ - left = paper_width / 2.0 - width / 2.0; - bottom = paper_height / 2.0 - height / 2.0; - break; - - - case 8: /* top left landscape */ - left = 0.0; - bottom = paper_width - height; - break; - - case 9: /* top right landscape */ - left = paper_height - width; - bottom = paper_width - height; - break; - - case 10: /* bottom right landscape */ - left = paper_height - width; - bottom = 0.0; - break; - - case 11: /* bottom left landscape */ - left = 0.0; - bottom = 0.0; - break; - - case 12: /* center landscape */ - left = paper_height / 2.0 - width / 2.0; - bottom = paper_width / 2.0 - height / 2.0; - break; - } - - - if (paper_orientation >= 8) /* rotate with 90 degrees - landscape mode */ - { - rad = -M_PI_2; /* pi / 2 */ - position_left = left + paper_bottom_margin; - position_bottom = bottom - paper_width - paper_left_margin; - box_left = paper_width - paper_left_margin - bottom - height; - box_bottom = left + paper_bottom_margin; - box_right = box_left + ceil(height); - box_top = box_bottom + ceil(width); - } - else /* do not rotate, portrait mode */ - { - rad = 0; - position_left = left + paper_left_margin; - position_bottom = bottom + paper_bottom_margin; - box_left = left + paper_left_margin; - box_bottom = bottom + paper_bottom_margin; - box_right = box_left + ceil(width); - box_top = box_bottom + ceil(height); - } - - depth = image_info->depth; - - if (depth > 8) - { - depth = 8; - } - - fprintf(outfile, "%%PDF-1.4\n"); - fprintf(outfile, "\n"); - fprintf(outfile, "1 0 obj\n"); - fprintf(outfile, " << /Type /Catalog\n"); - fprintf(outfile, " /Outlines 2 0 R\n"); - fprintf(outfile, " /Pages 3 0 R\n"); - fprintf(outfile, " >>\n"); - fprintf(outfile, "endobj\n"); - fprintf(outfile, "\n"); - fprintf(outfile, "2 0 obj\n"); - fprintf(outfile, " << /Type /Outlines\n"); - fprintf(outfile, " /Count 0\n"); - fprintf(outfile, " >>\n"); - fprintf(outfile, "endobj\n"); - fprintf(outfile, "\n"); - fprintf(outfile, "3 0 obj\n"); - fprintf(outfile, " << /Type /Pages\n"); - fprintf(outfile, " /Kids [4 0 R]\n"); - fprintf(outfile, " /Count 1\n"); - fprintf(outfile, " >>\n"); - fprintf(outfile, "endobj\n"); - fprintf(outfile, "\n"); - fprintf(outfile, "4 0 obj\n"); - fprintf(outfile, " << /Type /Page\n"); - fprintf(outfile, " /Parent 3 0 R\n"); - fprintf(outfile, " /MediaBox [%d %d %d %d]\n", box_left, box_bottom, box_right, box_top); - fprintf(outfile, " /Contents 5 0 R\n"); - fprintf(outfile, " /Resources << /ProcSet 6 0 R >>\n"); - fprintf(outfile, " >>\n"); - fprintf(outfile, "endobj\n"); - fprintf(outfile, "\n"); - - /* Offset of object 5, for xref */ - xref->obj5 = ftell(outfile); - - fprintf(outfile, "5 0 obj\n"); - fprintf(outfile, " << /Length >>\n"); - - /* Position of the stream length, to be written later on */ - xref->slenp = ftell(outfile) - 15; - - fprintf(outfile, "stream\n"); - - /* Start of the stream data */ - xref->slen = ftell(outfile); - - fprintf(outfile, "q\n"); - fprintf(outfile, "1 0 0 1 %d %d cm\n", position_left, position_bottom); /* translate */ - fprintf(outfile, "%f %f -%f %f 0 0 cm\n", cos(rad), sin(rad), sin(rad), cos(rad)); /* rotate */ - fprintf(outfile, "%f 0 0 %f 0 0 cm\n", width, height); /* scale */ - fprintf(outfile, "BI\n"); - fprintf(outfile, " /W %d\n", image_info->image_width); - fprintf(outfile, " /H %d\n", image_info->image_height); - - if (image_info->colors == 3) /* what about RGBA here ? */ - { - fprintf(outfile, " /CS /RGB\n"); - fprintf(outfile, " /BPC %d\n", depth); - } - else if (image_info->depth == 1) /* BW */ - { - fprintf(outfile, " /CS /G\n"); - fprintf(outfile, " /BPC 1\n"); - } - else /* gray */ - { - fprintf(outfile, " /CS /G\n"); - fprintf(outfile, " /BPC 8\n"); - } - -#ifdef HAVE_LIBZ - if (flatdecode) - { - fprintf(outfile, " /F [/A85 /FlateDecode]\n"); - } - else - { - fprintf(outfile, " /F /A85\n"); - } -#else - fprintf(outfile, " /F /A85\n"); -#endif - fprintf(outfile, "ID\n"); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_pdf(FILE *outfile, FILE *imagefile, Image_info *image_info, float width, float height, - int paper_left_margin, int paper_bottom_margin, int paperheight, int paperwidth, int paper_orientation, - int flatdecode, - GtkProgressBar *progress_bar, int *cancel_save) -{ - struct tm *t; - time_t tt; - struct pdf_xref xref; - - DBG(DBG_proc, "xsane_save_pdf\n"); - - *cancel_save = 0; - - xsane_save_pdf_create_header(outfile, image_info, width, height, - paper_left_margin, paper_bottom_margin, paperheight, paperwidth, paper_orientation, - flatdecode, - progress_bar, &xref); - - if (image_info->colors == 1) /* lineart, halftone, grayscale */ - { - if (image_info->depth == 1) /* lineart, halftone */ - { - xsane_save_ps_pdf_bw(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); - } - else /* grayscale */ - { - xsane_save_ps_pdf_gray(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); - } - } - else /* color RGB */ - { - xsane_save_ps_pdf_color(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save); - } - - /* PDF trailer */ - fprintf(outfile, "EI\n"); - fprintf(outfile, "Q\n"); - - /* Go back and write the length of the stream */ - xref.slen = ftell(outfile) - xref.slen - 1; - fseek(outfile, xref.slenp, SEEK_SET); - fprintf(outfile, "%lu", xref.slen); - fseek(outfile, 0L, SEEK_END); - - fprintf(outfile, "endstream\n"); - fprintf(outfile, "endobj\n"); - fprintf(outfile, "\n"); - - /* Offset of object 6, for xref */ - xref.obj6 = ftell(outfile); - - fprintf(outfile, "6 0 obj\n"); - fprintf(outfile, " [/PDF]\n"); - fprintf(outfile, "endobj\n"); - fprintf(outfile, "\n"); - - /* Offset of object 7, for xref */ - xref.obj7 = ftell(outfile); - - fprintf(outfile, "7 0 obj\n"); - fprintf(outfile, " << /Title (XSane scanned image)\n"); - fprintf(outfile, " /Creator (XSane version %s (sane %d.%d) - by Oliver Rauch)\n", - VERSION, - SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), - SANE_VERSION_MINOR(xsane.sane_backend_versioncode)); - fprintf(outfile, " /Producer (XSane %s)\n", VERSION); - - tt = time(NULL); - t = gmtime(&tt); - - fprintf(outfile, " /CreationDate (D:%04d%02d%02d%02d%02d%02d+00'00')\n", - 1900 + t->tm_year, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); - fprintf(outfile, " >>\n"); - fprintf(outfile, "endobj\n"); - fprintf(outfile, "\n"); - - /* Offset of xref, for startxref below */ - xref.xref = ftell(outfile); - - fprintf(outfile, "xref\n"); - fprintf(outfile, "0 8\n"); - fprintf(outfile, "0000000000 65535 f \n"); - fprintf(outfile, "0000000010 00000 n \n"); - fprintf(outfile, "0000000094 00000 n \n"); - fprintf(outfile, "0000000153 00000 n \n"); - fprintf(outfile, "0000000229 00000 n \n"); - fprintf(outfile, "%010lu 00000 n \n", xref.obj5); - fprintf(outfile, "%010lu 00000 n \n", xref.obj6); - fprintf(outfile, "%010lu 00000 n \n", xref.obj7); - fprintf(outfile, "\n"); - fprintf(outfile, "trailer\n"); - fprintf(outfile, " << /Size 8\n"); - fprintf(outfile, " /Root 1 0 R\n"); - fprintf(outfile, " /Info 7 0 R\n"); - fprintf(outfile, " >>\n"); - fprintf(outfile, "startxref\n"); - fprintf(outfile, "%lu\n", xref.xref); - fprintf(outfile, "%%%%EOF\n"); - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ -#ifdef HAVE_LIBJPEG - -typedef struct -{ - struct jpeg_error_mgr pub;/* "public" fields */ - int *cancel_save; -} xsane_jpeg_error_mgr; - -typedef xsane_jpeg_error_mgr *xsane_jpeg_error_mgr_ptr; - -static void xsane_jpeg_error_exit(j_common_ptr cinfo) -{ - char buf[256]; - - /* cinfo->err points to a xsane_jpeg_error_mgr struct */ - xsane_jpeg_error_mgr_ptr xsane_jpeg_error_mgr_data = (xsane_jpeg_error_mgr_ptr) cinfo->err; - - - if (!*xsane_jpeg_error_mgr_data->cancel_save) - { - /* output original error message */ - (*cinfo->err->output_message) (cinfo); - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBJPEG); - xsane_back_gtk_error(buf, TRUE); - } - - *xsane_jpeg_error_mgr_data->cancel_save = 1; -} - -int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int quality, GtkProgressBar *progress_bar, int *cancel_save) -{ - unsigned char *data; - char buf[256]; - int components = 1; - int x,y; - int bytespp = 1; - struct jpeg_compress_struct cinfo; - xsane_jpeg_error_mgr jerr; - JSAMPROW row_pointer[1]; - - DBG(DBG_proc, "xsane_save_jpeg\n"); - - *cancel_save = 0; - - if (image_info->colors == 3) - { - components = 3; - } - - if (image_info->depth > 8) - { - bytespp = 2; - } - - data = malloc(image_info->image_width * components * bytespp); - - if (!data) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); - xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ - } - - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = xsane_jpeg_error_exit; - jerr.cancel_save = cancel_save; - - jpeg_create_compress(&cinfo); - jpeg_stdio_dest(&cinfo, outfile); - cinfo.image_width = image_info->image_width; - cinfo.image_height = image_info->image_height; - cinfo.input_components = components; - if (image_info->colors == 3) - { - cinfo.in_color_space = JCS_RGB; - } - else - { - cinfo.in_color_space = JCS_GRAYSCALE; - } - jpeg_set_defaults(&cinfo); - - jpeg_set_quality(&cinfo, quality, TRUE); - - cinfo.density_unit = 1; /* dpi */ - cinfo.X_density = image_info->resolution_x; - cinfo.Y_density = image_info->resolution_y; - - jpeg_start_compress(&cinfo, TRUE); - - for (y = 0; y < image_info->image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - if (image_info->depth == 1) - { - int byte = 0; - int mask = 128; - - for (x = 0; x < image_info->image_width; x++) - { - - if ( (x % 8) == 0) - { - byte = fgetc(imagefile); - mask = 128; - } - - if (byte & mask) - { - data[x] = 0; - } - else - { - data[x] = 255; - } - mask >>= 1; - } - } - else if (image_info->depth > 8) /* jpeg does not support 16 bits/sample, so we reduce it at first */ - { - guint16 *data16 = (guint16 *) data; - fread(data, components * 2, image_info->image_width, imagefile); - for (x = 0; x < image_info->image_width * components; x++) - { - data[x] = data16[x] / 256; - } - - } - else /* 8 bits/sample */ - { - fread(data, components, image_info->image_width, imagefile); - } - - row_pointer[0] = data; - jpeg_write_scanlines(&cinfo, row_pointer, 1); - - if (*cancel_save) - { - cinfo.image_height = y; /* correct image height */ - break; - } - } - - jpeg_finish_compress(&cinfo); - free(data); - - return (*cancel_save); -} -#endif - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef HAVE_LIBTIFF -/* pages = 0 => single page tiff, page = 0 */ -/* pages > 0 => page = [1 .. pages] */ -int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Image_info *image_info, int quality, - GtkProgressBar *progress_bar, int *cancel_save) -{ - char *data; - char buf[256]; - int y, w; - int components; - int compression; - int bytes; - struct tm *ptm; - time_t now; - - DBG(DBG_proc, "xsane_save_tiff_page(%d/%d\n", page, pages); - - *cancel_save = 0; - - if (image_info->depth == 1) - { - compression = preferences.tiff_compression1_nr; - } - else if (image_info->depth == 8) - { - compression = preferences.tiff_compression8_nr; - } - else - { - compression = preferences.tiff_compression16_nr; - } - - - if (image_info->colors == 3) - { - components = 3; - } - else - { - components = 1; - } - - if (image_info->depth <= 8) - { - bytes = 1; - } - else - { - bytes = 2; - } - - data = (char *)_TIFFmalloc(image_info->image_width * components * bytes); - - if (!data) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); - xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ - } - - TIFFSetField(tiffile, TIFFTAG_IMAGEWIDTH, image_info->image_width); - TIFFSetField(tiffile, TIFFTAG_IMAGELENGTH, image_info->image_height); - TIFFSetField(tiffile, TIFFTAG_BITSPERSAMPLE, image_info->depth); - TIFFSetField(tiffile, TIFFTAG_SAMPLESPERPIXEL, components); - TIFFSetField(tiffile, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tiffile, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tiffile, TIFFTAG_COMPRESSION, compression); - TIFFSetField(tiffile, TIFFTAG_SOFTWARE, "xsane"); - - time(&now); - ptm = localtime(&now); - sprintf(buf, "%04d:%02d:%02d %02d:%02d:%02d", 1900+ptm->tm_year, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec); - TIFFSetField(tiffile, TIFFTAG_DATETIME, buf); - - if (image_info->resolution_x > 0.0) - { - TIFFSetField(tiffile, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - TIFFSetField(tiffile, TIFFTAG_XRESOLUTION, image_info->resolution_x); - TIFFSetField(tiffile, TIFFTAG_YRESOLUTION, image_info->resolution_y); - } - - if (compression == COMPRESSION_JPEG) - { - TIFFSetField(tiffile, TIFFTAG_JPEGQUALITY, quality); - TIFFSetField(tiffile, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW); /* should be default, but to be sure */ - } - - if (image_info->colors == 3) - { - TIFFSetField(tiffile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); - } - else - { - if (image_info->depth == 1) /* lineart */ - { - TIFFSetField(tiffile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); - } - else /* grayscale */ - { - TIFFSetField(tiffile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); - } - } - - TIFFSetField(tiffile, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tiffile, -1)); - - if (pages) - { - TIFFSetField(tiffile, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); - TIFFSetField(tiffile, TIFFTAG_PAGENUMBER, page, pages); - } - - w = TIFFScanlineSize(tiffile); - - for (y = 0; y < image_info->image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - fread(data, 1, w, imagefile); - - if (TIFFWriteScanline(tiffile, data, y, 0) != 1) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s", ERR_DURING_SAVE); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - - if (pages) - { - TIFFWriteDirectory(tiffile); - } - - _TIFFfree(data); - return (*cancel_save); -} -#endif - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef HAVE_LIBPNG -#ifdef HAVE_LIBZ -int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int compression, GtkProgressBar *progress_bar, int *cancel_save) -{ - png_structp png_ptr; - png_infop png_info_ptr; - png_bytep row_ptr; - png_color_8 sig_bit; - unsigned char *data; - char buf[256]; - int colortype, components, byte_width; - int y; - - DBG(DBG_proc, "xsane_save_png\n"); - - *cancel_save = 0; - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!png_ptr) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBPNG); - xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ - } - - png_info_ptr = png_create_info_struct(png_ptr); - if (!png_info_ptr) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBTIFF); - xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ - } - - if (setjmp(png_ptr->jmpbuf)) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBPNG); - xsane_back_gtk_error(buf, TRUE); - png_destroy_write_struct(&png_ptr, (png_infopp) 0); - return -1; /* error */ - } - - byte_width = image_info->image_width; - - if (image_info->colors == 4) /* RGBA */ - { - components = 4; - colortype = PNG_COLOR_TYPE_RGB_ALPHA; - } - else if (image_info->colors == 3) /* RGB */ - { - components = 3; - colortype = PNG_COLOR_TYPE_RGB; - } - else /* gray or black/white */ - { - components = 1; - colortype = PNG_COLOR_TYPE_GRAY; - } - - png_init_io(png_ptr, outfile); - png_set_compression_level(png_ptr, compression); - png_set_IHDR(png_ptr, png_info_ptr, image_info->image_width, image_info->image_height, image_info->depth, - colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - if (image_info->colors >=3) - { - sig_bit.red = image_info->depth; - sig_bit.green = image_info->depth; - sig_bit.blue = image_info->depth; - - if (image_info->colors == 4) - { - sig_bit.alpha = image_info->depth; - } - - } - else - { - sig_bit.gray = image_info->depth; - - if (image_info->depth == 1) - { - byte_width = (image_info->image_width+7)/8; - png_set_invert_mono(png_ptr); - } - } - - png_set_sBIT(png_ptr, png_info_ptr, &sig_bit); -#if defined(PNG_pHYs_SUPPORTED) - png_set_pHYs(png_ptr, png_info_ptr, - image_info->resolution_x * 100.0 / 2.54, - image_info->resolution_y * 100.0 / 2.54, PNG_RESOLUTION_METER); -#endif - png_write_info(png_ptr, png_info_ptr); - png_set_shift(png_ptr, &sig_bit); - - data = malloc(image_info->image_width * components); - - if (!data) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); - xsane_back_gtk_error(buf, TRUE); - png_destroy_write_struct(&png_ptr, (png_infopp) 0); - return -1; /* error */ - } - - for (y = 0; y < image_info->image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - fread(data, components, byte_width, imagefile); - - row_ptr = data; - png_write_rows(png_ptr, &row_ptr, 1); /* errors are caught by test sor setjmp(...) */ - - if (*cancel_save) - { - break; - } - } - - free(data); - png_write_end(png_ptr, png_info_ptr); - png_destroy_write_struct(&png_ptr, (png_infopp) 0); - - return (*cancel_save); -} -#endif -#endif - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef HAVE_LIBPNG -#ifdef HAVE_LIBZ -int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, int compression, GtkProgressBar *progress_bar, int *cancel_save) -{ - png_structp png_ptr; - png_infop png_info_ptr; - png_bytep row_ptr; - png_color_8 sig_bit; /* should be 16, but then I get a warning about wrong type */ - unsigned char *data; - char buf[256]; - int colortype, components; - int x,y; - guint16 val; - - DBG(DBG_proc, "xsane_save_png16\n"); - - *cancel_save = 0; - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!png_ptr) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBPNG); - xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ - } - - png_info_ptr = png_create_info_struct(png_ptr); - if (!png_info_ptr) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBPNG); - xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ - } - - if (setjmp(png_ptr->jmpbuf)) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBPNG); - xsane_back_gtk_error(buf, TRUE); - png_destroy_write_struct(&png_ptr, (png_infopp) 0); - return -1; /* error */ - } - - if (image_info->colors == 4) /* RGBA */ - { - components = 4; - colortype = PNG_COLOR_TYPE_RGB_ALPHA; - } - else if (image_info->colors == 3) /* RGB */ - { - components = 3; - colortype = PNG_COLOR_TYPE_RGB; - } - else /* gray or black/white */ - { - components = 1; - colortype = PNG_COLOR_TYPE_GRAY; - } - - png_init_io(png_ptr, outfile); - png_set_compression_level(png_ptr, compression); - png_set_IHDR(png_ptr, png_info_ptr, image_info->image_width, image_info->image_height, 16, - colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - sig_bit.red = image_info->depth; - sig_bit.green = image_info->depth; - sig_bit.blue = image_info->depth; - sig_bit.alpha = image_info->depth; - sig_bit.gray = image_info->depth; - - png_set_sBIT(png_ptr, png_info_ptr, &sig_bit); - png_write_info(png_ptr, png_info_ptr); - png_set_shift(png_ptr, &sig_bit); - png_set_packing(png_ptr); - - data = malloc(image_info->image_width * components * 2); - - if (!data) - { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); - xsane_back_gtk_error(buf, TRUE); - png_destroy_write_struct(&png_ptr, (png_infopp) 0); - return -1; /* error */ - } - - for (y = 0; y < image_info->image_height; y++) - { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - for (x = 0; x < image_info->image_width * components; x++) /* this must be changed in dependance of endianess */ - { - fread(&val, 2, 1, imagefile); /* get data in machine order */ - data[x*2+0] = val / 256; /* write data in network order (MSB first) */ - data[x*2+1] = val & 255; - } - - row_ptr = data; - png_write_rows(png_ptr, &row_ptr, 1); - if (*cancel_save) - { - break; - } - } - - free(data); - png_write_end(png_ptr, png_info_ptr); - png_destroy_write_struct(&png_ptr, (png_infopp) 0); - - return (*cancel_save); -} -#endif -#endif - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_save_pnm_16_ascii_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x,y; - guint16 val; - int count = 0; - - DBG(DBG_proc, "xsane_save_pnm_16_ascii_gray\n"); - - *cancel_save = 0; - - for (y = 0; y < image_info->image_height; y++) - { - for (x = 0; x < image_info->image_width; x++) - { - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fprintf(outfile, "%d ", val); - - if (++count >= 10) - { - fprintf(outfile, "\n"); - count = 0; - } - } - fprintf(outfile, "\n"); - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - count = 0; - - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - if (*cancel_save) - { - break; - } - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_save_pnm_16_ascii_color(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x,y; - guint16 val; - int count = 0; - - DBG(DBG_proc, "xsane_save_pnm_16_ascii_color\n"); - - *cancel_save = 0; - - for (y = 0; y < image_info->image_height; y++) - { - for (x = 0; x < image_info->image_width; x++) - { - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fprintf(outfile, "%d ", val); - - fread(&val, 2, 1, imagefile); - fprintf(outfile, "%d ", val); - - fread(&val, 2, 1, imagefile); - fprintf(outfile, "%d ", val); - - if (++count >= 3) - { - fprintf(outfile, "\n"); - count = 0; - } - } - fprintf(outfile, "\n"); - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - count = 0; - - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - if (*cancel_save) - { - break; - } - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_save_pnm_16_binary_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x,y; - guint16 val; - - DBG(DBG_proc, "xsane_save_pnm_16_binary_gray\n"); - - *cancel_save = 0; - - for (y = 0; y < image_info->image_height; y++) - { - for (x = 0; x < image_info->image_width; x++) - { - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fputc(val / 256, outfile); /* MSB fist */ - fputc(val & 255, outfile); /* LSB */ - } - - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_save_pnm_16_binary_color(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) -{ - int x,y; - guint16 val; - - DBG(DBG_proc, "xsane_save_pnm_16_binary_color\n"); - - *cancel_save = 0; - - for (y = 0; y < image_info->image_height; y++) - { - for (x = 0; x < image_info->image_width; x++) - { - /* red */ - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fputc(val / 256, outfile); /* MSB fist */ - fputc(val & 255, outfile); /* LSB */ - - /* green */ - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fputc(val / 256, outfile); /* MSB fist */ - fputc(val & 255, outfile); /* LSB */ - - /* blue */ - fread(&val, 2, 1, imagefile); /* get data in machine order */ - fputc(val / 256, outfile); /* MSB fist */ - fputc(val & 255, outfile); /* LSB */ - } - - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - - if (ferror(outfile)) - { - char buf[255]; - - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); - DBG(DBG_error, "%s\n", buf); - xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); - *cancel_save = 1; - break; - } - - if (*cancel_save) - { - break; - } - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) -{ - DBG(DBG_proc, "xsane_save_pnm_16\n"); - - *cancel_save = 0; - - xsane_write_pnm_header(outfile, image_info, preferences.save_pnm16_as_ascii); - - if (image_info->colors > 1) - { - if (preferences.save_pnm16_as_ascii) - { - xsane_save_pnm_16_ascii_color(outfile, imagefile, image_info, progress_bar, cancel_save); - } - else - { - xsane_save_pnm_16_binary_color(outfile, imagefile, image_info, progress_bar, cancel_save); - } - } - else - { - if (preferences.save_pnm16_as_ascii) - { - xsane_save_pnm_16_ascii_gray(outfile, imagefile, image_info, progress_bar, cancel_save); - } - else - { - xsane_save_pnm_16_binary_gray(outfile, imagefile, image_info, progress_bar, cancel_save); - } - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* 0=ok, <0=error, 1=canceled */ -int xsane_save_image_as_lineart(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save) -{ - FILE *outfile; - FILE *infile; - char buf[256]; - Image_info image_info; - - *cancel_save = 0; - - outfile = fopen(output_filename, "wb"); /* b = binary mode for win32 */ - - if (outfile == 0) - { - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, output_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - return -2; - } - - infile = fopen(input_filename, "rb"); /* read binary (b for win32) */ - if (infile == 0) - { - char buf[256]; - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, input_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - - fclose(outfile); - remove(output_filename); /* remove already created output file */ - return -1; - } - - xsane_read_pnm_header(infile, &image_info); - - xsane_save_grayscale_image_as_lineart(outfile, infile, &image_info, progress_bar, cancel_save); - - fclose(infile); - fclose(outfile); - - if (*cancel_save) /* remove output file if saving has been canceled */ - { - remove(output_filename); - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_save_image_as_text(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save) -{ - char *arg[1000]; - char buf[256]; - int argnr; - pid_t pid; - int i; - int pipefd[2]; /* for progress communication with gocr */ - FILE *ocr_progress = NULL; - - DBG(DBG_proc, "xsane_save_image_as_text\n"); - - argnr = xsane_parse_options(preferences.ocr_command, arg); - - arg[argnr++] = strdup(preferences.ocr_inputfile_option); - arg[argnr++] = strdup(input_filename); - - arg[argnr++] = strdup(preferences.ocr_outputfile_option); - arg[argnr++] = strdup(output_filename); - - if (preferences.ocr_use_gui_pipe) - { - if (!pipe(pipefd)) /* success */ - { - DBG(DBG_info, "xsane_save_image_as_text: created pipe for progress communication\n"); - - arg[argnr++] = strdup(preferences.ocr_gui_outfd_option); - - snprintf(buf, sizeof(buf),"%d", pipefd[1]); - arg[argnr++] = strdup(buf); - } - else - { - DBG(DBG_info, "xsane_save_image_as_text: could not create pipe for progress communication\n"); - pipefd[0] = 0; - pipefd[1] = 0; - } - } - else - { - DBG(DBG_info, "xsane_save_image_as_text: no pipe for progress communication requested\n"); - pipefd[0] = 0; - pipefd[1] = 0; - } - - arg[argnr] = 0; - -#ifndef HAVE_OS2_H - pid = fork(); - - if (pid == 0) /* new process */ - { - FILE *ipc_file = NULL; - - if (xsane.ipc_pipefd[0]) /* did we create the progress pipe? */ - { - close(xsane.ipc_pipefd[0]); /* close reading end of pipe */ - ipc_file = fdopen(xsane.ipc_pipefd[1], "w"); - } - - if (pipefd[0]) /* did we create the progress pipe? */ - { - close(pipefd[0]); /* close reading end of pipe */ - } - - DBG(DBG_info, "trying to change user id for new subprocess:\n"); - DBG(DBG_info, "old effective uid = %d\n", (int) geteuid()); - setuid(getuid()); - DBG(DBG_info, "new effective uid = %d\n", (int) geteuid()); - - - execvp(arg[0], arg); /* does not return if successfully */ - DBG(DBG_error, "%s %s\n", ERR_FAILED_EXEC_OCR_CMD, preferences.ocr_command); - - /* send error message via IPC pipe to parent process */ - if (ipc_file) - { - fprintf(ipc_file, "%s %s:\n%s", ERR_FAILED_EXEC_OCR_CMD, preferences.ocr_command, strerror(errno)); - fflush(ipc_file); /* make sure message is displayed */ - fclose(ipc_file); - } - - _exit(0); /* do not use exit() here! otherwise gtk gets in trouble */ - } - -#else - pid = spawnvp(P_NOWAIT, arg[0], arg); - if (pid == -1) - { - DBG(DBG_error, "%s %s\n", ERR_FAILED_EXEC_OCR_CMD, preferences.ocr_command); - } -#endif - - if (pipefd[1]) - { - close(pipefd[1]); /* close writing end of pipe */ - ocr_progress = fdopen(pipefd[0], "r"); /* open reading end of pipe as file */ - } - - for (i=0; i<argnr; i++) - { - free(arg[i]); - } - - if (ocr_progress) /* pipe available */ - { - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); - - while (!feof(ocr_progress)) - { - int progress, subprogress; - float fprogress; - - fgets(buf, sizeof(buf), ocr_progress); - - if (!strncmp(preferences.ocr_progress_keyword, buf, strlen(preferences.ocr_progress_keyword))) - { - sscanf(buf + strlen(preferences.ocr_progress_keyword), "%d %d", &progress, &subprogress); - - snprintf(buf, sizeof(buf), "%s (%d:%d)", PROGRESS_OCR, progress, subprogress); - gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), buf); - - fprogress = progress / 100.0; - - if (fprogress < 0.0) - { - fprogress = 0.0; - } - - if (fprogress > 11.0) - { - fprogress = 1.0; - } - - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), fprogress); - } - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } - - gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); - } - else /* no pipe available */ - { - while (pid) - { - int status = 0; - pid_t pid_status = waitpid(pid, &status, WNOHANG); - - if (pid == pid_status) - { - pid = 0; /* ok, child process has terminated */ - } - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } - } - - if (pipefd[0]) - { - fclose(ocr_progress); /* close reading end of pipe */ - } - - return (*cancel_save); -} -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* save image in destination file format. lineart images that are stored as grayscale image are reduced to lineart! */ -int xsane_save_image_as(char *output_filename, char *input_filename, int output_format, GtkProgressBar *progress_bar, int *cancel_save) -{ - FILE *outfile; - FILE *infile; - char buf[256]; - Image_info image_info; - char lineart_filename[PATH_MAX]; - int remove_input_file = FALSE; - - DBG(DBG_proc, "xsane_save_image_as(output_file=%s, input_file=%s, type=%d)\n", output_filename, input_filename, output_format); - - *cancel_save = 0; - - infile = fopen(input_filename, "rb"); /* read binary (b for win32) */ - if (infile == 0) - { - char buf[256]; - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, input_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - - return -1; - } - - xsane_read_pnm_header(infile, &image_info); - - if ((image_info.reduce_to_lineart) && (output_format != XSANE_PNM)) - { - DBG(DBG_info, "original image is a lineart => reduce to lineart\n"); - fclose(infile); - xsane_back_gtk_make_path(sizeof(lineart_filename), lineart_filename, 0, 0, "xsane-conversion-", xsane.dev_name, ".pbm", XSANE_PATH_TMP); - - snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_PACKING_DATA, output_filename); - - gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), buf); - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - xsane_save_image_as_lineart(lineart_filename, input_filename, progress_bar, cancel_save); - - input_filename = lineart_filename; - remove_input_file = TRUE; - - infile = fopen(input_filename, "rb"); /* read binary (b for win32) */ - if (infile == 0) - { - char buf[256]; - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, input_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - - return -1; - } - - xsane_read_pnm_header(infile, &image_info); - } - - snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_SAVING_DATA, output_filename); - - gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), buf); - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - -#ifdef HAVE_LIBTIFF - if (output_format == XSANE_TIFF) /* routines that want to have filename for saving */ - { - TIFF *tiffile; - - if (xsane_create_secure_file(output_filename)) /* remove possibly existing symbolic links for security */ - { - snprintf(buf, sizeof(buf), "%s %s %s\n", ERR_DURING_SAVE, ERR_CREATE_SECURE_FILE, output_filename); - xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ - } - - tiffile = TIFFOpen(output_filename, "w"); - if (!tiffile) - { - snprintf(buf, sizeof(buf), "%s %s %s\n", ERR_DURING_SAVE, ERR_OPEN_FAILED, output_filename); - xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ - } - - xsane_save_tiff_page(tiffile, 0, 0, infile, &image_info, preferences.jpeg_quality, progress_bar, cancel_save); - - TIFFClose(tiffile); - } - else /* routines that want to have filedescriptor for saving */ -#endif /* HAVE_LIBTIFF */ - { - if (xsane_create_secure_file(output_filename)) /* remove possibly existing symbolic links for security */ - { - snprintf(buf, sizeof(buf), "%s %s %s\n", ERR_DURING_SAVE, ERR_CREATE_SECURE_FILE, output_filename); - xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ - } - - outfile = fopen(output_filename, "wb"); /* b = binary mode for win32 */ - - if (outfile != 0) - { - switch(output_format) - { - case XSANE_PNM: - if (image_info.reduce_to_lineart) - { - xsane_save_grayscale_image_as_lineart(outfile, infile, &image_info, progress_bar, cancel_save); - } - else - { - xsane_copy_file(outfile, infile, progress_bar, cancel_save); - } - break; - -#ifdef HAVE_LIBJPEG - case XSANE_JPEG: - xsane_save_jpeg(outfile, infile, &image_info, preferences.jpeg_quality, progress_bar, cancel_save); - break; /* switch format == XSANE_JPEG */ -#endif - -#ifdef HAVE_LIBPNG -#ifdef HAVE_LIBZ - case XSANE_PNG: - if (image_info.depth <= 8) - { - xsane_save_png(outfile, infile, &image_info, preferences.png_compression, progress_bar, cancel_save); - } - else - { - xsane_save_png_16(outfile, infile, &image_info, preferences.png_compression, progress_bar, cancel_save); - } - break; /* switch format == XSANE_PNG */ -#endif -#endif - - case XSANE_PNM16: - xsane_save_pnm_16(outfile, infile, &image_info, progress_bar, cancel_save); - break; /* switch fomat == XSANE_PNM16 */ - - case XSANE_PS: /* save postscript, use original size */ - { - float imagewidth, imageheight; - - imagewidth = 72.0 * image_info.image_width/image_info.resolution_x; /* width in 1/72 inch */ - imageheight = 72.0 * image_info.image_height/image_info.resolution_y; /* height in 1/72 inch */ - - xsane_save_ps(outfile, infile, - &image_info, - imagewidth, imageheight, - 0, /* paper_left_margin */ - 0, /* paper_bottom_margin */ - (int) imagewidth, /* paper_width */ - (int) imageheight, /* paper_height */ - 0 /* portrait top left */, - preferences.save_ps_flatdecoded, - progress_bar, - cancel_save); - } - break; /* switch format == XSANE_PS */ - - case XSANE_PDF: /* save PDF, use original size */ - { - float imagewidth, imageheight; - - imagewidth = 72.0 * image_info.image_width/image_info.resolution_x; /* width in 1/72 inch */ - imageheight = 72.0 * image_info.image_height/image_info.resolution_y; /* height in 1/72 inch */ - - xsane_save_pdf(outfile, infile, - &image_info, - imagewidth, imageheight, - 0, /* paper_left_margin */ - 0, /* paper_bottom_margin */ - (int) imagewidth, /* paper_width */ - (int) imageheight, /* paper_height */ - 0 /* portrait top left */, - preferences.save_pdf_flatdecoded, - progress_bar, - cancel_save); - } - break; /* switch format == XSANE_PDF */ - - case XSANE_TEXT: /* save as text using ocr program like gocr/jocr */ - { - xsane_save_image_as_text(output_filename, input_filename, progress_bar, cancel_save); - } - break; /* switch format == XSANE_TEXT */ - - default: - snprintf(buf, sizeof(buf),"%s", ERR_UNKNOWN_SAVING_FORMAT); - xsane_back_gtk_error(buf, TRUE); - - fclose(outfile); - fclose(infile); - - remove(output_filename); /* no usable output: remove output file */ - - if (remove_input_file) - { - remove(input_filename); /* remove lineart pbm file */ - } - - gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - return -2; - break; /* switch format == default */ - } - fclose(outfile); - } - else - { - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, output_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - - fclose(infile); - - if (remove_input_file) - { - remove(input_filename); /* remove lineart pbm file */ - } - - gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - return -2; - } - } - - fclose (infile); - - if (remove_input_file) - { - remove(input_filename); /* remove lineart pbm file */ - } - - if (*cancel_save) /* remove output file if saving has been canceled */ - { - remove(output_filename); - } - - gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); - gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - return (*cancel_save); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef HAVE_ANY_GIMP -static int xsane_decode_devname(const char *encoded_devname, int n, char *buf) -{ - char *dst, *limit; - const char *src; - char ch, val; - - DBG(DBG_proc, "xsane_decode_devname\n"); - - limit = buf + n; - for (src = encoded_devname, dst = buf; *src; ++dst) - { - if (dst >= limit) - { - return -1; - } - - ch = *src++; - /* don't use the ctype.h macros here since we don't want to allow anything non-ASCII here... */ - if (ch != '-') - { - *dst = ch; - } - else /* decode */ - { - ch = *src++; - if (ch == '-') - { - *dst = ch; - } - else - { - if (ch >= 'a' && ch <= 'f') - { - val = (ch - 'a') + 10; - } - else - { - val = (ch - '0'); - } - val <<= 4; - - ch = *src++; - if (ch >= 'a' && ch <= 'f') - { - val |= (ch - 'a') + 10; - } - else - { - val |= (ch - '0'); - } - - *dst = val; - - ++src; /* simply skip terminating '-' for now... */ - } - } - } - - if (dst >= limit) - { - return -1; - } - - *dst = '\0'; - return 0; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_encode_devname(const char *devname, int n, char *buf) -{ - static const char hexdigit[] = "0123456789abcdef"; - char *dst, *limit; - const char *src; - char ch; - - DBG(DBG_proc, "xsane_encode_devname\n"); - - limit = buf + n; - for (src = devname, dst = buf; *src; ++src) - { - if (dst >= limit) - { - return -1; - } - - ch = *src; - /* don't use the ctype.h macros here since we don't want to allow anything non-ASCII here... */ - if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) - { - *dst++ = ch; - } - else /* encode */ - { - if (dst + 4 >= limit) - { - return -1; - } - - *dst++ = '-'; - if (ch == '-') - { - *dst++ = '-'; - } - else - { - *dst++ = hexdigit[(ch >> 4) & 0x0f]; - *dst++ = hexdigit[(ch >> 0) & 0x0f]; - *dst++ = '-'; - } - } - } - - if (dst >= limit) - { - return -1; - } - - *dst = '\0'; - return 0; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static void xsane_gimp_query(void) -{ - static GimpParamDef args[] = - { - {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, - }; - static GimpParamDef *return_vals = NULL; - static int nargs = sizeof(args) / sizeof(args[0]); - static int nreturn_vals = 0; - char mpath[1024]; - char name[1024]; - size_t len; - int i, j; - - DBG(DBG_proc, "xsane_gimp_query\n"); - - snprintf(name, sizeof(name), "%s", xsane.prog_name); -#ifdef GIMP_CHECK_VERSION -# if GIMP_CHECK_VERSION(1,1,9) - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_DIALOG); -# else - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_DIALOG_OLD); -# endif -#else - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_DIALOG_OLD); -#endif - gimp_install_procedure(name, - XSANE_GIMP_INSTALL_BLURB, - XSANE_GIMP_INSTALL_HELP, - XSANE_AUTHOR, - XSANE_COPYRIGHT, - XSANE_DATE, - mpath, - 0, /* "RGB, GRAY", */ - GIMP_EXTENSION, - nargs, nreturn_vals, - args, return_vals); - - sane_init(&xsane.sane_backend_versioncode, (void *) xsane_authorization_callback); - if (SANE_VERSION_MAJOR(xsane.sane_backend_versioncode) != SANE_V_MAJOR) - { - DBG(DBG_error0, "\n\n" - "%s %s:\n" - " %s\n" - " %s %d\n" - " %s %d\n" - "%s\n\n", - xsane.prog_name, ERR_ERROR, - ERR_MAJOR_VERSION_NR_CONFLICT, - ERR_XSANE_MAJOR_VERSION, SANE_V_MAJOR, - ERR_BACKEND_MAJOR_VERSION, SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), - ERR_PROGRAM_ABORTED); - return; - } - - sane_get_devices(&xsane.devlist, SANE_FALSE); - - for (i = 0; xsane.devlist[i]; ++i) - { - snprintf(name, sizeof(name), "%s-", xsane.prog_name); - if (xsane_encode_devname(xsane.devlist[i]->name, sizeof(name) - 6, name + 6) < 0) - { - continue; /* name too long... */ - } - -#ifdef GIMP_CHECK_VERSION -# if GIMP_CHECK_VERSION(1,1,9) - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU); -# else - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_OLD); -# endif -#else - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_OLD); -#endif - len = strlen(mpath); - for (j = 0; xsane.devlist[i]->name[j]; ++j) - { - if (xsane.devlist[i]->name[j] == '/') - { - mpath[len++] = '\''; - } - else - { - mpath[len++] = xsane.devlist[i]->name[j]; - } - } - mpath[len++] = '\0'; - - gimp_install_procedure(name, - XSANE_GIMP_INSTALL_BLURB, - XSANE_GIMP_INSTALL_HELP, - XSANE_AUTHOR, - XSANE_COPYRIGHT, - XSANE_DATE, - mpath, - 0, /* "RGB, GRAY", */ - GIMP_EXTENSION, - nargs, nreturn_vals, - args, return_vals); - } - - sane_exit(); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef HAVE_GIMP_2 -static void xsane_gimp_run(const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) -{ - GimpRunMode run_mode; -#else /* GIMP-1.x */ -static void xsane_gimp_run(char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals) -{ - GimpRunModeType run_mode; -#endif - - static GimpParam values[2]; - char devname[1024]; - char *args[2]; - int nargs; - - DBG(DBG_proc, "xsane_gimp_run\n"); - - run_mode = param[0].data.d_int32; - xsane.mode = XSANE_GIMP_EXTENSION; - xsane.xsane_mode = XSANE_SAVE; - - *nreturn_vals = 1; - *return_vals = values; - - values[0].type = GIMP_PDB_STATUS; - values[0].data.d_status = GIMP_PDB_CALLING_ERROR; - - nargs = 0; - args[nargs++] = "xsane"; - - xsane.selected_dev = -1; - if (strncmp(name, "xsane-", 6) == 0) - { - if (xsane_decode_devname(name + 6, sizeof(devname), devname) < 0) - { - return; /* name too long */ - } - args[nargs++] = devname; - } - - switch (run_mode) - { - case GIMP_RUN_INTERACTIVE: -#ifdef HAVE_GIMP_2 - gimp_extension_ack(); -#endif - xsane_interface(nargs, args); - values[0].data.d_status = GIMP_PDB_SUCCESS; - break; - - case GIMP_RUN_NONINTERACTIVE: - /* Make sure all the arguments are there! */ - break; - - case GIMP_RUN_WITH_LAST_VALS: - /* Possibly retrieve data */ - break; - - default: - break; - } -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void null_print_func(gchar *msg) -{ -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, int *cancel_save) -{ - int remaining; - size_t tile_size; - GimpImageType image_type = GIMP_GRAY; - GimpImageType drawable_type = GIMP_GRAY_IMAGE; - gint32 layer_ID; - gint32 image_ID; - GimpDrawable *drawable; - guchar *tile; - GimpPixelRgn region; - unsigned tile_offset; - int i, x, y; - Image_info image_info; - FILE *imagefile; - - DBG(DBG_info, "xsane_transer_to_gimp\n"); - - *cancel_save = 0; - - imagefile = fopen(input_filename, "rb"); /* read binary (b for win32) */ - if (imagefile == 0) - { - char buf[256]; - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, input_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - - return -1; - } - - xsane_read_pnm_header(imagefile, &image_info); - - x = 0; - y = 0; - tile_offset = 0; - tile_size = image_info.image_width * gimp_tile_height(); - - if (image_info.colors == 3) /* RGB */ - { - tile_size *= 3; /* 24 bits/pixel RGB */ - image_type = GIMP_RGB; - drawable_type = GIMP_RGB_IMAGE; - } - else if (image_info.colors == 4) /* RGBA */ - { - tile_size *= 4; /* 32 bits/pixel RGBA */ - image_type = GIMP_RGB; - drawable_type = GIMP_RGBA_IMAGE; /* interpret infrared as alpha */ - } - /* colors == 0/1 is predefined */ - - image_ID = gimp_image_new(image_info.image_width, image_info.image_height, image_type); - -/* the following is supported since gimp-1.1.? */ -#ifdef GIMP_HAVE_RESOLUTION_INFO - if (image_info.resolution_x > 0) - { - gimp_image_set_resolution(image_ID, image_info.resolution_x, image_info.resolution_y); - } -/* gimp_image_set_unit(image_ID, unit?); */ -#endif - - layer_ID = gimp_layer_new(image_ID, "Background", image_info.image_width, image_info.image_height, drawable_type, 100.0, GIMP_NORMAL_MODE); - gimp_image_add_layer(image_ID, layer_ID, 0); - drawable = gimp_drawable_get(layer_ID); - gimp_pixel_rgn_init(®ion, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); - tile = g_new(guchar, tile_size); - - - if (image_info.colors == 1) /* gray */ - { - switch (image_info.depth) - { - case 1: /* 1 bit gray => conversion to 8 bit gray */ - for (i = 0; i < ( (image_info.image_width + 7) / 8) * image_info.image_height; ++i) - { - u_char mask; - int j; - - mask = fgetc(imagefile); - for (j = 7; j >= 0; --j) - { - u_char gl = (mask & (1 << j)) ? 0x00 : 0xff; - tile[tile_offset++] = gl; - - x++; - - if (x >= image_info.image_width) - { - int tile_height = gimp_tile_height(); - - x = 0; - y++; - - if (y % tile_height == 0) - { - gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); - tile_offset = 0; - } - - gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - break; /* leave for j loop */ - } - } - - if (*cancel_save) - { - break; - } - } - break; /* leave switch depth 1 */ - - case 8: /* 8 bit gray */ - case 16: /* 16 bit gray already has been reduced to 8 bit */ - for (i = 0; i < image_info.image_width * image_info.image_height; ++i) - { - tile[tile_offset++] = fgetc(imagefile); - x++; - - if (x >= image_info.image_width) - { - int tile_height = gimp_tile_height(); - - x = 0; - y++; - - if (y % tile_height == 0) - { - gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); - tile_offset = 0; - } - - gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } - - if (*cancel_save) - { - break; - } - } - break; /* leave switch depth */ - - default: /* bad depth */ - break; /* default */ - } - } - else if (image_info.colors == 3) /* RGB */ - { - switch (image_info.depth) - { - case 8: /* 8 bit RGB */ - case 16: /* 16 bit RGB already has been reduced to 8 bit */ - for (i = 0; i < image_info.image_width * image_info.image_height*3; ++i) - { - tile[tile_offset++] = fgetc(imagefile); - if (tile_offset % 3 == 0) - { - x++; - - if (x >= image_info.image_width) - { - int tile_height = gimp_tile_height(); - - x = 0; - y++; - - if (y % tile_height == 0) - { - gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); - tile_offset = 0; - } - - gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } - } - - if (*cancel_save) - { - break; - } - } - break; /* case 8 */ - - default: /* bad depth */ - break; /* default */ - } - } -#ifdef SUPPORT_RGBA - else if (image_info.colors == 4) /* RGBA */ - { - int i; - - switch (image_info.depth) - { - case 8: /* 8 bit RGBA */ - case 16: /* 16 bit RGBA already has been reduced to 8 bit */ - for (i = 0; i < image_info.image_width * image_info.image_height * 4; ++i) - { - tile[tile_offset++] = fgetc(imagefile); - if (tile_offset % 4 == 0) - { - x++; - - if (x >= image_info.image_width) - { - int tile_height = gimp_tile_height(); - - x = 0; - y++; - - if (y % tile_height == 0) - { - gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); - tile_offset = 0; - } - - gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } - } - - if (*cancel_save) - { - break; - } - } - break; - - default: /* bad depth */ - break; - } - } -#endif - -/* scan_done part */ - if (y > image_info.image_height) - { - y = image_info.image_height; - } - - remaining = y % gimp_tile_height(); - - if (remaining) - { - gimp_pixel_rgn_set_rect(®ion, tile, 0, y - remaining, image_info.image_width, remaining); - } - - gimp_drawable_flush(drawable); - gimp_display_new(image_ID); - gimp_drawable_detach(drawable); - g_free(tile); - tile = 0; - - fclose(imagefile); - - return 0; -} -#endif /* HAVE_ANY_GIMP */ - -/* ---------------------------------------------------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef XSANE_ACTIVATE_MAIL - -/* character base of base64 coding */ -static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static void write_3chars_as_base64(unsigned char c1, unsigned char c2, unsigned char c3, int pads, int fd_socket) -{ - char buf[4]; - - buf[0] = base64[c1>>2]; /* wirte bits 7-2 of first char */ - buf[1] = base64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)]; /* write bits 1,0 of first and bits 7-4 of second char */ - - if (pads == 2) /* only one byte used */ - { - buf[2] = '='; /* char not used */ - buf[3] = '='; /* char not used */ - } - else if (pads) /* only two bytes used */ - { - buf[2] = base64[((c2 & 0xF) << 2)]; /* write bits 3-0 of second char */ - buf[3] = '='; /* char not used */ - } - else - { - buf[2] = base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)]; /* write bits 3-0 of second and bits 7,6 of third char */ - buf[3] = base64[c3 & 0x3F]; /* write bits 5-0 of third char as lsb */ - } - - write(fd_socket, buf, 4); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void write_base64(int fd_socket, FILE *infile) -{ - int c1, c2, c3; - int pos = 0; - - while ((c1 = getc(infile)) != EOF) - { - c2 = getc(infile); - if (c2 == EOF) - { - write_3chars_as_base64(c1, 0, 0, 2, fd_socket); - } - else - { - c3 = getc(infile); - if (c3 == EOF) - { - write_3chars_as_base64(c1, c2, 0, 1, fd_socket); - } - else - { - write_3chars_as_base64(c1, c2, c3, 0, fd_socket); - } - } - - pos += 4; - if (pos > 71) - { - write(fd_socket, "\n", 1); - - pos = 0; - } - - xsane.mail_progress_bytes += 3; - if ((int) ((xsane.mail_progress_bytes * 100) / xsane.mail_progress_size) != (int) (xsane.mail_progress_val * 100)) - { - xsane.mail_progress_val = (float) xsane.mail_progress_bytes / xsane.mail_progress_size; - xsane_front_gtk_mail_project_update_lockfile_status(); - } - } - - if (pos) - { - write(fd_socket, "\n", 1); - } - - xsane.mail_progress_val = 1.0; - xsane_front_gtk_mail_project_update_lockfile_status(); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void write_mail_header(int fd_socket, char *from, char *reply_to, char *to, char *subject, char *boundary, int related) -{ - char buf[1024]; - - snprintf(buf, sizeof(buf), "From: %s\n", from); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Reply-To: %s\n", reply_to); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "To: %s\n", to); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Subject: %s\n", subject); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "MIME-Version: 1.0\n"); - write(fd_socket, buf, strlen(buf)); - - if (related) /* related means that we need a special link in the html part to display the image */ - { - snprintf(buf, sizeof(buf), "Content-Type: multipart/related;\n"); - write(fd_socket, buf, strlen(buf)); - } - else - { - snprintf(buf, sizeof(buf), "Content-Type: multipart/mixed;\n"); - write(fd_socket, buf, strlen(buf)); - } - - snprintf(buf, sizeof(buf), " boundary=\"%s\"\n\n", boundary); - write(fd_socket, buf, strlen(buf)); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void write_mail_footer(int fd_socket, char *boundary) -{ - char buf[1024]; - - snprintf(buf, sizeof(buf), "--%s--\n", boundary); - write(fd_socket, buf, strlen(buf)); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void write_mail_mime_ascii(int fd_socket, char *boundary) -{ - char buf[1024]; - - snprintf(buf, sizeof(buf), "--%s\n", boundary); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Content-Type: text/plain;\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), " charset=\"iso-8859-1\"\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 8bit\n\n"); - write(fd_socket, buf, strlen(buf)); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void write_mail_mime_html(int fd_socket, char *boundary) -{ - char buf[1024]; - - snprintf(buf, sizeof(buf), "--%s\n", boundary); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Content-Type: text/html;\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), " charset=\"us-ascii\"\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 7bit\n\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "<html>\n"); - write(fd_socket, buf, strlen(buf)); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void write_mail_attach_image(int fd_socket, char *boundary, char *content_id, char *content_type, FILE *infile, char *filename) -{ - char buf[1024]; - - snprintf(buf, sizeof(buf), "--%s\n", boundary); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Content-Type: %s\n", content_type); - write(fd_socket, buf, strlen(buf)); - - if (content_id) - { - snprintf(buf, sizeof(buf), "Content-ID: <%s>\n", content_id); - write(fd_socket, buf, strlen(buf)); - } - - snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Content-Disposition: inline;\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), " filename=\"%s\"\n", filename); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "\n"); - write(fd_socket, buf, strlen(buf)); - - write_base64(fd_socket, infile); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void write_mail_attach_file(int fd_socket, char *boundary, FILE *infile, char *filename) -{ - char buf[1024]; - - snprintf(buf, sizeof(buf), "--%s\n", boundary); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Content-Type: application/octet-stream\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), " name=\"%s\"\n", filename); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Content-Disposition: attachment;\n"); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), " filename=\"%s\"\n", filename); - write(fd_socket, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "\n"); - write(fd_socket, buf, strlen(buf)); - - write_base64(fd_socket, infile); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* returns fd_socket if sucessfull, < 0 when error occured */ -int open_socket(char *server, int port) -{ - int fd_socket; - struct sockaddr_in sin; - struct hostent *he; - - he = gethostbyname(server); - if (!he) - { - DBG(DBG_error, "open_socket: Could not get hostname of \"%s\"\n", server); - return -1; - } - else - { - DBG(DBG_info, "open_socket: connecting to \"%s\" = %d.%d.%d.%d\n", - he->h_name, - (unsigned char) he->h_addr_list[0][0], - (unsigned char) he->h_addr_list[0][1], - (unsigned char) he->h_addr_list[0][2], - (unsigned char) he->h_addr_list[0][3]); - } - - if (he->h_addrtype != AF_INET) - { - DBG(DBG_error, "open_socket: Unknown address family: %d\n", he->h_addrtype); - return -1; - } - - fd_socket = socket(AF_INET, SOCK_STREAM, 0); - - if (fd_socket < 0) - { - DBG(DBG_error, "open_socket: Could not create socket: %s\n", strerror(errno)); - return -1; - } - -/* setsockopt (dev->ctl, level, TCP_NODELAY, &on, sizeof (on)); */ - - sin.sin_port = htons(port); - sin.sin_family = AF_INET; - memcpy(&sin.sin_addr, he->h_addr_list[0], he->h_length); - - if (connect(fd_socket, &sin, sizeof(sin))) - { - DBG(DBG_error, "open_socket: Could not connect with port %d of socket: %s\n", ntohs(sin.sin_port), strerror(errno)); - return -1; - } - - DBG(DBG_info, "open_socket: Connected with port %d\n", ntohs(sin.sin_port)); - - return fd_socket; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* returns 0 if success */ -/* not only a write routine, also reads data */ -int pop3_login(int fd_socket, char *user, char *passwd) -{ - char buf[1024]; - int len; - - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - - snprintf(buf, sizeof(buf), "USER %s\r\n", user); - DBG(DBG_info2, "> USER xxx\n"); - write(fd_socket, buf, strlen(buf)); - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - if (buf[0] != '+') - { - return -1; - } - - snprintf(buf, sizeof(buf), "PASS %s\r\n", passwd); - DBG(DBG_info2, "> PASS xxx\n"); - write(fd_socket, buf, strlen(buf)); - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - if (buf[0] != '+') - { - return -1; - } - - snprintf(buf, sizeof(buf), "QUIT\r\n"); - DBG(DBG_info2, "> QUIT\n"); - write(fd_socket, buf, strlen(buf)); - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - - return 0; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* not only a write routine, also reads data */ -/* returns -1 on error, 0 when ok */ -int write_smtp_header(int fd_socket, char *from, char *to) -{ - char buf[1024]; - int len; - - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - - snprintf(buf, sizeof(buf), "helo localhost\r\n"); - DBG(DBG_info2, "> %s", buf); - write(fd_socket, buf, strlen(buf)); - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - - if (buf[0] != '2') - { - DBG(DBG_info, "=> error\n"); - - if (xsane.mail_status) - { - free(xsane.mail_status); - } - xsane.mail_status = strdup(TEXT_MAIL_STATUS_SMTP_CONNECTION_FAILED); - xsane_front_gtk_mail_project_update_lockfile_status(); - return -1; - } - - snprintf(buf, sizeof(buf), "MAIL FROM: %s\r\n", from); - DBG(DBG_info2, "> %s", buf); - write(fd_socket, buf, strlen(buf)); - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - - if (buf[0] != '2') - { - DBG(DBG_info, "=> error\n"); - - if (xsane.mail_status) - { - free(xsane.mail_status); - } - xsane.mail_status = strdup(TEXT_MAIL_STATUS_SMTP_ERR_FROM); - xsane_front_gtk_mail_project_update_lockfile_status(); - return -1; - } - - - snprintf(buf, sizeof(buf), "RCPT TO: %s\r\n", to); - DBG(DBG_info2, "> %s", buf); - write(fd_socket, buf, strlen(buf)); - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - - if (buf[0] != '2') - { - DBG(DBG_info, "=> error\n"); - - if (xsane.mail_status) - { - free(xsane.mail_status); - } - xsane.mail_status = strdup(TEXT_MAIL_STATUS_SMTP_ERR_RCPT); - xsane_front_gtk_mail_project_update_lockfile_status(); - return -1; - } - - snprintf(buf, sizeof(buf), "DATA\r\n"); - DBG(DBG_info2, "> %s", buf); - write(fd_socket, buf, strlen(buf)); - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - - if ((buf[0] != '2') && (buf[0] != '3')) - { - DBG(DBG_info, "=> error\n"); - - if (xsane.mail_status) - { - free(xsane.mail_status); - } - xsane.mail_status = strdup(TEXT_MAIL_STATUS_SMTP_ERR_DATA); - xsane_front_gtk_mail_project_update_lockfile_status(); - return -1; - } - - return 0; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* not only a write routine, also reads data */ -int write_smtp_footer(int fd_socket) -{ - char buf[1024]; - int len; - - snprintf(buf, sizeof(buf), "\r\n.\r\n"); - DBG(DBG_info2, "> %s", buf); - write(fd_socket, buf, strlen(buf)); - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - - snprintf(buf, sizeof(buf), "QUIT\r\n"); - DBG(DBG_info2, "> %s", buf); - write(fd_socket, buf, strlen(buf)); - len = read(fd_socket, buf, sizeof(buf)); - if (len >= 0) - { - buf[len] = 0; - } - DBG(DBG_info2, "< %s\n", buf); - - return 0; -} - -#endif -/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/src/xsane-save.h b/src/xsane-save.h index 553fbd5..f94fe7c 100644 --- a/src/xsane-save.h +++ b/src/xsane-save.h @@ -3,7 +3,7 @@ xsane-save.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -40,7 +40,7 @@ #define PDF_PAGES_MAX 1000 struct pdf_xref { - unsigned long obj[PDF_PAGES_MAX * 2 + 6]; + unsigned long obj[PDF_PAGES_MAX * 2 + 8]; unsigned long xref; /* xref table */ unsigned long slen; /* length of image stream */ unsigned long slenp; /* position of image stream length */ @@ -60,50 +60,58 @@ extern void xsane_read_pnm_header(FILE *file, Image_info *image_info); extern void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_as_ascii); extern int xsane_copy_file(FILE *outfile, FILE *infile, GtkProgressBar *progress_bar, int *cancel_save); extern int xsane_copy_file_by_name(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save); +#ifdef HAVE_LIBLCMS +extern cmsHTRANSFORM xsane_create_cms_transform(Image_info *image_info, int cms_function, int cms_intent, int cms_bpc); +#endif extern int xsane_save_grayscale_image_as_lineart(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save); extern int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_info, float x_scale, float y_scale, GtkProgressBar *progress_bar, int *cancel_save); extern int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image_info, int radius, GtkProgressBar *progress_bar, int *cancel_save); extern int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info, float radius, GtkProgressBar *progress_bar, int *cancel_save); extern int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_info, int rotation, GtkProgressBar *progress_bar, int *cancel_save); -extern void xsane_save_ps_create_document_header(FILE *outfile, int pages, int flatdecode); +extern void xsane_save_ps_create_document_header(FILE *outfile, int pages, int flatedecode); extern void xsane_save_ps_create_document_trailer(FILE *outfile, int pages); extern int xsane_save_ps_page(FILE *outfile, int page, FILE *imagefile, Image_info *image_info, float width, float height, int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation, - int flatdecode, + int flatedecode, + cmsHTRANSFORM hTransform, int embed_scanner_icm_profile, GtkProgressBar *progress_bar, int *cancel_save); extern int xsane_save_ps(FILE *outfile, FILE *imagefile, Image_info *image_info, float width, float height, int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation, - int flatdecode, + int flatedecode, + cmsHTRANSFORM hTransform, int apply_ICM_profile, int embed_CSA, char *CSA_profile, + int embed_CRD, char *CRD_profile, int blackpointcompensation, int intent, GtkProgressBar *progress_bar, int *cancel_save); -extern void xsane_save_pdf_create_document_header(FILE *outfile, struct pdf_xref *xref, int pages, int flatdecode); +extern void xsane_save_pdf_create_document_header(FILE *outfile, struct pdf_xref *xref, int pages, int flatedecode); extern void xsane_save_pdf_create_document_trailer(FILE *outfile, struct pdf_xref *xref, int pages); extern int xsane_save_pdf_page(FILE *outfile, struct pdf_xref *xref, int page, FILE *imagefile, Image_info *image_info, float width, float height, int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation, - int flatdecode, + int flatedecode, + cmsHTRANSFORM hTransform, int embed__scanner_icm_profile, int icc_object, GtkProgressBar *progress_bar, int *cancel_save); extern int xsane_save_pdf(FILE *outfile, FILE *imagefile, Image_info *image_info, float width, float height, int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation, - int flatdecode, + int flatedecode, + cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, GtkProgressBar *progress_bar, int *cancel_save); #ifdef HAVE_LIBJPEG -extern int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int quality, GtkProgressBar *progress_bar, int *cancel_save); +extern int xsane_save_jpeg(FILE *outfile, int quality, FILE *imagefile, Image_info *image_info, cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, GtkProgressBar *progress_bar, int *cancel_save); #endif #ifdef HAVE_LIBTIFF -extern int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Image_info *image_info, int quality, - GtkProgressBar *progress_bar, int *cancel_save); +extern int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, int quality, FILE *imagefile, Image_info *image_info, cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, + GtkProgressBar *progress_bar, int *cancel_save); #endif -extern int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int compression, GtkProgressBar *progress_bar, int *cancel_save); -extern int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, int compression, GtkProgressBar *progress_bar, int *cancel_save); -extern int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save); +extern int xsane_save_png(FILE *outfile, int compression, FILE *imagefile, Image_info *image_info, cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, GtkProgressBar *progress_bar, int *cancel_save); +extern int xsane_save_png_16(FILE *outfile, int compression, FILE *imagefile, Image_info *image_info, cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function, GtkProgressBar *progress_bar, int *cancel_save); +extern int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, cmsHTRANSFORM hTransform, int apply_ICM_profile, GtkProgressBar *progress_bar, int *cancel_save); extern int xsane_save_image_as_lineart(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save); extern int xsane_save_image_as_text(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save); -extern int xsane_save_image_as(char *output_filename, char *input_filename, int output_format, GtkProgressBar *progress_bar, int *cancel_save); +extern int xsane_save_image_as(char *output_filename, char *input_filename, int output_format, int apply_ICM_profile, int cms_function, int cms_intent, int cms_bpc, GtkProgressBar *progress_bar, int *cancel_save); extern void null_print_func(gchar *msg); -extern int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, int *cancel_save); +extern int xsane_transfer_to_gimp(char *input_filename, int apply_ICM_profile, int cms_function, GtkProgressBar *progress_bar, int *cancel_save); extern void write_base64(int fd_socket, FILE *infile); extern void write_email_header(int fd_socket, char *from, char *reply_to, char *to, char *subject, char *boundary, int related); extern void write_email_footer(int fd_socket, char *boundary); diff --git a/src/xsane-scan.c b/src/xsane-scan.c index 578cc57..9cc9ffb 100644 --- a/src/xsane-scan.c +++ b/src/xsane-scan.c @@ -3,7 +3,7 @@ xsane-scan.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -1061,7 +1061,7 @@ void xsane_scan_done(SANE_Status status) image_info.image_width = xsane.param.pixels_per_line; image_info.image_height = pixel_height; image_info.depth = xsane.depth; - image_info.colors = xsane.xsane_colors; + image_info.channels = xsane.xsane_channels; image_info.resolution_x = xsane.resolution_x; image_info.resolution_y = xsane.resolution_y; @@ -1085,6 +1085,13 @@ void xsane_scan_done(SANE_Status status) image_info.reduce_to_lineart = xsane.expand_lineart_to_grayscale; + image_info.enable_color_management = xsane.enable_color_management; + image_info.cms_function = preferences.cms_function; + image_info.cms_intent = preferences.cms_intent; + image_info.cms_bpc = preferences.cms_bpc; + + strncpy(image_info.icm_profile, xsane.scanner_default_color_icm_profile, sizeof(image_info.icm_profile)); + xsane_write_pnm_header(xsane.out, &image_info, 0); } @@ -1233,12 +1240,12 @@ void xsane_scan_done(SANE_Status status) #ifdef HAVE_ANY_GIMP if (xsane.mode == XSANE_GIMP_EXTENSION) /* xsane runs as gimp plugin */ { - xsane_transfer_to_gimp(xsane.dummy_filename, xsane.progress_bar, &xsane.cancel_save); + xsane_transfer_to_gimp(xsane.dummy_filename, xsane.enable_color_management, preferences.cms_function, xsane.progress_bar, &xsane.cancel_save); } else #endif /* HAVE_ANY_GIMP */ { - xsane_save_image_as(xsane.output_filename, xsane.dummy_filename, xsane.xsane_output_format, xsane.progress_bar, &xsane.cancel_save); + xsane_save_image_as(xsane.output_filename, xsane.dummy_filename, xsane.xsane_output_format, xsane.enable_color_management, preferences.cms_function, preferences.cms_intent, preferences.cms_bpc, xsane.progress_bar, &xsane.cancel_save); } xsane_progress_clear(); @@ -1345,7 +1352,11 @@ void xsane_scan_done(SANE_Status status) preferences.printer[preferences.printernr]->width * 72.0/MM_PER_INCH, /* usable paperwidth */ preferences.printer[preferences.printernr]->height * 72.0/MM_PER_INCH, /* usable paperheight */ preferences.paper_orientation, - preferences.printer[preferences.printernr]->ps_flatdecoded, /* ps level 3 */ + preferences.printer[preferences.printernr]->ps_flatedecoded, /* ps level 3 */ + NULL /* hTransform */, xsane.enable_color_management, + preferences.printer[preferences.printernr]->embed_csa, xsane.scanner_default_color_icm_profile, + preferences.printer[preferences.printernr]->embed_crd, preferences.printer[preferences.printernr]->icm_profile, preferences.printer[preferences.printernr]->blackpointcompensation, + 0 /* intent */, xsane.progress_bar, &xsane.cancel_save); } @@ -1729,7 +1740,7 @@ static void xsane_start_scan(void) image_info.image_width = xsane.param.pixels_per_line; image_info.image_height = xsane.param.lines; image_info.depth = xsane.depth; - image_info.colors = xsane.xsane_colors; + image_info.channels = xsane.xsane_channels; image_info.resolution_x = xsane.resolution_x; image_info.resolution_y = xsane.resolution_y; @@ -1753,6 +1764,13 @@ static void xsane_start_scan(void) image_info.reduce_to_lineart = xsane.expand_lineart_to_grayscale; + image_info.enable_color_management = xsane.enable_color_management; + image_info.cms_function = preferences.cms_function; + image_info.cms_intent = preferences.cms_intent; + image_info.cms_bpc = preferences.cms_bpc; + + strncpy(image_info.icm_profile, xsane.scanner_default_color_icm_profile, sizeof(image_info.icm_profile)); + xsane_write_pnm_header(xsane.out, &image_info, 0); fflush(xsane.out); @@ -1946,34 +1964,6 @@ gint xsane_scan_dialog(gpointer *data) free(extension); } } -#ifdef HAVE_ANY_GIMP - else /* We are running in gimp mode */ - { - if ((xsane.param.depth != 1) && (xsane.param.depth != 8)) /* not support bit depth ? */ - { - if (!xsane.reduce_16bit_to_8bit) /* ask if reduce 16 to 8 bit */ - { - if (xsane.param.depth == 16) - { - snprintf(buf, sizeof(buf), TEXT_GIMP_REDUCE_16BIT_TO_8BIT); - if (xsane_back_gtk_decision(ERR_HEADER_INFO, (gchar **) info_xpm, buf, BUTTON_REDUCE, BUTTON_CANCEL, TRUE /* wait */) == FALSE) - { - xsane_set_sensitivity(TRUE); - return FALSE; - } - xsane.reduce_16bit_to_8bit = TRUE; - } - else /* unsupported bit depth */ - { - snprintf(buf, sizeof(buf), ERR_GIMP_BAD_DEPTH, xsane.param.depth); - xsane_back_gtk_error(buf, TRUE); - xsane_set_sensitivity(TRUE); - return FALSE; - } - } - } - } -#endif if (xsane.dummy_filename) /* no dummy filename defined - necessary if an error occurs */ { @@ -1982,7 +1972,7 @@ gint xsane_scan_dialog(gpointer *data) } /* create scanner gamma tables, xsane internal gamma tables are created after sane_start */ - if ( (xsane.xsane_colors > 1) && /* color scan */ + if ( (xsane.xsane_channels > 1) && /* color scan */ xsane.scanner_gamma_color ) /* gamma table for red, green and blue available */ { double gamma_red, gamma_green, gamma_blue; @@ -2097,7 +2087,7 @@ gint xsane_scan_dialog(gpointer *data) xsane.gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int)); - if (xsane.xsane_colors > 1) /* color scan */ + if (xsane.xsane_channels > 1) /* color scan */ { xsane_create_gamma_curve(xsane.gamma_data, xsane.negative, gamma, xsane.brightness, xsane.contrast, @@ -2145,7 +2135,7 @@ static void xsane_create_internal_gamma_tables(void) size = (int) pow(2, xsane.param.depth); maxval = size-1; - if (xsane.xsane_colors > 1) /* color scan */ + if (xsane.xsane_channels > 1) /* color scan */ { if ( (!xsane.scanner_gamma_color) && (xsane.scanner_gamma_gray) ) { diff --git a/src/xsane-scan.h b/src/xsane-scan.h index b46d5e0..681e89f 100644 --- a/src/xsane-scan.h +++ b/src/xsane-scan.h @@ -3,7 +3,7 @@ xsane-scan.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-setup.c b/src/xsane-setup.c index c0c9000..677c375 100644 --- a/src/xsane-setup.c +++ b/src/xsane-setup.c @@ -3,7 +3,7 @@ xsane-setup.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -92,6 +92,9 @@ static void xsane_setup_authentication_type_callback(GtkWidget *widget, gpointer static void xsane_setup_show_range_mode_callback(GtkWidget *widget, gpointer data); static void xsane_setup_lineart_mode_callback(GtkWidget *widget, gpointer data); static void xsane_enhance_notebook(GtkWidget *notebook); +#ifdef HAVE_LIBLCMS +static void xsane_color_management_notebook(GtkWidget *notebook); +#endif void xsane_setup_dialog(GtkWidget *widget, gpointer data); @@ -135,7 +138,10 @@ void xsane_new_printer(void) preferences.printer[preferences.printernr]->gamma_red = 1.0; preferences.printer[preferences.printernr]->gamma_green = 1.0; preferences.printer[preferences.printernr]->gamma_blue = 1.0; - preferences.printer[preferences.printernr]->ps_flatdecoded = 1; + preferences.printer[preferences.printernr]->icm_profile = NULL; + preferences.printer[preferences.printernr]->embed_csa = 1; + preferences.printer[preferences.printernr]->embed_crd = 0; + preferences.printer[preferences.printernr]->ps_flatedecoded = 1; } else { @@ -275,8 +281,23 @@ static void xsane_setup_printer_update() gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_gamma_green_entry), buf); snprintf(buf, sizeof(buf), "%1.2f", preferences.printer[preferences.printernr]->gamma_blue); gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_gamma_blue_entry), buf); + +#ifdef HAVE_LIBLCMS + if (preferences.printer[preferences.printernr]->icm_profile) + { + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_icm_profile_entry), (char *) preferences.printer[preferences.printernr]->icm_profile); + } + else + { + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_icm_profile_entry), ""); + } + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xsane_setup.printer_embed_csa_button), preferences.printer[preferences.printernr]->embed_csa); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xsane_setup.printer_embed_crd_button), preferences.printer[preferences.printernr]->embed_crd); +#endif + #ifdef HAVE_LIBZ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xsane_setup.printer_ps_flatdecoded_button), preferences.printer[preferences.printernr]->ps_flatdecoded); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xsane_setup.printer_ps_flatedecoded_button), preferences.printer[preferences.printernr]->ps_flatedecoded); #endif } @@ -354,8 +375,18 @@ static void xsane_setup_printer_apply_changes(GtkWidget *widget, gpointer data) xsane_update_double(xsane_setup.printer_gamma_green_entry, &preferences.printer[preferences.printernr]->gamma_green); xsane_update_double(xsane_setup.printer_gamma_blue_entry, &preferences.printer[preferences.printernr]->gamma_blue); +#ifdef HAVE_LIBLCMS + if (preferences.printer[preferences.printernr]->icm_profile) + { + free(preferences.printer[preferences.printernr]->icm_profile); + } + preferences.printer[preferences.printernr]->icm_profile = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.printer_icm_profile_entry))); + xsane_update_bool(xsane_setup.printer_embed_csa_button, &preferences.printer[preferences.printernr]->embed_csa); + xsane_update_bool(xsane_setup.printer_embed_crd_button, &preferences.printer[preferences.printernr]->embed_crd); +#endif + #ifdef HAVE_LIBZ - xsane_update_bool(xsane_setup.printer_ps_flatdecoded_button, &preferences.printer[preferences.printernr]->ps_flatdecoded); + xsane_update_bool(xsane_setup.printer_ps_flatedecoded_button, &preferences.printer[preferences.printernr]->ps_flatedecoded); #endif if (option_menu) @@ -530,6 +561,50 @@ static void xsane_setup_enhance_apply_changes(GtkWidget *widget, gpointer data) /* ---------------------------------------------------------------------------------------------------------------------- */ +#ifdef HAVE_LIBLCMS +static void xsane_setup_color_management_apply_changes(GtkWidget *widget, gpointer data) +{ + DBG(DBG_proc, "xsane_setup_colormagaement_apply_changes\n"); + +// preferences.cms_intent = gtk_option_menu_get_history(GTK_OPTION_MENU(xsane_setup.cms_intent_option_menu)); +// preferences.cms_intent = gtk_option_menu_get_history(GTK_OPTION_MENU(xsane_setup.cms_intent_option_menu)); + preferences.cms_intent = (int) gtk_object_get_data(GTK_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(xsane_setup.cms_intent_option_menu))))), "Selection"); + xsane_update_bool(xsane_setup.cms_bpc_button, &preferences.cms_bpc); + + if (xsane.scanner_default_color_icm_profile) + { + free(xsane.scanner_default_color_icm_profile); + } + xsane.scanner_default_color_icm_profile = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.scanner_default_color_icm_profile_entry))); + + if (xsane.scanner_default_gray_icm_profile) + { + free(xsane.scanner_default_gray_icm_profile); + } + xsane.scanner_default_gray_icm_profile = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.scanner_default_gray_icm_profile_entry))); + + if (preferences.display_icm_profile) + { + free(preferences.display_icm_profile); + } + preferences.display_icm_profile = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.display_icm_profile_entry))); + + if (preferences.custom_proofing_icm_profile) + { + free(preferences.custom_proofing_icm_profile); + } + preferences.custom_proofing_icm_profile = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.custom_proofing_icm_profile_entry))); + + if (preferences.working_color_space_icm_profile) + { + free(preferences.working_color_space_icm_profile); + } + preferences.working_color_space_icm_profile = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.working_color_space_icm_profile_entry))); +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + static void xsane_setup_saving_apply_changes(GtkWidget *widget, gpointer data) { int level; @@ -597,8 +672,8 @@ static void xsane_setup_image_apply_changes(GtkWidget *widget, gpointer data) xsane_update_bool(xsane_setup.save_pnm16_as_ascii_button, &preferences.save_pnm16_as_ascii); #ifdef HAVE_LIBZ - xsane_update_bool(xsane_setup.save_ps_flatdecoded_button, &preferences.save_ps_flatdecoded); - xsane_update_bool(xsane_setup.save_pdf_flatdecoded_button, &preferences.save_pdf_flatdecoded); + xsane_update_bool(xsane_setup.save_ps_flatedecoded_button, &preferences.save_ps_flatedecoded); + xsane_update_bool(xsane_setup.save_pdf_flatedecoded_button, &preferences.save_pdf_flatedecoded); #endif xsane_define_maximum_output_size(); @@ -627,7 +702,7 @@ static void xsane_setup_fax_apply_changes(GtkWidget *widget, gpointer data) xsane_update_geometry_double(xsane_setup.fax_height_entry, &preferences.fax_height, preferences.length_unit); #ifdef HAVE_LIBZ - xsane_update_bool(xsane_setup.fax_ps_flatdecoded_button, &preferences.fax_ps_flatdecoded); + xsane_update_bool(xsane_setup.fax_ps_flatedecoded_button, &preferences.fax_ps_flatedecoded); #endif xsane_define_maximum_output_size(); @@ -719,6 +794,9 @@ static void xsane_setup_options_ok_callback(GtkWidget *widget, gpointer data) xsane_setup_email_apply_changes(0, 0); #endif xsane_setup_ocr_apply_changes(0, 0); +#ifdef HAVE_LIBLCMS + xsane_setup_color_management_apply_changes(0, 0); +#endif if (xsane_setup.grayscale_scanmode) { @@ -851,7 +929,7 @@ static void xsane_permission_box(GtkWidget *parent, gchar *name, gchar *descript button = gtk_toggle_button_new_with_label("x"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 64 ); - xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PERMISSION_EXECUTE); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PERMISSION_SEARCH); gtk_widget_set_size_request(button, 21, -1); gtk_widget_set_name(button, name); g_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 64); @@ -887,7 +965,7 @@ static void xsane_permission_box(GtkWidget *parent, gchar *name, gchar *descript button = gtk_toggle_button_new_with_label("x"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 8 ); - xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PERMISSION_EXECUTE); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PERMISSION_SEARCH); gtk_widget_set_size_request(button, 21, -1); gtk_widget_set_name(button, name); g_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 8); @@ -923,7 +1001,7 @@ static void xsane_permission_box(GtkWidget *parent, gchar *name, gchar *descript button = gtk_toggle_button_new_with_label("x"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 1 ); - xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PERMISSION_EXECUTE); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PERMISSION_SEARCH); gtk_widget_set_size_request(button, 21, -1); gtk_widget_set_name(button, name); g_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 1); @@ -948,6 +1026,47 @@ static void xsane_permission_box(GtkWidget *parent, gchar *name, gchar *descript /* ---------------------------------------------------------------------------------------------------------------------- */ +#ifdef HAVE_LIBLCMSx +static void xsane_setup_display_icm_profile_info_callback(GtkWidget *widget, gpointer data) +{ + DBG(DBG_proc, "xsane_setup_display_icm_profile_info_callback\n"); + + const char* cmsTakeProductName(cmsHPROFILE hProfile); + const char* cmsTakeProductDesc(cmsHPROFILE hProfile); + + int cmsTakeRenderingIntent(cmsHPROFILE hProfile); + + #define LCMS_USED_AS_INPUT 0 + #define LCMS_USED_AS_OUTPUT 1 + #define LCMS_USED_AS_PROOF 2 + BOOL cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection); + +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBLCMS +static void xsane_setup_browse_printer_icm_profile_callback(GtkWidget *widget, gpointer data) +{ + const gchar *old_printer_icm_profile; + char printer_icm_profile[PATH_MAX]; + char windowname[TEXTBUFSIZE]; + + DBG(DBG_proc, "xsane_setup_browse_printer_icm_profile_callback\n"); + + old_printer_icm_profile = gtk_entry_get_text(GTK_ENTRY(xsane_setup.printer_icm_profile_entry)); + strncpy(printer_icm_profile, old_printer_icm_profile, sizeof(printer_icm_profile)); + + snprintf(windowname, sizeof(windowname), "%s %s", xsane.prog_name, WINDOW_PRINTER_ICM_PROFILE); + xsane_back_gtk_get_filename(windowname, printer_icm_profile, sizeof(printer_icm_profile), printer_icm_profile, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_OPEN, XSANE_GET_FILENAME_SHOW_NOTHING, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_ICM, XSANE_FILE_FILTER_ICM); + + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_icm_profile_entry), printer_icm_profile); +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + static void xsane_printer_notebook(GtkWidget *notebook) { GtkWidget *setup_vbox, *vbox, *hbox, *button, *label, *text, *frame; @@ -1273,23 +1392,82 @@ static void xsane_printer_notebook(GtkWidget *notebook) gtk_widget_show(hbox); xsane_setup.printer_gamma_blue_entry = text; +#ifdef HAVE_LIBLCMS + xsane_separator_new(vbox, 2); + + /* printer ICM profile: */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_PRINTER_ICM_PROFILE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new_with_max_length(PATH_MAX); + gtk_widget_set_size_request(text, 70, -1); /* set minimum size */ + xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_PRINTER_ICM_PROFILE); + + if (preferences.printer[preferences.printernr]->icm_profile) + { + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.printer[preferences.printernr]->icm_profile); + } + else + { + gtk_entry_set_text(GTK_ENTRY(text), ""); + } + + gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 4); + gtk_widget_show(text); + xsane_setup.printer_icm_profile_entry = text; + + button = gtk_button_new_with_label(BUTTON_BROWSE); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_browse_printer_icm_profile_callback, NULL); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 2); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_BUTTON_PRINTER_ICM_PROFILE_BROWSE); + gtk_widget_show(button); + + gtk_widget_show(hbox); + + + /* embed csa */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + button = gtk_check_button_new_with_label(TEXT_SETUP_PRINTER_EMBED_CSA); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PRINTER_EMBED_CSA); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.printer[preferences.printernr]->embed_csa); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); + gtk_widget_show(button); + gtk_widget_show(hbox); + xsane_setup.printer_embed_csa_button = button; + + /* embed crd */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + button = gtk_check_button_new_with_label(TEXT_SETUP_PRINTER_EMBED_CRD); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PRINTER_EMBED_CRD); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.printer[preferences.printernr]->embed_crd); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); + gtk_widget_show(button); + gtk_widget_show(hbox); + xsane_setup.printer_embed_crd_button = button; +#endif #ifdef HAVE_LIBZ xsane_separator_new(vbox, 2); - /* flatdecoded = ps level 3 */ + /* flatedecoded = ps level 3 */ hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); - button = gtk_check_button_new_with_label(TEXT_SETUP_PRINTER_PS_FLATDECODED); - xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PRINTER_PS_FLATDECODED); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.printer[preferences.printernr]->ps_flatdecoded); + button = gtk_check_button_new_with_label(TEXT_SETUP_PRINTER_PS_FLATEDECODED); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_PRINTER_PS_FLATEDECODED); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.printer[preferences.printernr]->ps_flatedecoded); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); gtk_widget_show(button); gtk_widget_show(hbox); - xsane_setup.printer_ps_flatdecoded_button = button; + xsane_setup.printer_ps_flatedecoded_button = button; #endif @@ -1336,13 +1514,110 @@ static void xsane_setup_browse_tmp_path_callback(GtkWidget *widget, gpointer dat strncpy(tmp_path, old_tmp_path, sizeof(tmp_path)); snprintf(windowname, sizeof(windowname), "%s %s", xsane.prog_name, WINDOW_TMP_PATH); - xsane_back_gtk_get_filename(windowname, tmp_path, sizeof(tmp_path), tmp_path, NULL, TRUE, FALSE, TRUE, FALSE); + xsane_back_gtk_get_filename(windowname, tmp_path, sizeof(tmp_path), tmp_path, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_FOLDER, XSANE_GET_FILENAME_SHOW_NOTHING, 0, 0); gtk_entry_set_text(GTK_ENTRY(xsane_setup.tmp_path_entry), tmp_path); } /* ---------------------------------------------------------------------------------------------------------------------- */ +#ifdef HAVE_LIBLCMS +static void xsane_setup_browse_scanner_default_color_icm_profile_callback(GtkWidget *widget, gpointer data) +{ + const gchar *old_scanner_default_color_icm_profile; + char scanner_default_color_icm_profile[PATH_MAX]; + char windowname[TEXTBUFSIZE]; + + DBG(DBG_proc, "xsane_setup_browse_scanner_default_color_icm_profile_callback\n"); + + old_scanner_default_color_icm_profile = gtk_entry_get_text(GTK_ENTRY(xsane_setup.scanner_default_color_icm_profile_entry)); + strncpy(scanner_default_color_icm_profile, old_scanner_default_color_icm_profile, sizeof(scanner_default_color_icm_profile)); + + snprintf(windowname, sizeof(windowname), "%s %s", xsane.prog_name, WINDOW_SCANNER_DEFAULT_COLOR_ICM_PROFILE); + xsane_back_gtk_get_filename(windowname, scanner_default_color_icm_profile, sizeof(scanner_default_color_icm_profile), scanner_default_color_icm_profile, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_OPEN, XSANE_GET_FILENAME_SHOW_NOTHING, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_ICM, XSANE_FILE_FILTER_ICM); + + gtk_entry_set_text(GTK_ENTRY(xsane_setup.scanner_default_color_icm_profile_entry), scanner_default_color_icm_profile); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_browse_scanner_default_gray_icm_profile_callback(GtkWidget *widget, gpointer data) +{ + const gchar *old_scanner_default_gray_icm_profile; + char scanner_default_gray_icm_profile[PATH_MAX]; + char windowname[TEXTBUFSIZE]; + + DBG(DBG_proc, "xsane_setup_browse_scanner_default_gray_icm_profile_callback\n"); + + old_scanner_default_gray_icm_profile = gtk_entry_get_text(GTK_ENTRY(xsane_setup.scanner_default_gray_icm_profile_entry)); + strncpy(scanner_default_gray_icm_profile, old_scanner_default_gray_icm_profile, sizeof(scanner_default_gray_icm_profile)); + + snprintf(windowname, sizeof(windowname), "%s %s", xsane.prog_name, WINDOW_SCANNER_DEFAULT_GRAY_ICM_PROFILE); + xsane_back_gtk_get_filename(windowname, scanner_default_gray_icm_profile, sizeof(scanner_default_gray_icm_profile), scanner_default_gray_icm_profile, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_OPEN, XSANE_GET_FILENAME_SHOW_NOTHING, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_ICM, XSANE_FILE_FILTER_ICM); + + gtk_entry_set_text(GTK_ENTRY(xsane_setup.scanner_default_gray_icm_profile_entry), scanner_default_gray_icm_profile); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_browse_display_icm_profile_callback(GtkWidget *widget, gpointer data) +{ + const gchar *old_display_icm_profile; + char display_icm_profile[PATH_MAX]; + char windowname[TEXTBUFSIZE]; + + DBG(DBG_proc, "xsane_setup_browse_display_icm_profile_callback\n"); + + old_display_icm_profile = gtk_entry_get_text(GTK_ENTRY(xsane_setup.display_icm_profile_entry)); + strncpy(display_icm_profile, old_display_icm_profile, sizeof(display_icm_profile)); + + snprintf(windowname, sizeof(windowname), "%s %s", xsane.prog_name, WINDOW_DISPLAY_ICM_PROFILE); + xsane_back_gtk_get_filename(windowname, display_icm_profile, sizeof(display_icm_profile), display_icm_profile, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_OPEN, XSANE_GET_FILENAME_SHOW_NOTHING, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_ICM, XSANE_FILE_FILTER_ICM); + + gtk_entry_set_text(GTK_ENTRY(xsane_setup.display_icm_profile_entry), display_icm_profile); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_browse_custom_proofing_icm_profile_callback(GtkWidget *widget, gpointer data) +{ + const gchar *old_custom_proofing_icm_profile; + char custom_proofing_icm_profile[PATH_MAX]; + char windowname[TEXTBUFSIZE]; + + DBG(DBG_proc, "xsane_setup_browse_custom_proofing_icm_profile_callback\n"); + + old_custom_proofing_icm_profile = gtk_entry_get_text(GTK_ENTRY(xsane_setup.custom_proofing_icm_profile_entry)); + strncpy(custom_proofing_icm_profile, old_custom_proofing_icm_profile, sizeof(custom_proofing_icm_profile)); + + snprintf(windowname, sizeof(windowname), "%s %s", xsane.prog_name, WINDOW_CUSTOM_PROOFING_ICM_PROFILE); + xsane_back_gtk_get_filename(windowname, custom_proofing_icm_profile, sizeof(custom_proofing_icm_profile), custom_proofing_icm_profile, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_OPEN, XSANE_GET_FILENAME_SHOW_NOTHING, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_ICM, XSANE_FILE_FILTER_ICM); + + gtk_entry_set_text(GTK_ENTRY(xsane_setup.custom_proofing_icm_profile_entry), custom_proofing_icm_profile); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_browse_working_color_space_icm_profile_callback(GtkWidget *widget, gpointer data) +{ + const gchar *old_working_color_space_icm_profile; + char working_color_space_icm_profile[PATH_MAX]; + char windowname[TEXTBUFSIZE]; + + DBG(DBG_proc, "xsane_setup_browse_working_color_space_icm_profile_callback\n"); + + old_working_color_space_icm_profile = gtk_entry_get_text(GTK_ENTRY(xsane_setup.working_color_space_icm_profile_entry)); + strncpy(working_color_space_icm_profile, old_working_color_space_icm_profile, sizeof(working_color_space_icm_profile)); + + snprintf(windowname, sizeof(windowname), "%s %s", xsane.prog_name, WINDOW_WORKING_COLOR_SPACE_ICM_PROFILE); + xsane_back_gtk_get_filename(windowname, working_color_space_icm_profile, sizeof(working_color_space_icm_profile), working_color_space_icm_profile, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SELECT_OPEN, XSANE_GET_FILENAME_SHOW_NOTHING, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_ICM, XSANE_FILE_FILTER_ICM); + + gtk_entry_set_text(GTK_ENTRY(xsane_setup.working_color_space_icm_profile_entry), working_color_space_icm_profile); +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + static void xsane_saving_notebook(GtkWidget *notebook) { GtkWidget *setup_vbox, *vbox, *hbox, *button, *label, *text, *frame; @@ -1379,7 +1654,7 @@ static void xsane_saving_notebook(GtkWidget *notebook) gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); gtk_widget_show(label); - text = gtk_entry_new_with_max_length(255); + text = gtk_entry_new_with_max_length(PATH_MAX); gtk_widget_set_size_request(text, 70, -1); /* set minimum size */ xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_TMP_PATH); gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.tmp_path); @@ -1615,28 +1890,28 @@ static void xsane_filetype_notebook(GtkWidget *notebook) #ifdef HAVE_LIBZ - /* save ps with zlib compression / flatdecode = ps level 3 */ + /* save ps with zlib compression / flatedecode = ps level 3 */ hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); - button = gtk_check_button_new_with_label(RADIO_BUTTON_SAVE_PS_FLATDECODED); - xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_SAVE_PS_FLATDECODED); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.save_ps_flatdecoded); + button = gtk_check_button_new_with_label(RADIO_BUTTON_SAVE_PS_FLATEDECODED); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_SAVE_PS_FLATEDECODED); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.save_ps_flatedecoded); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); gtk_widget_show(button); gtk_widget_show(hbox); - xsane_setup.save_ps_flatdecoded_button = button; + xsane_setup.save_ps_flatedecoded_button = button; - /* save pdf with zlib compression / flatdecode */ + /* save pdf with zlib compression / flatedecode */ hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); - button = gtk_check_button_new_with_label(RADIO_BUTTON_SAVE_PDF_FLATDECODED); - xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_SAVE_PDF_FLATDECODED); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.save_pdf_flatdecoded); + button = gtk_check_button_new_with_label(RADIO_BUTTON_SAVE_PDF_FLATEDECODED); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_SAVE_PDF_FLATEDECODED); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.save_pdf_flatedecoded); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); gtk_widget_show(button); gtk_widget_show(hbox); - xsane_setup.save_pdf_flatdecoded_button = button; + xsane_setup.save_pdf_flatedecoded_button = button; #endif @@ -1656,24 +1931,24 @@ static void xsane_filetype_notebook(GtkWidget *notebook) #ifdef HAVE_LIBJPEG xsane_range_new(GTK_BOX(vbox), TEXT_SETUP_JPEG_QUALITY, DESC_JPEG_QUALITY, 0.0, 100.0, 1.0, 10.0, 0, - &preferences.jpeg_quality, (GtkObject **) &xsane_setup.jpeg_image_quality_scale, 0, TRUE); + &preferences.jpeg_quality, &xsane_setup.jpeg_image_quality_scale, 0, TRUE); #else #ifdef HAVE_LIBTIFF xsane_range_new(GTK_BOX(vbox), TEXT_SETUP_JPEG_QUALITY, DESC_JPEG_QUALITY, 0.0, 100.0, 1.0, 10.0, 0, - &preferences.jpeg_quality, (GtkObject **) &xsane_setup.jpeg_image_quality_scale, 0, TRUE); + &preferences.jpeg_quality, &xsane_setup.jpeg_image_quality_scale, 0, TRUE); #endif #endif #ifdef HAVE_LIBPNG #ifdef HAVE_LIBZ xsane_range_new(GTK_BOX(vbox), TEXT_SETUP_PNG_COMPRESSION, DESC_PNG_COMPRESSION, 0.0, Z_BEST_COMPRESSION, 1.0, 10.0, 0, - &preferences.png_compression, (GtkObject **) &xsane_setup.png_image_compression_scale, 0, TRUE); + &preferences.png_compression, &xsane_setup.png_image_compression_scale, 0, TRUE); #endif #endif #ifdef HAVE_LIBTIFF xsane_range_new(GTK_BOX(vbox), TEXT_SETUP_TIFF_ZIP_COMPRESSION, DESC_TIFF_ZIP_COMPRESSION, 1.0, 9.0, 1.0, 6.0, 0, - &preferences.tiff_zip_compression, (GtkObject **) &xsane_setup.tiff_image_zip_compression_scale, 0, TRUE); + &preferences.tiff_zip_compression, &xsane_setup.tiff_image_zip_compression_scale, 0, TRUE); /* TIFF 16 BIT IMAGES COMPRESSION */ @@ -2083,16 +2358,16 @@ static void xsane_fax_notebook(GtkWidget *notebook) xsane_separator_new(vbox, 4); - /* flatdecoded = ps level 3 */ + /* flatedecoded = ps level 3 */ hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); - button = gtk_check_button_new_with_label(TEXT_SETUP_FAX_PS_FLATDECODED); - xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_FAX_PS_FLATDECODED); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.fax_ps_flatdecoded); + button = gtk_check_button_new_with_label(TEXT_SETUP_FAX_PS_FLATEDECODED); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_FAX_PS_FLATEDECODED); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.fax_ps_flatedecoded); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); gtk_widget_show(button); gtk_widget_show(hbox); - xsane_setup.fax_ps_flatdecoded_button = button; + xsane_setup.fax_ps_flatedecoded_button = button; #endif @@ -3224,6 +3499,355 @@ static void xsane_enhance_notebook(GtkWidget *notebook) /* ---------------------------------------------------------------------------------------------------------------------- */ +#ifdef HAVE_LIBLCMS +static void xsane_color_management_notebook(GtkWidget *notebook) +{ + GtkWidget *setup_vbox, *vbox, *hbox, *button, *label, *text, *frame, *option_menu, *menu, *menu_item; + int selection = 0; + + DBG(DBG_proc, "xsane_color_management_notebook\n"); + + /* color management options notebook page */ + + setup_vbox = gtk_vbox_new(FALSE, 5); + + label = gtk_label_new(NOTEBOOK_COLOR_MANAGEMENT_OPTIONS); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), setup_vbox, label); + gtk_widget_show(setup_vbox); + + frame = gtk_frame_new(0); + gtk_container_set_border_width(GTK_CONTAINER(frame), 7); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start(GTK_BOX(setup_vbox), frame, TRUE, TRUE, 0); /* sizeable framehight */ + gtk_widget_show(frame); + + vbox = gtk_vbox_new(FALSE, 1); + gtk_container_add(GTK_CONTAINER(frame), vbox); + gtk_widget_show(vbox); + + + + /* black point compensation */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + button = gtk_check_button_new_with_label(RADIO_BUTTON_CMS_BPC); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_CMS_BPC); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.cms_bpc); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); + gtk_widget_show(button); + gtk_widget_show(hbox); + xsane_setup.cms_bpc_button = button; + + + + /* Intent menu */ + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new(MENU_ITEM_CMS_RENDERING_INTENT); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + option_menu = gtk_option_menu_new(); + xsane_back_gtk_set_tooltip(xsane.tooltips, option_menu, DESC_RENDERING_INTENT); + gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 2); + gtk_widget_show(option_menu); + gtk_widget_show(hbox); + + menu = gtk_menu_new(); + + menu_item = gtk_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_PERCEPTUAL); + gtk_object_set_data(GTK_OBJECT(menu_item), "Selection", (void *) INTENT_PERCEPTUAL); + gtk_container_add(GTK_CONTAINER(menu), menu_item); + gtk_widget_show(menu_item); + + menu_item = gtk_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_RELATIVE_COLORIMETRIC); + gtk_object_set_data(GTK_OBJECT(menu_item), "Selection", (void *) INTENT_RELATIVE_COLORIMETRIC); + gtk_container_add(GTK_CONTAINER(menu), menu_item); + gtk_widget_show(menu_item); + + menu_item = gtk_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_ABSOLUTE_COLORIMETRIC); + gtk_object_set_data(GTK_OBJECT(menu_item), "Selection", (void *) INTENT_ABSOLUTE_COLORIMETRIC); + gtk_container_add(GTK_CONTAINER(menu), menu_item); + gtk_widget_show(menu_item); + + menu_item = gtk_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_SATURATION); + gtk_object_set_data(GTK_OBJECT(menu_item), "Selection", (void *) INTENT_SATURATION); + gtk_container_add(GTK_CONTAINER(menu), menu_item); + gtk_widget_show(menu_item); + + if (preferences.cms_intent == INTENT_PERCEPTUAL) + { + selection = 0; + } + else if (preferences.cms_intent == INTENT_RELATIVE_COLORIMETRIC) + { + selection = 1; + } + else if (preferences.cms_intent == INTENT_ABSOLUTE_COLORIMETRIC) + { + selection = 2; + } + else + { + selection = 3; + } + + + gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), selection); + xsane_setup.cms_intent_option_menu = option_menu; + + + xsane_separator_new(vbox, 4); + + + /* scanner_default_color_icm_profile filename : */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_SCANNER_DEFAULT_COLOR_ICM_PROFILE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + button = gtk_button_new_with_label(BUTTON_BROWSE); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_browse_scanner_default_color_icm_profile_callback, NULL); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 2); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_BUTTON_SCANNER_DEFAULT_COLOR_ICM_PROFILE_BROWSE); + gtk_widget_show(button); + + text = gtk_entry_new_with_max_length(PATH_MAX); + gtk_widget_set_size_request(text, 250, -1); /* set minimum size */ + xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_SCANNER_DEFAULT_COLOR_ICM_PROFILE); + + if (xsane.scanner_default_color_icm_profile) + { + gtk_entry_set_text(GTK_ENTRY(text), (char *) xsane.scanner_default_color_icm_profile); + } + + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 4); + gtk_widget_show(text); + xsane_setup.scanner_default_color_icm_profile_entry = text; + + gtk_widget_show(hbox); + + + /* scanner_default_gray_icm_profile filename : */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_SCANNER_DEFAULT_GRAY_ICM_PROFILE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + button = gtk_button_new_with_label(BUTTON_BROWSE); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_browse_scanner_default_gray_icm_profile_callback, NULL); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 2); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_BUTTON_SCANNER_DEFAULT_GRAY_ICM_PROFILE_BROWSE); + gtk_widget_show(button); + + text = gtk_entry_new_with_max_length(PATH_MAX); + gtk_widget_set_size_request(text, 250, -1); /* set minimum size */ + xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_SCANNER_DEFAULT_GRAY_ICM_PROFILE); + + if (xsane.scanner_default_gray_icm_profile) + { + gtk_entry_set_text(GTK_ENTRY(text), (char *) xsane.scanner_default_gray_icm_profile); + } + + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 4); + gtk_widget_show(text); + xsane_setup.scanner_default_gray_icm_profile_entry = text; + + gtk_widget_show(hbox); + +#if 0 + xsane_separator_new(vbox, 4); + + + /* scanner_tran icm-profile filename : */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_SCANNER_TRAN_ICM_PROFILE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + button = gtk_button_new_with_label(BUTTON_BROWSE); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_browse_scanner_tran_icm_profile_callback, NULL); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 2); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_BUTTON_SCANNER_TRAN_ICM_PROFILE_BROWSE); + gtk_widget_show(button); + + text = gtk_entry_new_with_max_length(PATH_MAX); + gtk_widget_set_size_request(text, 250, -1); /* set minimum size */ + xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_SCANNER_TRAN_ICM_PROFILE); + + if (xsane.scanner_tran_icm_profile) + { + gtk_entry_set_text(GTK_ENTRY(text), (char *) xsane.scanner_tran_icm_profile); + } + + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 4); + gtk_widget_show(text); + xsane_setup.scanner_tran_icm_profile_entry = text; + + gtk_widget_show(hbox); + + + /* scanner_tran_gray icm-profile filename : */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_SCANNER_TRAN_GRAY_ICM_PROFILE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + button = gtk_button_new_with_label(BUTTON_BROWSE); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_browse_scanner_tran_gray_icm_profile_callback, NULL); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 2); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_BUTTON_SCANNER_TRAN_GRAY_ICM_PROFILE_BROWSE); + gtk_widget_show(button); + + text = gtk_entry_new_with_max_length(PATH_MAX); + gtk_widget_set_size_request(text, 250, -1); /* set minimum size */ + xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_SCANNER_TRAN_GRAY_ICM_PROFILE); + + if (xsane.scanner_tran_gray_icm_profile) + { + gtk_entry_set_text(GTK_ENTRY(text), (char *) xsane.scanner_tran_gray_icm_profile); + } + + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 4); + gtk_widget_show(text); + xsane_setup.scanner_tran_gray_icm_profile_entry = text; + + gtk_widget_show(hbox); +#endif + + xsane_separator_new(vbox, 4); + + + /* display icm-profile filename : */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_DISPLAY_ICM_PROFILE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + button = gtk_button_new_with_label(BUTTON_BROWSE); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_browse_display_icm_profile_callback, NULL); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 2); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_BUTTON_DISPLAY_ICM_PROFILE_BROWSE); + gtk_widget_show(button); + + text = gtk_entry_new_with_max_length(PATH_MAX); + gtk_widget_set_size_request(text, 250, -1); /* set minimum size */ + xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_DISPLAY_ICM_PROFILE); + + if (preferences.display_icm_profile) + { + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.display_icm_profile); + } + + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 4); + gtk_widget_show(text); + xsane_setup.display_icm_profile_entry = text; + + gtk_widget_show(hbox); + + + + /* custom output icm-profile filename : */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_CUSTOM_PROOFING_ICM_PROFILE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + button = gtk_button_new_with_label(BUTTON_BROWSE); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_browse_custom_proofing_icm_profile_callback, NULL); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 2); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_BUTTON_CUSTOM_PROOFING_ICM_PROFILE_BROWSE); + gtk_widget_show(button); + + text = gtk_entry_new_with_max_length(PATH_MAX); + gtk_widget_set_size_request(text, 250, -1); /* set minimum size */ + xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_CUSTOM_PROOFING_ICM_PROFILE); + + if (preferences.custom_proofing_icm_profile) + { + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.custom_proofing_icm_profile); + } + + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 4); + gtk_widget_show(text); + xsane_setup.custom_proofing_icm_profile_entry = text; + + gtk_widget_show(hbox); + + + xsane_separator_new(vbox, 4); + + + /* working color space icm-profile filename : */ + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_WORKING_COLOR_SPACE_ICM_PROFILE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + button = gtk_button_new_with_label(BUTTON_BROWSE); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_browse_working_color_space_icm_profile_callback, NULL); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 2); + xsane_back_gtk_set_tooltip(xsane.tooltips, button, DESC_BUTTON_WORKING_COLOR_SPACE_ICM_PROFILE_BROWSE); + gtk_widget_show(button); + + text = gtk_entry_new_with_max_length(PATH_MAX); + gtk_widget_set_size_request(text, 250, -1); /* set minimum size */ + xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_WORKING_COLOR_SPACE_ICM_PROFILE); + + if (preferences.working_color_space_icm_profile) + { + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.working_color_space_icm_profile); + } + + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 4); + gtk_widget_show(text); + xsane_setup.working_color_space_icm_profile_entry = text; + + gtk_widget_show(hbox); + + + + xsane_separator_new(vbox, 4); + + + + /* apply button */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + +#ifdef HAVE_GTK2 + button = gtk_button_new_from_stock(GTK_STOCK_APPLY); +#else + button = gtk_button_new_with_label(BUTTON_APPLY); +#endif + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_color_management_apply_changes, NULL); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + gtk_widget_show(hbox); +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + void xsane_setup_dialog(GtkWidget *widget, gpointer data) { GtkWidget *setup_dialog, *setup_vbox, *hbox, *button, *notebook; @@ -3267,6 +3891,9 @@ void xsane_setup_dialog(GtkWidget *widget, gpointer data) xsane_ocr_notebook(notebook); xsane_display_notebook(notebook); xsane_enhance_notebook(notebook); +#ifdef HAVE_LIBLCMS + xsane_color_management_notebook(notebook); +#endif /* set the main hbox */ @@ -3277,23 +3904,23 @@ void xsane_setup_dialog(GtkWidget *widget, gpointer data) gtk_widget_show(hbox); #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_OK); + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); #else - button = gtk_button_new_with_label(BUTTON_OK); + button = gtk_button_new_with_label(BUTTON_CANCEL); #endif - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_options_ok_callback, setup_dialog); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_close_setup_dialog_callback, setup_dialog); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); - gtk_widget_grab_default(button); gtk_widget_show(button); #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + button = gtk_button_new_from_stock(GTK_STOCK_OK); #else - button = gtk_button_new_with_label(BUTTON_CANCEL); + button = gtk_button_new_with_label(BUTTON_OK); #endif - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_close_setup_dialog_callback, setup_dialog); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_options_ok_callback, setup_dialog); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_grab_default(button); gtk_widget_show(button); gtk_widget_show(setup_dialog); diff --git a/src/xsane-setup.h b/src/xsane-setup.h index 8055dfb..155790f 100644 --- a/src/xsane-setup.h +++ b/src/xsane-setup.h @@ -3,7 +3,7 @@ xsane-setup.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify diff --git a/src/xsane-text.h b/src/xsane-text.h index 7614bfc..c271956 100644 --- a/src/xsane-text.h +++ b/src/xsane-text.h @@ -3,7 +3,7 @@ xsane-text.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -26,182 +26,193 @@ #define XSANE_TEXT_H /* Please translate this to the correct directory name (eg. german=>de) */ -#define XSANE_LANGUAGE_DIR _("language_dir") - -#define XSANE_STRSTATUS(status) _(sane_strstatus(status)) -#define _BGT(text) dgettext(xsane.backend_translation, text) - -#define XSANE_COPYRIGHT_SIGN _("(c)") /* can be translated with \251 */ - -#define FILENAME_PREFIX_CLONE_OF _("clone-of-") - -#define WINDOW_ABOUT_XSANE _("About") -#define WINDOW_ABOUT_TRANSLATION _("About translation") -#define WINDOW_AUTHORIZE _("authorization") -#define WINDOW_GPL _("GPL - the license") -#define WINDOW_EULA _("End User License Agreement") -#define WINDOW_INFO _("info") -#define WINDOW_LOAD_BATCH_LIST _("load batch list") -#define WINDOW_SAVE_BATCH_LIST _("save batch list") -#define WINDOW_BATCH_SCAN _("batch scan") -#define WINDOW_BATCH_RENAME _("rename batch area") -#define WINDOW_FAX_PROJECT _("fax project") -#define WINDOW_FAX_RENAME _("rename fax page") -#define WINDOW_FAX_INSERT _("insert ps-file into fax") -#define WINDOW_EMAIL_PROJECT _("E-mail project") -#define WINDOW_EMAIL_RENAME _("rename e-mail image") -#define WINDOW_EMAIL_INSERT _("insert file into e-mail") -#define WINDOW_MULTIPAGE_PROJECT _("multipage project") -#define WINDOW_PRESET_AREA_RENAME _("rename preset area") -#define WINDOW_PRESET_AREA_ADD _("add preset area") -#define WINDOW_MEDIUM_RENAME _("rename medium") -#define WINDOW_MEDIUM_ADD _("add new medium") -#define WINDOW_SETUP _("setup") -#define WINDOW_HISTOGRAM _("Histogram") -#define WINDOW_GAMMA _("Gamma curve") -#define WINDOW_STANDARD_OPTIONS _("Standard options") -#define WINDOW_ADVANCED_OPTIONS _("Advanced options") -#define WINDOW_DEVICE_SELECTION _("device selection") -#define WINDOW_PREVIEW _("Preview") -#define WINDOW_VIEWER _("Viewer") -#define WINDOW_VIEWER_OUTPUT_FILENAME _("Viewer: select output filename") -#define WINDOW_OCR_OUTPUT_FILENAME _("Select output filename for OCR text file") -#define WINDOW_OUTPUT_FILENAME _("select output filename") -#define WINDOW_SAVE_SETTINGS _("save device settings") -#define WINDOW_LOAD_SETTINGS _("load device settings") -#define WINDOW_CHANGE_WORKING_DIR _("change working directory") -#define WINDOW_TMP_PATH _("select temporary directory") -#define WINDOW_SCALE _("Scale image") -#define WINDOW_DESPECKLE _("Despeckle image") -#define WINDOW_BLUR _("Blur image") -#define WINDOW_STORE_MEDIUM _("Store medium definition") -#define WINDOW_NO_DEVICES _("No devices available") - -#define MENU_FILE _("File") -#define MENU_PREFERENCES _("Preferences") -#define MENU_VIEW _("View") -#define MENU_WINDOW _("Window") -#define MENU_HELP _("Help") -#define MENU_EDIT _("Edit") -#define MENU_FILTERS _("Filters") -#define MENU_GEOMETRY _("Geometry") - -#define MENU_ITEM_ABOUT_XSANE _("About XSane") -#define MENU_ITEM_ABOUT_TRANSLATION _("About translation") -#define MENU_ITEM_INFO _("Info") -#define MENU_ITEM_QUIT _("Quit") - -#define MENU_ITEM_SAVE_IMAGE _("Save image") -#define MENU_ITEM_OCR _("OCR - save as text") -#define MENU_ITEM_CLONE _("Clone") -#define MENU_ITEM_SCALE _("Scale") -#define MENU_ITEM_CLOSE _("Close") - -#define MENU_ITEM_UNDO _("Undo") - -#define MENU_ITEM_DESPECKLE _("Despeckle") -#define MENU_ITEM_BLUR _("Blur") - -#define MENU_ITEM_ROTATE90 _("Rotate 90") -#define MENU_ITEM_ROTATE180 _("Rotate 180") -#define MENU_ITEM_ROTATE270 _("Rotate 270") -#define MENU_ITEM_MIRROR_X _("Mirror |") -#define MENU_ITEM_MIRROR_Y _("Mirror -") - -#define FRAME_RAW_IMAGE _("Raw image") -#define FRAME_ENHANCED_IMAGE _("Enhanced image") - -#define BUTTON_SCAN _("Scan") -#define BUTTON_OK _("Ok") -#define BUTTON_ACCEPT _("Accept") -#define BUTTON_NOT_ACCEPT _("Not accept") -#define BUTTON_APPLY _("Apply") -#define BUTTON_CANCEL _("Cancel") -#define BUTTON_REDUCE _("Reduce") -#define BUTTON_CONT_AT_OWN_RISK _("Continue at your own risk") -#define BUTTON_BROWSE _("Browse") -#define BUTTON_CLOSE _("Close") -#define BUTTON_HELP _("Help") -#define BUTTON_OVERWRITE _("Overwrite") -#define BUTTON_BATCH_LIST_SCAN _("Scan batch list") -#define BUTTON_BATCH_AREA_SCAN _("Scan selected area") -#define BUTTON_PAGE_DELETE _("Delete page") -#define BUTTON_PAGE_SHOW _("Show page") -#define BUTTON_PAGE_RENAME _("Rename page") -#define BUTTON_IMAGE_DELETE _("Delete image") -#define BUTTON_IMAGE_SHOW _("Show image") -#define BUTTON_IMAGE_EDIT _("Edit image") -#define BUTTON_IMAGE_RENAME _("Rename image") -#define BUTTON_FILE_INSERT _("Insert file") -#define BUTTON_CREATE_PROJECT _("Create project") -#define BUTTON_SEND_PROJECT _("Send project") -#define BUTTON_SAVE_MULTIPAGE _("Save multipage file") -#define BUTTON_DELETE_PROJECT _("Delete project") -#define BUTTON_ADD_PRINTER _("Add printer") -#define BUTTON_DELETE_PRINTER _("Delete printer") -#define BUTTON_PREVIEW_ACQUIRE _("Acquire preview") -#define BUTTON_PREVIEW_CANCEL _("Cancel preview") -#define BUTTON_DISCARD_IMAGE _("Discard image") -#define BUTTON_DISCARD_ALL_IMAGES _("Discard all images") -#define BUTTON_DO_NOT_CLOSE _("Do not close") -#define BUTTON_SCALE_BIND _("Bind scale") - -#define RADIO_BUTTON_FINE_MODE _("Fine mode") -#define RADIO_BUTTON_HTML_EMAIL _("HTML e-mail") -#define RADIO_BUTTON_SAVE_DEVPREFS_AT_EXIT _("Save device preferences at exit") -#define RADIO_BUTTON_OVERWRITE_WARNING _("Overwrite warning") -#define RADIO_BUTTON_SKIP_EXISTING_NRS _("Skip existing filenames") -#define RADIO_BUTTON_SAVE_PS_FLATDECODED _("Save postscript zlib compressed (ps level 3)") -#define RADIO_BUTTON_SAVE_PDF_FLATDECODED _("Save PDF zlib compressed") -#define RADIO_BUTTON_SAVE_PNM16_AS_ASCII _("Save 16bit pnm in ascii format") -#define RADIO_BUTTON_REDUCE_16BIT_TO_8BIT _("Reduce 16 bit image to 8 bit") -#define RADIO_BUTTON_WINDOW_FIXED _("Main window size fixed") -#define RADIO_BUTTON_DISABLE_GIMP_PREVIEW_GAMMA _("Disable gimp preview gamma") -#define RADIO_BUTTON_PRIVATE_COLORMAP _("Use private colormap") -#define RADIO_BUTTON_AUTOENHANCE_GAMMA _("Autoenhance gamma") -#define RADIO_BUTTON_PRESELECT_SCANAREA _("Preselect scanarea") -#define RADIO_BUTTON_AUTOCORRECT_COLORS _("Autocorrect colors") -#define RADIO_BUTTON_OCR_USE_GUI_PIPE _("Use GUI progress pipe") - -#define TEXT_SCANNING_DEVICES _("scanning for devices") -#define TEXT_AVAILABLE_DEVICES _("Available devices:") -#define TEXT_XSANE_OPTIONS _("XSane options") -#define TEXT_FILETYPE _("Type") -#define TEXT_SCANNER_BACKEND _("Scanner and backend:") -#define TEXT_VENDOR _("Vendor:") -#define TEXT_MODEL _("Model:") -#define TEXT_TYPE _("Type:") -#define TEXT_DEVICE _("Device:") -#define TEXT_LOADED_BACKEND _("Loaded backend:") -#define TEXT_SANE_VERSION _("Sane version:") -#define TEXT_RECENT_VALUES _("Recent values:") -#define TEXT_GAMMA_CORR_BY _("Gamma correction by:") -#define TEXT_SCANNER _("scanner") -#define TEXT_SOFTWARE_XSANE _("software (XSane)") -#define TEXT_NONE _("none") -#define TEXT_GAMMA_INPUT_DEPTH _("Gamma input depth:") -#define TEXT_GAMMA_OUTPUT_DEPTH _("Gamma output depth:") -#define TEXT_SCANNER_OUTPUT_DEPTH _("Scanner output depth:") -#define TEXT_OUTPUT_FORMATS _("XSane output formats:") -#define TEXT_8BIT_FORMATS _("8 bit output formats:") -#define TEXT_16BIT_FORMATS _("16 bit output formats:") -#define TEXT_GIMP_REDUCE_16BIT_TO_8BIT _("Gimp does not support depth 16 bits/color.\n" \ - "Do you want to reduce the depth to 8 bits/color?") -#define TEXT_REDUCE_16BIT_TO_8BIT _("Bit depth 16 bits/color is not supported for this output format.\n" \ - "Do you want to reduce the depth to 8 bits/color?") -#define TEXT_AUTHORIZATION_REQ _("Authorization required for") -#define TEXT_AUTHORIZATION_SECURE _("Password transmission is secure") -#define TEXT_AUTHORIZATION_INSECURE _("Backend requests plain-text password") -#define TEXT_USERNAME _("Username :") -#define TEXT_PASSWORD _("Password :") -#define TEXT_INVALID_PARAMS _("Invalid parameters.") -#define TEXT_VERSION _("version:") -#define TEXT_PACKAGE _("package") -#define TEXT_WITH_GIMP_SUPPORT _("with GIMP support") -#define TEXT_WITHOUT_GIMP_SUPPORT _("without GIMP support") -#define TEXT_GTK_VERSION _("compiled with GTK-") -#define TEXT_GIMP_VERSION _("compiled with GIMP-") -#define TEXT_UNKNOWN _("unknown") +#define XSANE_LANGUAGE_DIR _("language_dir") + +#define XSANE_STRSTATUS(status) _(sane_strstatus(status)) +#define _BGT(text) dgettext(xsane.backend_translation, text) + +#define XSANE_COPYRIGHT_SIGN _("(c)") /* can be translated with \251 */ + +#define FILENAME_PREFIX_CLONE_OF _("clone-of-") + +#define WINDOW_ABOUT_XSANE _("About") +#define WINDOW_ABOUT_TRANSLATION _("About translation") +#define WINDOW_AUTHORIZE _("authorization") +#define WINDOW_GPL _("GPL - the license") +#define WINDOW_EULA _("End User License Agreement") +#define WINDOW_INFO _("info") +#define WINDOW_LOAD_BATCH_LIST _("load batch list") +#define WINDOW_SAVE_BATCH_LIST _("save batch list") +#define WINDOW_BATCH_SCAN _("batch scan") +#define WINDOW_BATCH_RENAME _("rename batch area") +#define WINDOW_FAX_PROJECT _("fax project") +#define WINDOW_FAX_PROJECT_BROWSE _("browse for fax project") +#define WINDOW_FAX_RENAME _("rename fax page") +#define WINDOW_FAX_INSERT _("insert ps-file into fax") +#define WINDOW_EMAIL_PROJECT _("E-mail project") +#define WINDOW_EMAIL_PROJECT_BROWSE _("browse for email project") +#define WINDOW_EMAIL_RENAME _("rename e-mail image") +#define WINDOW_EMAIL_INSERT _("insert file into e-mail") +#define WINDOW_MULTIPAGE_PROJECT _("multipage project") +#define WINDOW_MULTIPAGE_PROJECT_BROWSE _("browse for multipage project") +#define WINDOW_PRESET_AREA_RENAME _("rename preset area") +#define WINDOW_PRESET_AREA_ADD _("add preset area") +#define WINDOW_MEDIUM_RENAME _("rename medium") +#define WINDOW_MEDIUM_ADD _("add new medium") +#define WINDOW_SETUP _("setup") +#define WINDOW_HISTOGRAM _("Histogram") +#define WINDOW_GAMMA _("Gamma curve") +#define WINDOW_STANDARD_OPTIONS _("Standard options") +#define WINDOW_ADVANCED_OPTIONS _("Advanced options") +#define WINDOW_DEVICE_SELECTION _("device selection") +#define WINDOW_PREVIEW _("Preview") +#define WINDOW_VIEWER _("Viewer") +#define WINDOW_VIEWER_OUTPUT_FILENAME _("Viewer: select output filename") +#define WINDOW_OCR_OUTPUT_FILENAME _("Select output filename for OCR text file") +#define WINDOW_OUTPUT_FILENAME _("select output filename") +#define WINDOW_SAVE_SETTINGS _("save device settings") +#define WINDOW_LOAD_SETTINGS _("load device settings") +#define WINDOW_CHANGE_WORKING_DIR _("change working directory") +#define WINDOW_TMP_PATH _("select temporary directory") +#define WINDOW_SCALE _("Scale image") +#define WINDOW_DESPECKLE _("Despeckle image") +#define WINDOW_BLUR _("Blur image") +#define WINDOW_STORE_MEDIUM _("Store medium definition") +#define WINDOW_NO_DEVICES _("No devices available") +#define WINDOW_SCANNER_DEFAULT_COLOR_ICM_PROFILE _("select scanner default color ICM-profile") +#define WINDOW_SCANNER_DEFAULT_GRAY_ICM_PROFILE _("select scanner default gray ICM-profile") +#define WINDOW_DISPLAY_ICM_PROFILE _("select display ICM-profile") +#define WINDOW_CUSTOM_PROOFING_ICM_PROFILE _("select custom proofing ICM-profile") +#define WINDOW_WORKING_COLOR_SPACE_ICM_PROFILE _("select working color space ICM-profile") +#define WINDOW_PRINTER_ICM_PROFILE _("select printer ICM-profile") + +#define MENU_FILE _("File") +#define MENU_PREFERENCES _("Preferences") +#define MENU_VIEW _("View") +#define MENU_WINDOW _("Window") +#define MENU_HELP _("Help") +#define MENU_EDIT _("Edit") +#define MENU_FILTERS _("Filters") +#define MENU_GEOMETRY _("Geometry") +#define MENU_COLOR_MANAGEMENT _("Color management") + +#define MENU_ITEM_ABOUT_XSANE _("About XSane") +#define MENU_ITEM_ABOUT_TRANSLATION _("About translation") +#define MENU_ITEM_INFO _("Info") +#define MENU_ITEM_QUIT _("Quit") + +#define MENU_ITEM_SAVE_IMAGE _("Save image") +#define MENU_ITEM_OCR _("OCR - save as text") +#define MENU_ITEM_CLONE _("Clone") +#define MENU_ITEM_SCALE _("Scale") +#define MENU_ITEM_CLOSE _("Close") + +#define MENU_ITEM_UNDO _("Undo") + +#define MENU_ITEM_DESPECKLE _("Despeckle") +#define MENU_ITEM_BLUR _("Blur") + +#define MENU_ITEM_ROTATE90 _("Rotate 90") +#define MENU_ITEM_ROTATE180 _("Rotate 180") +#define MENU_ITEM_ROTATE270 _("Rotate 270") +#define MENU_ITEM_MIRROR_X _("Mirror |") +#define MENU_ITEM_MIRROR_Y _("Mirror -") + +#define FRAME_RAW_IMAGE _("Raw image") +#define FRAME_ENHANCED_IMAGE _("Enhanced image") + +#define BUTTON_SCAN _("Scan") +#define BUTTON_OK _("Ok") +#define BUTTON_ACCEPT _("Accept") +#define BUTTON_NOT_ACCEPT _("Not accept") +#define BUTTON_APPLY _("Apply") +#define BUTTON_CANCEL _("Cancel") +#define BUTTON_REDUCE _("Reduce") +#define BUTTON_CONT_AT_OWN_RISK _("Continue at your own risk") +#define BUTTON_BROWSE _("Browse") +#define BUTTON_CLOSE _("Close") +#define BUTTON_HELP _("Help") +#define BUTTON_OVERWRITE _("Overwrite") +#define BUTTON_BATCH_LIST_SCAN _("Scan batch list") +#define BUTTON_BATCH_AREA_SCAN _("Scan selected area") +#define BUTTON_PAGE_DELETE _("Delete page") +#define BUTTON_PAGE_SHOW _("Show page") +#define BUTTON_PAGE_RENAME _("Rename page") +#define BUTTON_IMAGE_DELETE _("Delete image") +#define BUTTON_IMAGE_SHOW _("Show image") +#define BUTTON_IMAGE_EDIT _("Edit image") +#define BUTTON_IMAGE_RENAME _("Rename image") +#define BUTTON_FILE_INSERT _("Insert file") +#define BUTTON_CREATE_PROJECT _("Create project") +#define BUTTON_SEND_PROJECT _("Send project") +#define BUTTON_SAVE_MULTIPAGE _("Save multipage file") +#define BUTTON_DELETE_PROJECT _("Delete project") +#define BUTTON_ADD_PRINTER _("Add printer") +#define BUTTON_DELETE_PRINTER _("Delete printer") +#define BUTTON_PREVIEW_ACQUIRE _("Acquire preview") +#define BUTTON_PREVIEW_CANCEL _("Cancel preview") +#define BUTTON_DISCARD_IMAGE _("Discard image") +#define BUTTON_DISCARD_ALL_IMAGES _("Discard all images") +#define BUTTON_DO_NOT_CLOSE _("Do not close") +#define BUTTON_SCALE_BIND _("Bind scale") + +#define RADIO_BUTTON_FINE_MODE _("Fine mode") +#define RADIO_BUTTON_HTML_EMAIL _("HTML e-mail") +#define RADIO_BUTTON_SAVE_DEVPREFS_AT_EXIT _("Save device preferences at exit") +#define RADIO_BUTTON_OVERWRITE_WARNING _("Overwrite warning") +#define RADIO_BUTTON_SKIP_EXISTING_NRS _("Skip existing filenames") +#define RADIO_BUTTON_SAVE_PS_FLATEDECODED _("Save postscript zlib compressed (ps level 3)") +#define RADIO_BUTTON_SAVE_PDF_FLATEDECODED _("Save PDF zlib compressed") +#define RADIO_BUTTON_SAVE_PNM16_AS_ASCII _("Save 16bit pnm in ascii format") +#define RADIO_BUTTON_REDUCE_16BIT_TO_8BIT _("Reduce 16 bit image to 8 bit") +#define RADIO_BUTTON_WINDOW_FIXED _("Main window size fixed") +#define RADIO_BUTTON_DISABLE_GIMP_PREVIEW_GAMMA _("Disable GIMP preview gamma") +#define RADIO_BUTTON_PRIVATE_COLORMAP _("Use private colormap") +#define RADIO_BUTTON_AUTOENHANCE_GAMMA _("Autoenhance gamma") +#define RADIO_BUTTON_PRESELECT_SCANAREA _("Preselect scanarea") +#define RADIO_BUTTON_AUTOCORRECT_COLORS _("Autocorrect colors") +#define RADIO_BUTTON_OCR_USE_GUI_PIPE _("Use GUI progress pipe") +#define RADIO_BUTTON_CMS_BPC _("Black point compensation") + +#define TEXT_SCANNING_DEVICES _("scanning for devices") +#define TEXT_AVAILABLE_DEVICES _("Available devices:") +#define TEXT_XSANE_OPTIONS _("XSane options") +#define TEXT_FILETYPE _("Type") +#define TEXT_CMS_FUNCTION _("Color management function") +#define TEXT_SCANNER_BACKEND _("Scanner and backend:") +#define TEXT_VENDOR _("Vendor:") +#define TEXT_MODEL _("Model:") +#define TEXT_TYPE _("Type:") +#define TEXT_DEVICE _("Device:") +#define TEXT_LOADED_BACKEND _("Loaded backend:") +#define TEXT_SANE_VERSION _("Sane version:") +#define TEXT_RECENT_VALUES _("Recent values:") +#define TEXT_GAMMA_CORR_BY _("Gamma correction by:") +#define TEXT_SCANNER _("scanner") +#define TEXT_SOFTWARE_XSANE _("software (XSane)") +#define TEXT_NONE _("none") +#define TEXT_GAMMA_INPUT_DEPTH _("Gamma input depth:") +#define TEXT_GAMMA_OUTPUT_DEPTH _("Gamma output depth:") +#define TEXT_SCANNER_OUTPUT_DEPTH _("Scanner output depth:") +#define TEXT_OUTPUT_FORMATS _("XSane output formats:") +#define TEXT_8BIT_FORMATS _("8 bit output formats:") +#define TEXT_16BIT_FORMATS _("16 bit output formats:") +#define TEXT_REDUCE_16BIT_TO_8BIT _("Bit depth 16 bits/channel is not supported for this output format.\n" \ + "Do you want to reduce the depth to 8 bits/channel?") +#define TEXT_AUTHORIZATION_REQ _("Authorization required for") +#define TEXT_AUTHORIZATION_SECURE _("Password transmission is secure") +#define TEXT_AUTHORIZATION_INSECURE _("Backend requests plain-text password") +#define TEXT_USERNAME _("Username :") +#define TEXT_PASSWORD _("Password :") +#define TEXT_INVALID_PARAMS _("Invalid parameters.") +#define TEXT_VERSION _("version:") +#define TEXT_PACKAGE _("package") +#define TEXT_WITH_CMS_FUNCTION _("with color management function") +#define TEXT_WITH_GIMP_SUPPORT _("with GIMP support") +#define TEXT_WITHOUT_GIMP_SUPPORT _("without GIMP support") +#define TEXT_GTK_VERSION _("compiled with GTK-") +#define TEXT_GIMP_VERSION _("compiled with GIMP-") +#define TEXT_UNKNOWN _("unknown") #define TEXT_EULA _( "XSane is distributed under the terms of the GNU General Public License\n" \ "as published by the Free Software Foundation; either version 2 of the\n" \ "License, or (at your option) any later version.\n" \ @@ -220,164 +231,196 @@ "This program is distributed in the hope that it will be useful, but\n" \ "WITHOUT ANY WARRANTY; without even the implied warranty of\n" \ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n") -#define TEXT_EMAIL_ADR _("E-mail:") -#define TEXT_HOMEPAGE _("Homepage:") -#define TEXT_FILE _("File:") -#define TEXT_TRANSLATION _("Translation:") +#define TEXT_EMAIL_ADR _("E-mail:") +#define TEXT_HOMEPAGE _("Homepage:") +#define TEXT_FILE _("File:") +#define TEXT_TRANSLATION _("Translation:") /* Please translate this to something like */ /* translation to YOUR LANGUAGE\n */ /* by YOUR NAME\n */ /* E-mail: your.name@yourdomain.com\n */ -#define TEXT_TRANSLATION_INFO _("untranslated original english text\n" \ - "by Oliver Rauch\n" \ - "E-mail: Oliver.Rauch@rauch-domain.de\n") - -#define TEXT_INFO_BOX _("0x0: 0KB") - -#define TEXT_ADF_PAGES_SCANNED _("Scanned pages: ") - -#define TEXT_EMAIL_TEXT _("E-mail text:") -#define TEXT_ATTACHMENTS _("Attachments:") -#define TEXT_EMAIL_STATUS _("Project status:") -#define TEXT_EMAIL_FILETYPE _("E-mail image filetype:") - -#define TEXT_PAGES _("Pages:") -#define TEXT_MULTIPAGE_FILETYPE _("Multipage document filetype:") - -#define TEXT_MEDIUM_DEFINITION_NAME _("Medium Name:") - -#define TEXT_VIEWER_IMAGE_INFO _("Size %d x %d pixel, %d bit/color, %d colors, %1.0f dpi x %1.0f dpi, %1.1f %s") -#define TEXT_DESPECKLE_RADIUS _("Despeckle radius:") -#define TEXT_BLUR_RADIUS _("Blur radius:") -#define TEXT_BATCH_AREA_DEFAULT_NAME _("(no name)") -#define TEXT_BATCH_LIST_AREANAME _("Area name:") -#define TEXT_BATCH_LIST_SCANMODE _("Scanmode:") -#define TEXT_BATCH_LIST_GEOMETRY_TL _("Top left:") -#define TEXT_BATCH_LIST_GEOMETRY_SIZE _("Size:") -#define TEXT_BATCH_LIST_RESOLUTION _("Resolution:") -#define TEXT_BATCH_LIST_BIT_DEPTH _("Bit depth:") -#define TEXT_BATCH_LIST_BY_GUI _("as selected") - -#define TEXT_SETUP_PRINTER_SEL _("Printer selection:") -#define TEXT_SETUP_PRINTER_NAME _("Name:") -#define TEXT_SETUP_PRINTER_CMD _("Command:") -#define TEXT_SETUP_COPY_NR_OPT _("Copy number option:") -#define TEXT_SETUP_PRINTER_LINEART_RES _("Lineart resolution (dpi):") -#define TEXT_SETUP_PRINTER_GRAYSCALE_RES _("Grayscale resolution (dpi):") -#define TEXT_SETUP_PRINTER_COLOR_RES _("Color resolution (dpi):") -#define TEXT_SETUP_PRINTER_WIDTH _("Width") -#define TEXT_SETUP_PRINTER_HEIGHT _("Height") -#define TEXT_SETUP_PRINTER_LEFT _("Left offset") -#define TEXT_SETUP_PRINTER_BOTTOM _("Bottom offset") -#define TEXT_SETUP_PRINTER_GAMMA _("Printer gamma value:") -#define TEXT_SETUP_PRINTER_GAMMA_RED _("Printer gamma red:") -#define TEXT_SETUP_PRINTER_GAMMA_GREEN _("Printer gamma green:") -#define TEXT_SETUP_PRINTER_GAMMA_BLUE _("Printer gamma blue:") -#define TEXT_SETUP_PRINTER_PS_FLATDECODED _("Create zlib compressed postscript image (ps level 3) for printing") -#define TEXT_SETUP_TMP_PATH _("Temporary directory") -#define TEXT_SETUP_IMAGE_PERMISSION _("Image-file permissions") -#define TEXT_SETUP_DIR_PERMISSION _("Directory permissions") -#define TEXT_SETUP_JPEG_QUALITY _("JPEG image quality") -#define TEXT_SETUP_PNG_COMPRESSION _("PNG image compression") -#define TEXT_SETUP_FILENAME_COUNTER_LEN _("Filename counter length") -#define TEXT_SETUP_TIFF_ZIP_COMPRESSION _("TIFF zip compression rate") -#define TEXT_SETUP_TIFF_COMPRESSION_16 _("TIFF 16 bit image compression") -#define TEXT_SETUP_TIFF_COMPRESSION_8 _("TIFF 8 bit image compression") -#define TEXT_SETUP_TIFF_COMPRESSION_1 _("TIFF lineart image compression") -#define TEXT_SETUP_SHOW_RANGE_MODE _("Show range as:") -#define TEXT_SETUP_PREVIEW_OVERSAMPLING _("Preview oversampling:") -#define TEXT_SETUP_PREVIEW_GAMMA _("Preview gamma:") -#define TEXT_SETUP_PREVIEW_GAMMA_RED _("Preview gamma red:") -#define TEXT_SETUP_PREVIEW_GAMMA_GREEN _("Preview gamma green:") -#define TEXT_SETUP_PREVIEW_GAMMA_BLUE _("Preview gamma blue:") -#define TEXT_SETUP_LINEART_MODE _("Threshold option:") -#define TEXT_SETUP_PREVIEW_PIPETTE_RANGE _("Preview pipette range") -#define TEXT_SETUP_THRESHOLD_MIN _("Threshold minimum:") -#define TEXT_SETUP_THRESHOLD_MAX _("Threshold maximum:") -#define TEXT_SETUP_THRESHOLD_MUL _("Threshold multiplier:") -#define TEXT_SETUP_THRESHOLD_OFF _("Threshold offset:") -#define TEXT_SETUP_GRAYSCALE_SCANMODE _("Name of grayscale scanmode:") -#define TEXT_SETUP_HELPFILE_VIEWER _("Helpfile viewer (HTML):") -#define TEXT_SETUP_FAX_COMMAND _("Command:") -#define TEXT_SETUP_FAX_RECEIVER_OPTION _("Receiver option:") -#define TEXT_SETUP_FAX_POSTSCRIPT_OPT _("Postscriptfile option:") -#define TEXT_SETUP_FAX_NORMAL_MODE_OPT _("Normal mode option:") -#define TEXT_SETUP_FAX_FINE_MODE_OPT _("Fine mode option:") -#define TEXT_SETUP_FAX_PROGRAM_DEFAULTS _("Set program defaults for:") -#define TEXT_SETUP_FAX_VIEWER _("Viewer (Postscript):") -#define TEXT_SETUP_FAX_WIDTH _("Width") -#define TEXT_SETUP_FAX_HEIGHT _("Height") -#define TEXT_SETUP_FAX_LEFT _("Left offset") -#define TEXT_SETUP_FAX_BOTTOM _("Bottom offset") -#define TEXT_SETUP_FAX_PS_FLATDECODED _("Create zlib compressed postscript image (ps level 3) for fax") -#define TEXT_SETUP_SMTP_SERVER _("SMTP server:") -#define TEXT_SETUP_SMTP_PORT _("SMTP port:") -#define TEXT_SETUP_EMAIL_FROM _("From:") -#define TEXT_SETUP_EMAIL_REPLY_TO _("Reply to:") -#define TEXT_SETUP_EMAIL_AUTHENTICATION _("E-mail authentication") -#define TEXT_SETUP_EMAIL_AUTH_USER _("User:") -#define TEXT_SETUP_EMAIL_AUTH_PASS _("Password:") -#define TEXT_SETUP_POP3_SERVER _("POP3 server:") -#define TEXT_SETUP_POP3_PORT _("POP3 port:") -#define TEXT_SETUP_OCR_COMMAND _("OCR Command:") -#define TEXT_SETUP_OCR_INPUTFILE_OPT _("Inputfile option:") -#define TEXT_SETUP_OCR_OUTPUTFILE_OPT _("Outputfile option:") -#define TEXT_SETUP_OCR_USE_GUI_PIPE_OPT _("Use GUI progress pipe:") -#define TEXT_SETUP_OCR_OUTFD_OPT _("GUI output-fd option:") -#define TEXT_SETUP_OCR_PROGRESS_KEYWORD _("Progress keyword:") -#define TEXT_SETUP_PERMISSION_USER _("user") -#define TEXT_SETUP_PERMISSION_GROUP _("group") -#define TEXT_SETUP_PERMISSION_ALL _("all") -#define TEXT_NEW_MEDIA_NAME _("new media") - -#define NOTEBOOK_SAVING_OPTIONS _("Save") -#define NOTEBOOK_FILETYPE_OPTIONS _("Filetype") -#define NOTEBOOK_COPY_OPTIONS _("Copy") -#define NOTEBOOK_FAX_OPTIONS _("Fax") -#define NOTEBOOK_EMAIL_OPTIONS _("E-mail") -#define NOTEBOOK_OCR_OPTIONS _("OCR") -#define NOTEBOOK_DISPLAY_OPTIONS _("Display") -#define NOTEBOOK_ENHANCE_OPTIONS _("Enhancement") - -#define MENU_ITEM_SAVE _("Save") -#define MENU_ITEM_VIEWER _("Viewer") -#define MENU_ITEM_COPY _("Copy") -#define MENU_ITEM_MULTIPAGE _("Multipage") -#define MENU_ITEM_FAX _("Fax") -#define MENU_ITEM_EMAIL _("E-mail") - -#define MENU_ITEM_SHOW_TOOLTIPS _("Show tooltips") -#define MENU_ITEM_SHOW_PREVIEW _("Show preview") -#define MENU_ITEM_SHOW_HISTOGRAM _("Show histogram") -#define MENU_ITEM_SHOW_GAMMA _("Show gamma curve") -#define MENU_ITEM_SHOW_BATCH_SCAN _("Show batch scan") -#define MENU_ITEM_SHOW_STANDARDOPTIONS _("Show standard options") -#define MENU_ITEM_SHOW_ADVANCEDOPTIONS _("Show advanced options") - -#define MENU_ITEM_SETUP _("Setup") -#define MENU_ITEM_LENGTH_UNIT _("Length unit") -#define SUBMENU_ITEM_LENGTH_MILLIMETERS _("millimeters") -#define SUBMENU_ITEM_LENGTH_CENTIMETERS _("centimeters") -#define SUBMENU_ITEM_LENGTH_INCHES _("inches") -#define MENU_ITEM_UPDATE_POLICY _("Update policy") -#define SUBMENU_ITEM_POLICY_CONTINUOUS _("continuous") -#define SUBMENU_ITEM_POLICY_DISCONTINU _("discontinuous") -#define SUBMENU_ITEM_POLICY_DELAYED _("delayed") -#define MENU_ITEM_SHOW_RESOLUTIONLIST _("Show resolution list") -#define MENU_ITEM_PAGE_ROTATE _("Rotate postscript") -#define MENU_ITEM_EDIT_MEDIUM_DEF _("Edit medium definition") -#define MENU_ITEM_SAVE_DEVICE_SETTINGS _("Save device settings") -#define MENU_ITEM_LOAD_DEVICE_SETTINGS _("Load device settings") -#define MENU_ITEM_CHANGE_WORKING_DIR _("Change directory") - -#define MENU_ITEM_XSANE_EULA _("Show EULA") -#define MENU_ITEM_XSANE_GPL _("Show license (GPL)") -#define MENU_ITEM_XSANE_DOC _("XSane doc") -#define MENU_ITEM_BACKEND_DOC _("Backend doc") -#define MENU_ITEM_AVAILABLE_BACKENDS _("Available backends") -#define MENU_ITEM_SCANTIPS _("Scantips") -#define MENU_ITEM_PROBLEMS _("Problems?") +#define TEXT_TRANSLATION_INFO _("untranslated original english text\n" \ + "by Oliver Rauch\n" \ + "E-mail: Oliver.Rauch@rauch-domain.de\n") + +#define TEXT_INFO_BOX _("0x0: 0KB") + +#define TEXT_ADF_PAGES_SCANNED _("Scanned pages: ") + +#define TEXT_EMAIL_TEXT _("E-mail text:") +#define TEXT_ATTACHMENTS _("Attachments:") +#define TEXT_EMAIL_STATUS _("Project status:") +#define TEXT_EMAIL_FILETYPE _("E-mail image filetype:") + +#define TEXT_PAGES _("Pages:") +#define TEXT_MULTIPAGE_FILETYPE _("Multipage document filetype:") + +#define TEXT_MEDIUM_DEFINITION_NAME _("Medium Name:") + +#define TEXT_VIEWER_IMAGE_INFO _("Size %d x %d pixel, %d bits/channel, %d channels, %1.0f dpi x %1.0f dpi, %1.1f %s") +#define TEXT_DESPECKLE_RADIUS _("Despeckle radius:") +#define TEXT_BLUR_RADIUS _("Blur radius:") +#define TEXT_BATCH_AREA_DEFAULT_NAME _("(no name)") +#define TEXT_BATCH_LIST_AREANAME _("Area name:") +#define TEXT_BATCH_LIST_SCANMODE _("Scanmode:") +#define TEXT_BATCH_LIST_GEOMETRY_TL _("Top left:") +#define TEXT_BATCH_LIST_GEOMETRY_SIZE _("Size:") +#define TEXT_BATCH_LIST_RESOLUTION _("Resolution:") +#define TEXT_BATCH_LIST_BIT_DEPTH _("Bit depth:") +#define TEXT_BATCH_LIST_BY_GUI _("as selected") + +#define TEXT_SETUP_PRINTER_SEL _("Printer selection:") +#define TEXT_SETUP_PRINTER_NAME _("Name:") +#define TEXT_SETUP_PRINTER_CMD _("Command:") +#define TEXT_SETUP_COPY_NR_OPT _("Copy number option:") +#define TEXT_SETUP_PRINTER_LINEART_RES _("Lineart resolution (dpi):") +#define TEXT_SETUP_PRINTER_GRAYSCALE_RES _("Grayscale resolution (dpi):") +#define TEXT_SETUP_PRINTER_COLOR_RES _("Color resolution (dpi):") +#define TEXT_SETUP_PRINTER_WIDTH _("Width") +#define TEXT_SETUP_PRINTER_HEIGHT _("Height") +#define TEXT_SETUP_PRINTER_LEFT _("Left offset") +#define TEXT_SETUP_PRINTER_BOTTOM _("Bottom offset") +#define TEXT_SETUP_PRINTER_GAMMA _("Printer gamma value:") +#define TEXT_SETUP_PRINTER_GAMMA_RED _("Printer gamma red:") +#define TEXT_SETUP_PRINTER_GAMMA_GREEN _("Printer gamma green:") +#define TEXT_SETUP_PRINTER_GAMMA_BLUE _("Printer gamma blue:") +#define TEXT_SETUP_PRINTER_EMBED_CSA _("Embed scanner ICM profile as CSA") +#define TEXT_SETUP_PRINTER_EMBED_CRD _("Embed printer ICM profile as CRD") +#define TEXT_SETUP_PRINTER_PS_FLATEDECODED _("Create zlib compressed postscript image (ps level 3) for printing") +#define TEXT_SETUP_TMP_PATH _("Temporary directory") +#define TEXT_SETUP_IMAGE_PERMISSION _("Image-file permissions") +#define TEXT_SETUP_DIR_PERMISSION _("Directory permissions") +#define TEXT_SETUP_JPEG_QUALITY _("JPEG image quality") +#define TEXT_SETUP_PNG_COMPRESSION _("PNG image compression") +#define TEXT_SETUP_FILENAME_COUNTER_LEN _("Filename counter length") +#define TEXT_SETUP_TIFF_ZIP_COMPRESSION _("TIFF zip compression rate") +#define TEXT_SETUP_TIFF_COMPRESSION_16 _("TIFF 16 bit image compression") +#define TEXT_SETUP_TIFF_COMPRESSION_8 _("TIFF 8 bit image compression") +#define TEXT_SETUP_TIFF_COMPRESSION_1 _("TIFF lineart image compression") +#define TEXT_SETUP_SHOW_RANGE_MODE _("Show range as:") +#define TEXT_SETUP_PREVIEW_OVERSAMPLING _("Preview oversampling:") +#define TEXT_SETUP_PREVIEW_GAMMA _("Preview gamma:") +#define TEXT_SETUP_PREVIEW_GAMMA_RED _("Preview gamma red:") +#define TEXT_SETUP_PREVIEW_GAMMA_GREEN _("Preview gamma green:") +#define TEXT_SETUP_PREVIEW_GAMMA_BLUE _("Preview gamma blue:") +#define TEXT_SETUP_LINEART_MODE _("Threshold option:") +#define TEXT_SETUP_PREVIEW_PIPETTE_RANGE _("Preview pipette range") +#define TEXT_SETUP_THRESHOLD_MIN _("Threshold minimum:") +#define TEXT_SETUP_THRESHOLD_MAX _("Threshold maximum:") +#define TEXT_SETUP_THRESHOLD_MUL _("Threshold multiplier:") +#define TEXT_SETUP_THRESHOLD_OFF _("Threshold offset:") +#define TEXT_SETUP_GRAYSCALE_SCANMODE _("Name of grayscale scanmode:") +#define TEXT_SETUP_HELPFILE_VIEWER _("Helpfile viewer (HTML):") +#define TEXT_SETUP_FAX_COMMAND _("Command:") +#define TEXT_SETUP_FAX_RECEIVER_OPTION _("Receiver option:") +#define TEXT_SETUP_FAX_POSTSCRIPT_OPT _("Postscriptfile option:") +#define TEXT_SETUP_FAX_NORMAL_MODE_OPT _("Normal mode option:") +#define TEXT_SETUP_FAX_FINE_MODE_OPT _("Fine mode option:") +#define TEXT_SETUP_FAX_PROGRAM_DEFAULTS _("Set program defaults for:") +#define TEXT_SETUP_FAX_VIEWER _("Viewer (Postscript):") +#define TEXT_SETUP_FAX_WIDTH _("Width") +#define TEXT_SETUP_FAX_HEIGHT _("Height") +#define TEXT_SETUP_FAX_LEFT _("Left offset") +#define TEXT_SETUP_FAX_BOTTOM _("Bottom offset") +#define TEXT_SETUP_FAX_PS_FLATEDECODED _("Create zlib compressed postscript image (ps level 3) for fax") +#define TEXT_SETUP_SMTP_SERVER _("SMTP server:") +#define TEXT_SETUP_SMTP_PORT _("SMTP port:") +#define TEXT_SETUP_EMAIL_FROM _("From:") +#define TEXT_SETUP_EMAIL_REPLY_TO _("Reply to:") +#define TEXT_SETUP_EMAIL_AUTHENTICATION _("E-mail authentication") +#define TEXT_SETUP_EMAIL_AUTH_USER _("User:") +#define TEXT_SETUP_EMAIL_AUTH_PASS _("Password:") +#define TEXT_SETUP_POP3_SERVER _("POP3 server:") +#define TEXT_SETUP_POP3_PORT _("POP3 port:") +#define TEXT_SETUP_OCR_COMMAND _("OCR Command:") +#define TEXT_SETUP_OCR_INPUTFILE_OPT _("Inputfile option:") +#define TEXT_SETUP_OCR_OUTPUTFILE_OPT _("Outputfile option:") +#define TEXT_SETUP_OCR_USE_GUI_PIPE_OPT _("Use GUI progress pipe:") +#define TEXT_SETUP_OCR_OUTFD_OPT _("GUI output-fd option:") +#define TEXT_SETUP_OCR_PROGRESS_KEYWORD _("Progress keyword:") +#define TEXT_SETUP_PERMISSION_USER _("user") +#define TEXT_SETUP_PERMISSION_GROUP _("group") +#define TEXT_SETUP_PERMISSION_ALL _("all") +#define TEXT_SETUP_SCANNER_DEFAULT_COLOR_ICM_PROFILE _("Scanner default color ICM-profile") +#define TEXT_SETUP_SCANNER_DEFAULT_GRAY_ICM_PROFILE _("Scanner default gray ICM-profile") +#define TEXT_SETUP_DISPLAY_ICM_PROFILE _("Display ICM-profile") +#define TEXT_SETUP_CUSTOM_PROOFING_ICM_PROFILE _("Custom proofing ICM-profile") +#define TEXT_SETUP_WORKING_COLOR_SPACE_ICM_PROFILE _("Working color space ICM-profile") +#define TEXT_SETUP_PRINTER_ICM_PROFILE _("Printer ICM-profile") +#define TEXT_NEW_MEDIA_NAME _("new media") + +#define NOTEBOOK_SAVING_OPTIONS _("Save") +#define NOTEBOOK_FILETYPE_OPTIONS _("Filetype") +#define NOTEBOOK_COPY_OPTIONS _("Copy") +#define NOTEBOOK_FAX_OPTIONS _("Fax") +#define NOTEBOOK_EMAIL_OPTIONS _("E-mail") +#define NOTEBOOK_OCR_OPTIONS _("OCR") +#define NOTEBOOK_DISPLAY_OPTIONS _("Display") +#define NOTEBOOK_ENHANCE_OPTIONS _("Enhancement") +#define NOTEBOOK_COLOR_MANAGEMENT_OPTIONS _("Color management") + +#define MENU_ITEM_SAVE _("Save") +#define MENU_ITEM_VIEWER _("Viewer") +#define MENU_ITEM_COPY _("Copy") +#define MENU_ITEM_MULTIPAGE _("Multipage") +#define MENU_ITEM_FAX _("Fax") +#define MENU_ITEM_EMAIL _("E-mail") + +#define MENU_ITEM_SHOW_TOOLTIPS _("Show tooltips") +#define MENU_ITEM_SHOW_PREVIEW _("Show preview") +#define MENU_ITEM_SHOW_HISTOGRAM _("Show histogram") +#define MENU_ITEM_SHOW_GAMMA _("Show gamma curve") +#define MENU_ITEM_SHOW_BATCH_SCAN _("Show batch scan") +#define MENU_ITEM_SHOW_STANDARDOPTIONS _("Show standard options") +#define MENU_ITEM_SHOW_ADVANCEDOPTIONS _("Show advanced options") + +#define MENU_ITEM_SETUP _("Setup") +#define MENU_ITEM_LENGTH_UNIT _("Length unit") +#define SUBMENU_ITEM_LENGTH_MILLIMETERS _("millimeters") +#define SUBMENU_ITEM_LENGTH_CENTIMETERS _("centimeters") +#define SUBMENU_ITEM_LENGTH_INCHES _("inches") +#define MENU_ITEM_UPDATE_POLICY _("Update policy") +#define SUBMENU_ITEM_POLICY_CONTINUOUS _("continuous") +#define SUBMENU_ITEM_POLICY_DISCONTINU _("discontinuous") +#define SUBMENU_ITEM_POLICY_DELAYED _("delayed") +#define MENU_ITEM_SHOW_RESOLUTIONLIST _("Show resolution list") +#define MENU_ITEM_PAGE_ROTATE _("Rotate postscript") +#define MENU_ITEM_ENABLE_COLOR_MANAGEMENT _("Enable color management") +#define MENU_ITEM_EDIT_MEDIUM_DEF _("Edit medium definition") +#define MENU_ITEM_SAVE_DEVICE_SETTINGS _("Save device settings") +#define MENU_ITEM_LOAD_DEVICE_SETTINGS _("Load device settings") +#define MENU_ITEM_CHANGE_WORKING_DIR _("Change directory") + +#define MENU_ITEM_XSANE_EULA _("Show EULA") +#define MENU_ITEM_XSANE_GPL _("Show license (GPL)") +#define MENU_ITEM_XSANE_DOC _("XSane doc") +#define MENU_ITEM_BACKEND_DOC _("Backend doc") +#define MENU_ITEM_AVAILABLE_BACKENDS _("Available backends") +#define MENU_ITEM_SCANTIPS _("Scantips") +#define MENU_ITEM_PROBLEMS _("Problems?") + + +#define MENU_ITEM_CMS_ENABLE_COLOR_MANAGEMENT _("Enable color management") +#define MENU_ITEM_CMS_BLACK_POINT_COMPENSATION _("Black point compensation") +#define MENU_ITEM_CMS_PROOFING _("Proofing") +#define SUBMENU_ITEM_CMS_PROOF_OFF _("no proofing (Display)") +#define SUBMENU_ITEM_CMS_PROOF_PRINTER _("Proof printer") +#define SUBMENU_ITEM_CMS_PROOF_CUSTOM _("Proof custom device") +#define MENU_ITEM_CMS_RENDERING_INTENT _("Rendering intent") +#define MENU_ITEM_CMS_PROOFING_INTENT _("Proofing rendering intent") +#define SUBMENU_ITEM_CMS_INTENT_PERCEPTUAL _("Perceptual") +#define SUBMENU_ITEM_CMS_INTENT_RELATIVE_COLORIMETRIC _("Relative colorimetric") +#define SUBMENU_ITEM_CMS_INTENT_ABSOLUTE_COLORIMETRIC _("Absolute colorimentric") +#define SUBMENU_ITEM_CMS_INTENT_SATURATION _("Saturation") +#define MENU_ITEM_CMS_GAMUT_CHECK _("Gamut check") +#define MENU_ITEM_CMS_GAMUT_ALARM_COLOR _("Gamut alarm color") +#define SUBMENU_ITEM_CMS_COLOR_BLACK _("Black") +#define SUBMENU_ITEM_CMS_COLOR_GRAY _("Gray") +#define SUBMENU_ITEM_CMS_COLOR_WHITE _("White") +#define SUBMENU_ITEM_CMS_COLOR_RED _("Red") +#define SUBMENU_ITEM_CMS_COLOR_GREEN _("Green") +#define SUBMENU_ITEM_CMS_COLOR_BLUE _("Blue") #define MENU_ITEM_COUNTER_LEN_INACTIVE _("inactive") #define MENU_ITEM_TIFF_COMP_NONE _("no compression") @@ -415,6 +458,10 @@ #define MENU_ITEM_AUTH_ASMTP_LOGIN _("ASMTP Login") #define MENU_ITEM_AUTH_ASMTP_CRAM_MD5 _("ASMTP CRAM-MD5") +#define MENU_ITEM_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE _("Embed scanner ICM profile") +#define MENU_ITEM_CMS_FUNCTION_CONVERT_TO_SRGB _("Convert to sRGB") +#define MENU_ITEM_FUNCTION_CONVERT_TO_WORKING_CS _("Convert to working color space") + #define PROGRESS_SCANNING _("Scanning") #define PROGRESS_RECEIVING_FRAME_DATA _("Receiving %s data") #define PROGRESS_PAGE _("page") @@ -430,6 +477,7 @@ #define PROGRESS_DESPECKLING_DATA _("Despeckling image") #define PROGRESS_BLURING_DATA _("Bluring image") #define PROGRESS_OCR _("OCR in progress") +#define PROGRESS_ICM_CONVERSION _("converting colors") #define DESC_SCAN_START _("Start scan <Ctrl-Enter>") #define DESC_SCAN_CANCEL _("Cancel scan <ESC>") @@ -445,15 +493,18 @@ #define DESC_BROWSE_FILENAME _("Browse for image filename") #define DESC_FILENAME _("Filename for scanned image") #define DESC_FILETYPE _("Type of image format, the suitable filename extension is automatically added to the filename") -#define DESC_FAXPROJECT _("Enter name of fax project") +#define DESC_FAXPROJECT _("Enter fax project directory name") #define DESC_FAXPAGENAME _("Enter new name for faxpage") #define DESC_FAXRECEIVER _("Enter receiver phone number or address") -#define DESC_EMAIL_PROJECT _("Enter name of e-mail project") +#define DESC_FAX_PROJECT_BROWSE _("Browse for fax project directory") +#define DESC_EMAIL_PROJECT _("Enter e-mail project directory name") #define DESC_EMAIL_IMAGENAME _("Enter new name for e-mail image") #define DESC_EMAIL_RECEIVER _("Enter e-mail address") +#define DESC_EMAIL_PROJECT_BROWSE _("Browse for email project directory") #define DESC_EMAIL_SUBJECT _("Enter subject of e-mail") #define DESC_EMAIL_FILETYPE _("Select filetype for image attachments") -#define DESC_MULTIPAGE_PROJECT _("Enter name of multipage project") +#define DESC_MULTIPAGE_PROJECT _("Enter multipage project directory name") +#define DESC_MULTIPAGE_PROJECT_BROWSE _("Browse for multipage project directory") #define DESC_MULTIPAGE_FILETYPE _("Select filetype for multipage file") #define DESC_PRESET_AREA_RENAME _("Enter new name for preset area") #define DESC_PRESET_AREA_ADD _("Enter name for new preset area") @@ -495,7 +546,7 @@ " brightness = 0\n" \ " contrast = 0") -#define DESC_ENH_AUTO _("Autoadjust gamma, brightness and contrast <Ctrl-e>") +#define DESC_ENH_AUTO _("Autoadjust gamma, brightness and contrast <Ctrl-a>") #define DESC_ENH_DEFAULT _("Set default enhancement values <Ctrl-0>:\n" \ "gamma = 1.0\n" \ "brightness = 0\n" \ @@ -525,7 +576,9 @@ #define DESC_PRINTER_GAMMA_RED _("Additional gamma value for red component for photocopy") #define DESC_PRINTER_GAMMA_GREEN _("Additional gamma value for green component for photocopy") #define DESC_PRINTER_GAMMA_BLUE _("Additional gamma value for blue component for photocopy") -#define DESC_PRINTER_PS_FLATDECODED _("Create zlib compressed postscript image for printer (flatdecode).\n" \ +#define DESC_PRINTER_EMBED_CSA _("Creates a postsciptfile that contains the ICM profile of the scanner") +#define DESC_PRINTER_EMBED_CRD _("Creates a postsciptfile that contains the ICM profile of the printer") +#define DESC_PRINTER_PS_FLATEDECODED _("Create zlib compressed postscript image for printer (flatedecode).\n" \ "The printer has to understand postscript level 3!") #define DESC_TMP_PATH _("Path to temp directory") #define DESC_BUTTON_TMP_PATH_BROWSE _("Browse for temporary directory") @@ -539,20 +592,20 @@ #define DESC_SAVE_DEVPREFS_AT_EXIT _("Save device dependant preferences in default file at exit of xsane") #define DESC_OVERWRITE_WARNING _("Warn before overwriting an existing file") #define DESC_SKIP_EXISTING _("If filename counter is automatically increased, used numbers are skipped") -#define DESC_SAVE_PS_FLATDECODED _("compress postscript image with zlib algorithm (flatdecode). " \ +#define DESC_SAVE_PS_FLATEDECODED _("compress postscript image with zlib algorithm (flatedecode). " \ "When you want to print such a file your printer has to understand postscript level 3") -#define DESC_SAVE_PDF_FLATDECODED _("compress PDF image with zlib algorithm (flatdecode).") +#define DESC_SAVE_PDF_FLATEDECODED _("compress PDF image with zlib algorithm (flatedecode).") #define DESC_SAVE_PNM16_AS_ASCII _("When a 16 bit image shall be saved in pnm format then use ascii format " \ "instead of binary format. The binary format is a new format that is not " \ "supported by all programs. The ascii format is supported by more programs " \ "but it produces really huge files!!!") -#define DESC_REDUCE_16BIT_TO_8BIT _("If scanner sends image with 16 bits/color save image with 8 bits/color") +#define DESC_REDUCE_16BIT_TO_8BIT _("If scanner sends image with 16 bits/channel save image with 8 bits/channel") #define DESC_PSFILE_WIDTH _("Width of paper for postscript files") #define DESC_PSFILE_HEIGHT _("Height of paper for postscript files") #define DESC_PSFILE_LEFTOFFSET _("Left offset from the edge of the paper to the usable area for postscript files") #define DESC_PSFILE_BOTTOMOFFSET _("Bottom offset from the edge of the paper to the usable area for postscript files") #define DESC_MAIN_WINDOW_FIXED _("Use fixed main window size or scrolled, resizable main window") -#define DESC_DISABLE_GIMP_PREVIEW_GAMMA _("Disable preview gamma when XSane runs as gimp plugin") +#define DESC_DISABLE_GIMP_PREVIEW_GAMMA _("Disable preview gamma when XSane runs as GIMP plugin") #define DESC_PREVIEW_COLORMAP _("Use an own colormap for preview if display depth is 8 bpp") #define DESC_SHOW_RANGE_MODE _("Select how a range is displayed") #define DESC_PREVIEW_OVERSAMPLING _("Value with that the calculated preview resolution is multiplied") @@ -575,6 +628,9 @@ #define DESC_PRESELECT_SCANAREA _("Select scanarea after preview scan has finished") #define DESC_AUTOCORRECT_COLORS _("Do color correction after preview scan has finished") +#define DESC_RENDERING_INTENT _("Select rendering intent for preview and saving") +#define DESC_CMS_BPC _("Apply black point compensation when color transformation is done") + #define DESC_FAX_COMMAND _("Enter command to be executed in fax mode") #define DESC_FAX_RECEIVER_OPT _("Enter option to specify receiver") #define DESC_FAX_POSTSCRIPT_OPT _("Enter option to specify postscript files following") @@ -586,7 +642,7 @@ #define DESC_FAX_HEIGHT _("Height of printable area") #define DESC_FAX_LEFTOFFSET _("Left offset from the edge of the paper to the printable area") #define DESC_FAX_BOTTOMOFFSET _("Bottom offset from the edge of the paper to the printable area") -#define DESC_FAX_PS_FLATDECODED _("Create zlib compressed postscript image for fax (flatdecode)") +#define DESC_FAX_PS_FLATEDECODED _("Create zlib compressed postscript image for fax (flatedecode)") #define DESC_SMTP_SERVER _("IP Address or Domain name of SMTP server") #define DESC_SMTP_PORT _("port to connect to SMTP server") #define DESC_EMAIL_FROM _("enter your e-mail address") @@ -606,7 +662,7 @@ #define DESC_PERMISSION_READ _("read") #define DESC_PERMISSION_WRITE _("write") -#define DESC_PERMISSION_EXECUTE _("execute") +#define DESC_PERMISSION_SEARCH _("search") #define DESC_ADD_BATCH _("Add selection for batch scan") #define DESC_PIPETTE_WHITE _("Pick white point") @@ -658,6 +714,21 @@ #define DESC_BATCH_DEL _("Delete selected area from batch list") #define DESC_AUTOMATIC _("Turns on automatic mode") +#define DESC_SCANNER_DEFAULT_COLOR_ICM_PROFILE _("Scanner default color ICM-profile") +#define DESC_BUTTON_SCANNER_DEFAULT_COLOR_ICM_PROFILE_BROWSE _("Browse for scanner default color ICM-profile") +#define DESC_SCANNER_DEFAULT_GRAY_ICM_PROFILE _("Scanner default gray ICM-profile") +#define DESC_BUTTON_SCANNER_DEFAULT_GRAY_ICM_PROFILE_BROWSE _("Browse for scanner default gray ICM-profile") +#define DESC_DISPLAY_ICM_PROFILE _("Display ICM-profile") +#define DESC_BUTTON_DISPLAY_ICM_PROFILE_BROWSE _("Browse for display ICM-profile") +#define DESC_PRINTER_ICM_PROFILE _("Printer ICM-profile") +#define DESC_BUTTON_PRINTER_ICM_PROFILE_BROWSE _("Browse for printer ICM-profile") +#define DESC_CUSTOM_PROOFING_ICM_PROFILE _("Custom proofing ICM-profile") +#define DESC_BUTTON_CUSTOM_PROOFING_ICM_PROFILE_BROWSE _("Browse for custom proofing ICM-profile") +#define DESC_WORKING_COLOR_SPACE_ICM_PROFILE _("Working color space ICM-profile") +#define DESC_BUTTON_WORKING_COLOR_SPACE_ICM_PROFILE_BROWSE _("Browse for working color space ICM-profile") + +#define DESC_CMS_FUNCTION _("Color management function") + #define ERR_HOME_DIR _("Failed to determine home directory:") #define ERR_CHANGE_WORKING_DIR _("Failed to change working directory to") #define ERR_FILENAME_TOO_LONG _("Filename too long") @@ -673,7 +744,6 @@ write permissions." ) #define ERR_DURING_READ _("Error during read:") #define ERR_DURING_SAVE _("Error during save:") #define ERR_BAD_DEPTH _("Can't handle depth") -#define ERR_GIMP_BAD_DEPTH _("GIMP can't handle depth %d bits/color") #define ERR_UNKNOWN_SAVING_FORMAT _("Unknown file format for saving") #define ERR_OPEN_FAILED _("Failed to open") #define ERR_CREATE_SECURE_FILE _("Could not create secure file (may be a link does exist):") @@ -741,8 +811,22 @@ YOU ARE ALONE!\ #define ERR_FILE_NOT_POSTSCRIPT _("File %s is not a postscript file") #define ERR_UNSUPPORTED_OUTPUT_FORMAT _("Unsupported %d-bit output format: %s") +#define ERR_CMS_CONVERSION _("Error during CMS conversion:") +#define ERR_CMS_OPEN_ICM_FILE _("Could not open") +#define CMS_SCANNER_ICM _("scanner ICM profile") +#define CMS_DISPLAY_ICM _("display ICM profile") +#define CMS_PROOF_ICM _("proofing ICM profile") +#define ERR_CMS_CREATE_TRANSFORM _("Could not create transform") + #define WARN_VIEWER_IMAGE_NOT_SAVED _("viewer image is not saved") +#define FILE_FILTER_ALL_FILES _("All files") +#define FILE_FILTER_IMAGES _("Images") +#define FILE_FILTER_XBL _("XSane batch list") +#define FILE_FILTER_ICM _("ICC/ICM Profiles") +#define FILE_FILTER_DRC _("XSane device preferences") +#define FILE_FILTER_RC _("XSane preferences") + #define TEXT_USAGE _("Usage:") #define TEXT_USAGE_OPTIONS _("[OPTION]... [DEVICE]") #define TEXT_HELP _(\ @@ -849,4 +933,5 @@ The format of [DEVICE] is backendname:devicefile (e.g. umax:/dev/scanner).\n\ #define TEXT_FAX_STATUS_QUEUEING_FAX N_("Queueing Fax") #define TEXT_FAX_STATUS_FAX_QUEUED N_("Fax is queued") + #endif diff --git a/src/xsane-viewer.c b/src/xsane-viewer.c index d1d8e5e..ef47529 100644 --- a/src/xsane-viewer.c +++ b/src/xsane-viewer.c @@ -3,7 +3,7 @@ xsane-viewer.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -32,8 +32,7 @@ #include "xsane-save.h" #include <gdk/gdkkeysyms.h> #include <sys/wait.h> - - + #ifndef PATH_MAX # define PATH_MAX 1024 #endif @@ -81,35 +80,37 @@ static void xsane_viewer_set_sensitivity(Viewer *v, int sensitivity) switch (v->allow_modification) { case VIEWER_NO_MODIFICATION: - gtk_widget_set_sensitive(GTK_WIDGET(v->save_menu_item), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->ocr_menu_item), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->clone_menu_item), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu), FALSE); - - gtk_widget_set_sensitive(GTK_WIDGET(v->save), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->ocr), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->clone), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->edit_button_box), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->filters_button_box), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_button_box), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->save_menu_item), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->ocr_menu_item), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->clone_menu_item), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu), v->enable_color_management); + + gtk_widget_set_sensitive(GTK_WIDGET(v->save), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->ocr), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->clone), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->edit_button_box), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->filters_button_box), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_button_box), FALSE); break; case VIEWER_NO_NAME_AND_SIZE_MODIFICATION: - gtk_widget_set_sensitive(GTK_WIDGET(v->save_menu_item), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->ocr_menu_item), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->clone_menu_item), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu), FALSE); - - gtk_widget_set_sensitive(GTK_WIDGET(v->save), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->ocr), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->clone), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->edit_button_box), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->filters_button_box), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_button_box), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->save_menu_item), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->ocr_menu_item), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->clone_menu_item), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu), v->enable_color_management); + + gtk_widget_set_sensitive(GTK_WIDGET(v->save), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->ocr), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->clone), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->edit_button_box), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->filters_button_box), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_button_box), FALSE); break; case VIEWER_NO_NAME_MODIFICATION: @@ -121,26 +122,28 @@ static void xsane_viewer_set_sensitivity(Viewer *v, int sensitivity) case VIEWER_FULL_MODIFICATION: default: - gtk_widget_set_sensitive(GTK_WIDGET(v->save_menu_item), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu), TRUE); - - gtk_widget_set_sensitive(GTK_WIDGET(v->save), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->edit_button_box), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->filters_button_box), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_button_box), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->save_menu_item), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu), v->enable_color_management); + + gtk_widget_set_sensitive(GTK_WIDGET(v->save), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->edit_button_box), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->filters_button_box), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_button_box), TRUE); break; } } else { v->block_actions = TRUE; - gtk_widget_set_sensitive(GTK_WIDGET(v->file_menu), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->file_menu), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu),FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE); } } @@ -255,6 +258,7 @@ static void xsane_viewer_save_callback(GtkWidget *window, gpointer data) char windowname[TEXTBUFSIZE]; int output_format; int abort = 0; + int show_extra_widgets; char buf[TEXTBUFSIZE]; if (v->block_actions) /* actions blocked: return */ @@ -280,9 +284,15 @@ static void xsane_viewer_save_callback(GtkWidget *window, gpointer data) if (v->allow_modification == VIEWER_FULL_MODIFICATION) /* it is allowed to rename the image */ { snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_VIEWER_OUTPUT_FILENAME, xsane.device_text); + + show_extra_widgets = XSANE_GET_FILENAME_SHOW_FILETYPE; + if (v->cms_enable) + { + show_extra_widgets |= XSANE_GET_FILENAME_SHOW_CMS_FUNCTION; + } umask((mode_t) preferences.directory_umask); /* define new file permissions */ - abort = xsane_back_gtk_get_filename(windowname, outputfilename, sizeof(outputfilename), outputfilename, &v->selection_filetype, TRUE, TRUE, FALSE, TRUE); + abort = xsane_back_gtk_get_filename(windowname, outputfilename, sizeof(outputfilename), outputfilename, &v->selection_filetype, &v->cms_function, XSANE_FILE_CHOOSER_ACTION_SAVE, show_extra_widgets, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_IMAGES, XSANE_FILE_FILTER_IMAGES); umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ if (abort) @@ -348,7 +358,7 @@ static void xsane_viewer_save_callback(GtkWidget *window, gpointer data) } else { - xsane_save_image_as(v->output_filename, inputfilename, output_format, v->progress_bar, &v->cancel_save); + xsane_save_image_as(v->output_filename, inputfilename, output_format, v->cms_enable, v->cms_function, v->cms_intent, v->cms_bpc, v->progress_bar, &v->cancel_save); } free(inputfilename); @@ -411,7 +421,7 @@ static void xsane_viewer_ocr_callback(GtkWidget *window, gpointer data) snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_OCR_OUTPUT_FILENAME, xsane.device_text); umask((mode_t) preferences.directory_umask); /* define new file permissions */ - abort = xsane_back_gtk_get_filename(windowname, outputfilename, sizeof(outputfilename), outputfilename, NULL, TRUE, TRUE, FALSE, FALSE); + abort = xsane_back_gtk_get_filename(windowname, outputfilename, sizeof(outputfilename), outputfilename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SAVE, XSANE_GET_FILENAME_SHOW_FILETYPE, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_IMAGES, XSANE_FILE_FILTER_IMAGES); umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ if (abort) @@ -458,11 +468,11 @@ static void xsane_viewer_clone_callback(GtkWidget *window, gpointer data) { char buf[TEXTBUFSIZE]; snprintf(buf, sizeof(buf), "%s%s", FILENAME_PREFIX_CLONE_OF, v->last_saved_filename); - xsane_viewer_new(outfilename, v->selection_filetype, v->allow_reduction_to_lineart, buf, v->allow_modification, IMAGE_NOT_SAVED); + xsane_viewer_new(outfilename, v->selection_filetype, v->allow_reduction_to_lineart, buf, v->allow_modification, v->image_saved); } else { - xsane_viewer_new(outfilename, v->selection_filetype, v->allow_reduction_to_lineart, NULL, v->allow_modification, IMAGE_NOT_SAVED); + xsane_viewer_new(outfilename, v->selection_filetype, v->allow_reduction_to_lineart, NULL, v->allow_modification, v->image_saved); } } @@ -569,7 +579,7 @@ static void xsane_viewer_scale_callback(GtkWidget *window, gpointer data) GtkWidget *frame; GtkWidget *hbox, *vbox; GtkWidget *button; - GtkObject *scale_widget, *scalex_widget, *scaley_widget; + GtkWidget *scale_widget, *scalex_widget, *scaley_widget; GtkAdjustment *adjustment_size_x; GtkAdjustment *adjustment_size_y; GtkWidget *spinbutton; @@ -1071,7 +1081,7 @@ static void xsane_viewer_scale_image(GtkWidget *window, gpointer data) xsane_read_pnm_header(infile, &image_info); - DBG(DBG_info, "scaling image %s with geometry: %d x %d x %d, %d colors\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors); + DBG(DBG_info, "scaling image %s with geometry: %d x %d x %d, %d channels\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels); xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP); @@ -1153,7 +1163,7 @@ static void xsane_viewer_despeckle_image(GtkWidget *window, gpointer data) xsane_read_pnm_header(infile, &image_info); - DBG(DBG_info, "despeckling image %s with geometry: %d x %d x %d, %d colors\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors); + DBG(DBG_info, "despeckling image %s with geometry: %d x %d x %d, %d channels\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels); xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP); @@ -1230,7 +1240,7 @@ static void xsane_viewer_blur_image(GtkWidget *window, gpointer data) xsane_read_pnm_header(infile, &image_info); - DBG(DBG_info, "bluring image %s with geometry: %d x %d x %d, %d colors\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors); + DBG(DBG_info, "bluring image %s with geometry: %d x %d x %d, %d channels\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels); xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP); @@ -1312,7 +1322,7 @@ static void xsane_viewer_rotate(Viewer *v, int rotation) xsane_read_pnm_header(infile, &image_info); - DBG(DBG_info, "rotating image %s with geometry: %d x %d x %d, %d colors\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors); + DBG(DBG_info, "rotating image %s with geometry: %d x %d x %d, %d channels\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels); xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP); @@ -1654,6 +1664,915 @@ static GtkWidget *xsane_viewer_geometry_build_menu(Viewer *v) /* ---------------------------------------------------------------------------------------------------------------------- */ +#ifdef HAVE_LIBLCMS +#define INTENT_PERCEPTUAL 0 +#define INTENT_RELATIVE_COLORIMETRIC 1 +#define INTENT_SATURATION 2 +#define INTENT_ABSOLUTE_COLORIMETRIC 3 + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_viewer_set_cms_enable_callback(GtkWidget *widget, gpointer data) +{ + Viewer *v = (Viewer *) data; + + v->cms_enable = (GTK_CHECK_MENU_ITEM(widget)->active != 0); + DBG(DBG_proc, "xsane_viewer_set_cms_enable_callback (%d)\n", v->cms_enable); + + xsane_viewer_read_image(v); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_viewer_set_cms_black_point_compensation_callback(GtkWidget *widget, gpointer data) +{ + Viewer *v = (Viewer *) data; + + v->cms_bpc = (GTK_CHECK_MENU_ITEM(widget)->active != 0); + DBG(DBG_proc, "xsane_viewer_set_cms_black_point_compensation_callback (%d)\n", v->cms_bpc); + + xsane_viewer_read_image(v); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_viewer_set_cms_gamut_check_callback(GtkWidget *widget, gpointer data) +{ + Viewer *v = (Viewer *) data; + + v->cms_gamut_check = (GTK_CHECK_MENU_ITEM(widget)->active != 0); + DBG(DBG_proc, "xsane_viewer_set_cms_gamut_check_callback (%d)\n", v->cms_gamut_check); + + xsane_viewer_read_image(v); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_viewer_set_cms_proofing_callback(GtkWidget *widget, gpointer data) +{ + Viewer *v = (Viewer *) data; + int val; + + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v); + + val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection"); + + DBG(DBG_proc, "xsane_viewer_set_cms_proofing_callback (%d)\n", val); + + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_proofing_widget[v->cms_proofing]), FALSE); + v->cms_proofing = val; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_proofing_widget[v->cms_proofing]), TRUE); + + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v); + + xsane_viewer_read_image(v); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_viewer_set_cms_intent_callback(GtkWidget *widget, gpointer data) +{ + Viewer *v = (Viewer *) data; + int val; + + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_intent_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_intent_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_intent_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_intent_widget[3]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + + val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection"); + + DBG(DBG_proc, "xsane_viewer_set_cms_intent_callback (%d)\n", val); + + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_intent_widget[v->cms_intent]), FALSE); + v->cms_intent = val; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_intent_widget[v->cms_intent]), TRUE); + + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_intent_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_intent_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_intent_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_intent_widget[3]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + + xsane_viewer_read_image(v); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_viewer_set_cms_proofing_intent_callback(GtkWidget *widget, gpointer data) +{ + Viewer *v = (Viewer *) data; + int val; + + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_intent_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_intent_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v); + + val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection"); + + DBG(DBG_proc, "xsane_viewer_set_cms_proofing_intent_callback (%d)\n", val); + + /* we have cms_proofing_intent = 1 and 3 and widget[0] and widget[1] => widget[(cms_proofing_intent-1)/2] */ + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_proofing_intent_widget[(v->cms_proofing_intent-1)/2]), FALSE); + v->cms_proofing_intent = val; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_proofing_intent_widget[(v->cms_proofing_intent-1)/2]), TRUE); + + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_intent_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_intent_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v); + + xsane_viewer_read_image(v); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_viewer_set_cms_gamut_alarm_color_callback(GtkWidget *widget, gpointer data) +{ + Viewer *v = (Viewer *) data; + int val; + + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[3]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[4]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[5]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + + val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection"); + + DBG(DBG_proc, "xsane_viewer_set_cms_gamut_alarm_color_callback (%d)\n", val); + + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_gamut_alarm_color_widget[v->cms_gamut_alarm_color]), FALSE); + v->cms_gamut_alarm_color = val; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_gamut_alarm_color_widget[v->cms_gamut_alarm_color]), TRUE); + + switch(v->cms_gamut_alarm_color) + { + default: + case 0: /* black */ + cmsSetAlarmCodes(0, 0, 0); + break; + + case 1: /* gray */ + cmsSetAlarmCodes(128, 128, 128); + break; + + case 2: /* white */ + cmsSetAlarmCodes(255, 255, 255); + break; + + case 3: /* red */ + cmsSetAlarmCodes(255, 0, 0); + break; + + case 4: /* green */ + cmsSetAlarmCodes(0, 255, 0); + break; + + case 5: /* blue */ + cmsSetAlarmCodes(0, 0, 255); + break; + } + + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[3]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[4]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[5]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + + if (v->cms_gamut_check) + { + xsane_viewer_read_image(v); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static GtkWidget *xsane_viewer_color_management_build_menu(Viewer *v) +{ + GtkWidget *menu, *item, *submenu, *subitem; + + DBG(DBG_proc, "xsane_viewer_color_management_build_menu\n"); + + menu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(menu), xsane.accelerator_group); + + /* cms enable */ + item = gtk_check_menu_item_new_with_label(MENU_ITEM_CMS_ENABLE_COLOR_MANAGEMENT); + gtk_menu_append(GTK_MENU(menu), item); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), v->cms_enable); + g_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_enable_callback, v); + gtk_widget_show(item); + + /* black point compensation */ + item = gtk_check_menu_item_new_with_label(MENU_ITEM_CMS_BLACK_POINT_COMPENSATION); + gtk_menu_append(GTK_MENU(menu), item); + if (v->cms_bpc) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE); + } + g_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_black_point_compensation_callback, v); + gtk_widget_show(item); + + + /* Output Device submenu */ + item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_PROOFING); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + submenu = gtk_menu_new(); + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_PROOF_OFF); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_proofing == 0) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 0); + gtk_widget_show(subitem); + v->cms_proofing_widget[0] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_PROOF_PRINTER); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_proofing == 1) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 1); + gtk_widget_show(subitem); + v->cms_proofing_widget[1] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_PROOF_CUSTOM); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_proofing == 2) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 2); + gtk_widget_show(subitem); + v->cms_proofing_widget[2] = subitem; + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); + + + /* Intent submenu */ + item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_RENDERING_INTENT); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + submenu = gtk_menu_new(); + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_PERCEPTUAL); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_intent == INTENT_PERCEPTUAL) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_PERCEPTUAL); + gtk_widget_show(subitem); + v->cms_intent_widget[INTENT_PERCEPTUAL] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_RELATIVE_COLORIMETRIC); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_intent == INTENT_RELATIVE_COLORIMETRIC) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_RELATIVE_COLORIMETRIC); + gtk_widget_show(subitem); + v->cms_intent_widget[INTENT_RELATIVE_COLORIMETRIC] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_ABSOLUTE_COLORIMETRIC); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_intent == INTENT_ABSOLUTE_COLORIMETRIC) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_ABSOLUTE_COLORIMETRIC); + gtk_widget_show(subitem); + v->cms_intent_widget[INTENT_ABSOLUTE_COLORIMETRIC] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_SATURATION); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_intent == INTENT_SATURATION) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_SATURATION); + gtk_widget_show(subitem); + v->cms_intent_widget[INTENT_SATURATION] = subitem; + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); + + + /* proofing_intent submenu */ + item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_PROOFING_INTENT); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + submenu = gtk_menu_new(); + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_RELATIVE_COLORIMETRIC); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_proofing_intent == INTENT_RELATIVE_COLORIMETRIC) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_RELATIVE_COLORIMETRIC); + gtk_widget_show(subitem); + v->cms_proofing_intent_widget[0] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_ABSOLUTE_COLORIMETRIC); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_proofing_intent == INTENT_ABSOLUTE_COLORIMETRIC) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_ABSOLUTE_COLORIMETRIC); + gtk_widget_show(subitem); + v->cms_proofing_intent_widget[1] = subitem; + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); + + + /* cms gamut check */ + item = gtk_check_menu_item_new_with_label(MENU_ITEM_CMS_GAMUT_CHECK); + gtk_menu_append(GTK_MENU(menu), item); + g_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_check_callback, v); + gtk_widget_show(item); + + + /* gamut alarm color */ + item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_GAMUT_ALARM_COLOR); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + submenu = gtk_menu_new(); + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_BLACK); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_gamut_alarm_color == 0) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 0); + gtk_widget_show(subitem); + v->cms_gamut_alarm_color_widget[0] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_GRAY); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_gamut_alarm_color == 1) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 1); + gtk_widget_show(subitem); + v->cms_gamut_alarm_color_widget[1] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_WHITE); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_gamut_alarm_color == 2) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 2); + gtk_widget_show(subitem); + v->cms_gamut_alarm_color_widget[2] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_RED); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_gamut_alarm_color == 3) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 3); + gtk_widget_show(subitem); + v->cms_gamut_alarm_color_widget[3] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_GREEN); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_gamut_alarm_color == 4) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 4); + gtk_widget_show(subitem); + v->cms_gamut_alarm_color_widget[4] = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_BLUE); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (v->cms_gamut_alarm_color == 5) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v); + gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 5); + gtk_widget_show(subitem); + v->cms_gamut_alarm_color_widget[5] = subitem; + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); + + return menu; +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + + +static int xsane_viewer_read_image_header(Viewer *v) +{ + int pos0; + FILE *infile; + Image_info image_info; + + /* open imagefile */ + + infile = fopen(v->filename, "rb"); + if (!infile) + { + DBG(DBG_error, "could not load file %s\n", v->filename); + return -1; + } + + xsane_read_pnm_header(infile, &image_info); + + pos0 = ftell(infile); + + if (!image_info.channels) /* == 0 (grayscale) ? */ + { + image_info.channels = 1; /* we have one color component */ + } + + DBG(DBG_info, "reading image header %s with geometry: %d x %d x %d, %d channels\n", v->filename, + image_info.image_width, image_info.image_height, image_info.depth, image_info.channels); + + /* init color management */ + v->enable_color_management = image_info.enable_color_management; + if (!image_info.enable_color_management) + { + v->cms_enable = FALSE; + } + + v->cms_function = image_info.cms_function; + v->cms_intent = image_info.cms_intent; + v->cms_bpc = image_info.cms_bpc; + + if ((v->enable_color_management) && (image_info.reduce_to_lineart)) + { + v->enable_color_management = FALSE; + v->cms_enable = FALSE; + } + + fclose(infile); + + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + + +static int xsane_viewer_read_image(Viewer *v) +{ + unsigned char *cms_row, *row, *src_row; + int x, y; + int last_y; + int nread; + int pos0; + FILE *infile; + Image_info image_info; + char buf[TEXTBUFSIZE]; + float size; + char *size_unit; + int width, height; + +#ifdef HAVE_LIBLCMS + cmsHPROFILE hInProfile = NULL; + cmsHPROFILE hOutProfile = NULL; + cmsHPROFILE hProofProfile = NULL; + cmsHTRANSFORM hTransform = NULL; + int proof = 0; + char *cms_proof_icm_profile = NULL; + DWORD cms_input_format; + DWORD cms_output_format; + DWORD cms_flags = 0; +#endif + + /* open imagefile */ + + infile = fopen(v->filename, "rb"); + if (!infile) + { + DBG(DBG_error, "could not load file %s\n", v->filename); + return -1; + } + + xsane_read_pnm_header(infile, &image_info); + + pos0 = ftell(infile); + + if (!image_info.channels) /* == 0 (grayscale) ? */ + { + image_info.channels = 1; /* we have one color component */ + } + + DBG(DBG_info, "reading image %s with geometry: %d x %d x %d, %d channels\n", v->filename, + image_info.image_width, image_info.image_height, image_info.depth, image_info.channels); + +#ifdef HAVE_LIBLCMS + /* init color management */ + + if ((v->enable_color_management) && (v->cms_enable)) + { + cmsErrorAction(LCMS_ERROR_SHOW); + + if (v->cms_bpc) + { + cms_flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + + if (image_info.channels == 1) /* == 1 (grayscale) */ + { + if (image_info.depth == 8) + { + cms_input_format = TYPE_GRAY_8; + cms_output_format = TYPE_GRAY_8; + } + else + { + cms_input_format = TYPE_GRAY_16; + cms_output_format = TYPE_GRAY_8; + } + } + else /* color */ + { + if (image_info.depth == 8) + { + cms_input_format = TYPE_RGB_8; + cms_output_format = TYPE_RGB_8; + } + else + { + cms_input_format = TYPE_RGB_16; + cms_output_format = TYPE_RGB_8; + } + } + + switch (v->cms_proofing) + { + default: + case 0: /* display */ + proof = 0; + break; + + case 1: /* proof printer */ + cms_proof_icm_profile = preferences.printer[preferences.printernr]->icm_profile; + proof = 1; + break; + + case 2: /* proof custom proofing */ + cms_proof_icm_profile = preferences.custom_proofing_icm_profile; + proof = 1; + break; + } + + hInProfile = cmsOpenProfileFromFile(image_info.icm_profile, "r"); + if (!hInProfile) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_SCANNER_ICM, image_info.icm_profile); + xsane_back_gtk_error(buf, TRUE); + return -1; + } + + hOutProfile = cmsOpenProfileFromFile(preferences.display_icm_profile, "r"); + if (!hOutProfile) + { + char buf[TEXTBUFSIZE]; + + cmsCloseProfile(hInProfile); + + snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_DISPLAY_ICM, preferences.display_icm_profile); + xsane_back_gtk_error(buf, TRUE); + return -1; + } + + + if (proof == 0) + { + hTransform = cmsCreateTransform(hInProfile, cms_input_format, + hOutProfile, cms_output_format, + v->cms_intent, cms_flags); + } + else /* proof */ + { + cms_flags |= cmsFLAGS_SOFTPROOFING; + + if (v->cms_gamut_check) + { + cms_flags |= cmsFLAGS_GAMUTCHECK; + } + + hProofProfile = cmsOpenProfileFromFile(cms_proof_icm_profile, "r"); + if (!hProofProfile) + { + char buf[TEXTBUFSIZE]; + + cmsCloseProfile(hInProfile); + cmsCloseProfile(hOutProfile); + + snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_PROOF_ICM, cms_proof_icm_profile); + xsane_back_gtk_error(buf, TRUE); + return -1; + } + + hTransform = cmsCreateProofingTransform(hInProfile, cms_input_format, + hOutProfile, cms_output_format, + hProofProfile, + v->cms_intent, v->cms_proofing_intent, cms_flags); + } + + cmsCloseProfile(hInProfile); + cmsCloseProfile(hOutProfile); + if (proof) + { + cmsCloseProfile(hProofProfile); + } + + if (!hTransform) + { + char buf[TEXTBUFSIZE]; + + snprintf(buf, sizeof(buf), "%s\n%s\n", ERR_CMS_CONVERSION, ERR_CMS_CREATE_TRANSFORM); + xsane_back_gtk_error(buf, TRUE); + return -1; + } + } +#endif + + /* open infile */ + + if (v->window) /* we already have an existing viewer preview window? */ + { + gtk_widget_destroy(v->window); + } + + /* the preview area */ + if (image_info.channels == 3) /* RGB */ + { + v->window = gtk_preview_new(GTK_PREVIEW_COLOR); + } + else /* grayscale */ + { + v->window = gtk_preview_new(GTK_PREVIEW_GRAYSCALE); + } + + gtk_preview_size(GTK_PREVIEW(v->window), image_info.image_width * v->zoom, image_info.image_height * v->zoom); + gtk_container_add(GTK_CONTAINER(v->viewport), v->window); + gtk_widget_show(v->window); + + + + /* get memory for one row of the image */ + src_row = malloc(image_info.image_width * image_info.channels * image_info.depth / 8); + + if ((v->enable_color_management) && (v->cms_enable)) + { + row = malloc(((int) image_info.image_width * v->zoom) * image_info.channels * image_info.depth / 8); + } + else + { + row = malloc(((int) image_info.image_width * v->zoom) * image_info.channels); + } + +#ifdef HAVE_LIBLCMS + if ((v->enable_color_management) && (v->cms_enable)) + { + cms_row = malloc(((int) image_info.image_width * v->zoom) * image_info.channels); + } + else +#endif + { + cms_row = row; + } + + if (!row || !src_row || !cms_row) + { + if (src_row) + { + free(src_row); + } + + if (row) + { + free(row); + } + +#ifdef HAVE_LIBLCMS + if ((cms_row) && (v->enable_color_management) && (v->cms_enable)) + { + free(cms_row); + } +#endif + + fclose(infile); + DBG(DBG_error, "could not allocate memory\n"); + return -1; + } + + + last_y = -99999; + + /* read the image from file */ + for (y = 0; y < (int) (image_info.image_height * v->zoom); y++) + { + if ((int) (last_y / v->zoom) != (int) (y / v->zoom)) + { + last_y = y; + + if (image_info.depth == 8) /* 8 bits/pixel */ + { + fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels, SEEK_SET); + nread = fread(src_row, image_info.channels, image_info.image_width, infile); + + if (image_info.channels > 1) + { + for (x=0; x < (int) (image_info.image_width * v->zoom); x++) + { + int xoff = ((int) (x / v->zoom)) * image_info.channels; + + row[3*x+0] = src_row[xoff + 0]; + row[3*x+1] = src_row[xoff + 1]; + row[3*x+2] = src_row[xoff + 2]; + } + } + else + { + for (x=0; x < (int) (image_info.image_width * v->zoom); x++) + { + row[x] = src_row[((int) (x / v->zoom))]; + } + } + } + else if ((!v->enable_color_management) || (!v->cms_enable)) /* 16 bits/pixel => reduce to 8 bits/pixel */ + { + guint16 *src_row16 = (guint16 *) src_row; + + fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels * 2, SEEK_SET); + nread = fread(src_row, 2 * image_info.channels, image_info.image_width, infile); + + if (image_info.channels > 1) + { + for (x=0; x < (int) (image_info.image_width * v->zoom); x++) + { + int xoff = ((int) (x / v->zoom)) * image_info.channels; + + row[3*x+0] = (unsigned char) (src_row16[xoff + 0] / 256); + row[3*x+1] = (unsigned char) (src_row16[xoff + 1] / 256); + row[3*x+2] = (unsigned char) (src_row16[xoff + 2] / 256); + } + } + else + { + for (x=0; x < (int) (image_info.image_width * v->zoom); x++) + { + row[x] = (unsigned char) (src_row16[(int) (x / v->zoom)] / 256); + } + } + } + else /* 16 bits/pixel with color management enabled, cms does 16->8 conversion */ + { + guint16 *src_row16 = (guint16 *) src_row; + guint16 *dst_row16 = (guint16 *) row; + + fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels * 2, SEEK_SET); + nread = fread(src_row, 2 * image_info.channels, image_info.image_width, infile); + + if (image_info.channels > 1) + { + for (x=0; x < (int) (image_info.image_width * v->zoom); x++) + { + int xoff = ((int) (x / v->zoom)) * image_info.channels; + + dst_row16[3*x+0] = src_row16[xoff + 0]; + dst_row16[3*x+1] = src_row16[xoff + 1]; + dst_row16[3*x+2] = src_row16[xoff + 2]; + } + } + else + { + for (x=0; x < (int) (image_info.image_width * v->zoom); x++) + { + dst_row16[x] = src_row16[(int) (x / v->zoom)]; + } + } + } + } + +#ifdef HAVE_LIBLCMS + if ((v->enable_color_management) && (v->cms_enable)) + { + cmsDoTransform(hTransform, row, cms_row, image_info.image_width * v->zoom); + } +#endif + gtk_preview_draw_row(GTK_PREVIEW(v->window), cms_row, 0, y, image_info.image_width * v->zoom); + } + + gtk_preview_put(GTK_PREVIEW(v->window), v->window->window, v->window->style->black_gc, 0, 0, 0, 0, + image_info.image_width * v->zoom, image_info.image_height * v->zoom); + + size = (float) image_info.image_width * image_info.image_height * image_info.channels; + if (image_info.depth == 16) + { + size *= 2.0; + } + + if (image_info.reduce_to_lineart) + { + size /= 8.0; + } + + size_unit = "B"; + + if (size >= 1024 * 1024) + { + size /= (1024.0 * 1024.0); + size_unit = "MB"; + } + else if (size >= 1024) + { + size /= 1024.0; + size_unit = "KB"; + } + + if (image_info.reduce_to_lineart) + { + snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, 1, image_info.channels, + image_info.resolution_x, image_info.resolution_y, size, size_unit); + } + else + { + snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels, + image_info.resolution_x, image_info.resolution_y, size, size_unit); + } + gtk_label_set(GTK_LABEL(v->image_info_label), buf); + + width = image_info.image_width * v->zoom + 26; + height = image_info.image_height * v->zoom + 136; + + if (width > gdk_screen_width()) + { + width = gdk_screen_width(); + } + + if (height > gdk_screen_height()) + { + height = gdk_screen_height(); + } + +#ifdef HAVE_GTK2 + if (GTK_WIDGET_REALIZED(v->top)) + { + gtk_window_resize(GTK_WINDOW(v->top), width, height); + } + else +#endif + { + gtk_window_set_default_size(GTK_WINDOW(v->top), width, height); + } + + free(row); + free(src_row); + fclose(infile); + +#ifdef HAVE_LIBLCMS + if ((v->enable_color_management) && (v->cms_enable)) + { + cmsDeleteTransform(hTransform); + } +#endif + + return 0; +} + +#if 0 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + static int xsane_viewer_read_image(Viewer *v) { unsigned char *row, *src_row; @@ -1679,13 +2598,13 @@ static int xsane_viewer_read_image(Viewer *v) pos0 = ftell(infile); - if (!image_info.colors) /* == 0 (grayscale) ? */ + if (!image_info.channels) /* == 0 (grayscale) ? */ { - image_info.colors = 1; /* we have one color component */ + image_info.channels = 1; /* we have one color component */ } - DBG(DBG_info, "reading image %s with geometry: %d x %d x %d, %d colors\n", v->filename, - image_info.image_width, image_info.image_height, image_info.depth, image_info.colors); + DBG(DBG_info, "reading image %s with geometry: %d x %d x %d, %d channels\n", v->filename, + image_info.image_width, image_info.image_height, image_info.depth, image_info.channels); /* open infile */ if (v->window) /* we already have an existing viewer preview window? */ @@ -1694,7 +2613,7 @@ static int xsane_viewer_read_image(Viewer *v) } /* the preview area */ - if (image_info.colors == 3) /* RGB */ + if (image_info.channels == 3) /* RGB */ { v->window = gtk_preview_new(GTK_PREVIEW_COLOR); } @@ -1710,8 +2629,8 @@ static int xsane_viewer_read_image(Viewer *v) /* get memory for one row of the image */ - src_row = malloc(image_info.image_width * image_info.colors * image_info.depth / 8); - row = malloc(((int) image_info.image_width * v->zoom) * image_info.colors); + src_row = malloc(image_info.image_width * image_info.channels * image_info.depth / 8); + row = malloc(((int) image_info.image_width * v->zoom) * image_info.channels); if (!row || !src_row) { @@ -1742,14 +2661,14 @@ static int xsane_viewer_read_image(Viewer *v) if (image_info.depth == 8) /* 8 bits/pixel */ { - fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.colors, SEEK_SET); - nread = fread(src_row, image_info.colors, image_info.image_width, infile); + fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels, SEEK_SET); + nread = fread(src_row, image_info.channels, image_info.image_width, infile); - if (image_info.colors > 1) + if (image_info.channels > 1) { for (x=0; x < (int) (image_info.image_width * v->zoom); x++) { - int xoff = ((int) (x / v->zoom)) * image_info.colors; + int xoff = ((int) (x / v->zoom)) * image_info.channels; row[3*x+0] = src_row[xoff + 0]; row[3*x+1] = src_row[xoff + 1]; @@ -1768,14 +2687,14 @@ static int xsane_viewer_read_image(Viewer *v) { guint16 *src_row16 = (guint16 *) src_row; - fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.colors * 2, SEEK_SET); - nread = fread(src_row, 2 * image_info.colors, image_info.image_width, infile); + fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels * 2, SEEK_SET); + nread = fread(src_row, 2 * image_info.channels, image_info.image_width, infile); - if (image_info.colors > 1) + if (image_info.channels > 1) { for (x=0; x < (int) (image_info.image_width * v->zoom); x++) { - int xoff = ((int) (x / v->zoom)) * image_info.colors; + int xoff = ((int) (x / v->zoom)) * image_info.channels; row[3*x+0] = (unsigned char) (src_row16[xoff + 0] / 256); row[3*x+1] = (unsigned char) (src_row16[xoff + 1] / 256); @@ -1798,7 +2717,7 @@ static int xsane_viewer_read_image(Viewer *v) gtk_preview_put(GTK_PREVIEW(v->window), v->window->window, v->window->style->black_gc, 0, 0, 0, 0, image_info.image_width * v->zoom, image_info.image_height * v->zoom); - size = (float) image_info.image_width * image_info.image_height * image_info.colors; + size = (float) image_info.image_width * image_info.image_height * image_info.channels; if (image_info.depth == 16) { size *= 2.0; @@ -1824,18 +2743,18 @@ static int xsane_viewer_read_image(Viewer *v) if (image_info.reduce_to_lineart) { - snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, 1, image_info.colors, + snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, 1, image_info.channels, image_info.resolution_x, image_info.resolution_y, size, size_unit); } else { - snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors, + snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels, image_info.resolution_x, image_info.resolution_y, size, size_unit); } gtk_label_set(GTK_LABEL(v->image_info_label), buf); - width = image_info.image_width + 26; - height = image_info.image_height + 136; + width = image_info.image_width * v->zoom + 26; + height = image_info.image_height * v->zoom + 136; if (width > gdk_screen_width()) { @@ -1864,6 +2783,7 @@ static int xsane_viewer_read_image(Viewer *v) return 0; } +#endif /* ---------------------------------------------------------------------------------------------------------------------- */ @@ -1897,6 +2817,17 @@ Viewer *xsane_viewer_new(char *filename, char *selection_filetype, int allow_red v->keep_viewer_pnm_format = FALSE; v->allow_modification = allow_modification; v->next_viewer = xsane.viewer_list; +#ifdef HAVE_LIBLCMS + v->enable_color_management = FALSE; + v->cms_enable = TRUE; + v->cms_function = XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE; + v->cms_intent = INTENT_PERCEPTUAL; + v->cms_proofing = 0; /* display */ + v->cms_proofing_intent = INTENT_ABSOLUTE_COLORIMETRIC; + v->cms_gamut_check = 0; + v->cms_gamut_alarm_color = 3; /* red */ + cmsSetAlarmCodes(255, 0, 0); +#endif if (selection_filetype) { v->selection_filetype = strdup(selection_filetype); @@ -1933,6 +2864,8 @@ Viewer *xsane_viewer_new(char *filename, char *selection_filetype, int allow_red snprintf(buf, sizeof(buf), "%s %s", WINDOW_VIEWER, xsane.device_text); } + xsane_viewer_read_image_header(v); // xxx oli + v->top = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(v->top), buf); xsane_set_window_icon(v->top, 0); @@ -1983,6 +2916,17 @@ Viewer *xsane_viewer_new(char *filename, char *selection_filetype, int allow_red gtk_widget_show(menubar_item); v->geometry_menu = menubar_item; +#ifdef HAVE_LIBLCMS + /* "Color management" submenu: */ + menubar_item = gtk_menu_item_new_with_label(MENU_COLOR_MANAGEMENT); + gtk_container_add(GTK_CONTAINER(menubar), menubar_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_viewer_color_management_build_menu(v)); +/* gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED); */ + gtk_widget_show(menubar_item); + v->color_management_menu = menubar_item; + gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu), v->enable_color_management); +#endif + gtk_widget_show(menubar); diff --git a/src/xsane-viewer.h b/src/xsane-viewer.h index 373fd31..b729151 100644 --- a/src/xsane-viewer.h +++ b/src/xsane-viewer.h @@ -3,7 +3,7 @@ xsane-viewer.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 2001-2005 Oliver Rauch + Copyright (C) 2001-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -47,6 +47,8 @@ typedef struct Viewer char *undo_filename; char *selection_filetype; + int cms_function; + int allow_reduction_to_lineart; int keep_viewer_pnm_format; float zoom; @@ -57,6 +59,15 @@ typedef struct Viewer int despeckle_radius; float blur_radius; + int enable_color_management; + int cms_enable; + int cms_bpc; + int cms_proofing; + int cms_intent; + int cms_proofing_intent; + int cms_gamut_check; + int cms_gamut_alarm_color; + int bind_scale; double x_scale_factor; double y_scale_factor; @@ -73,6 +84,7 @@ typedef struct Viewer GtkWidget *edit_menu; GtkWidget *filters_menu; GtkWidget *geometry_menu; + GtkWidget *color_management_menu; GtkWidget *viewport; GtkWidget *window; @@ -94,6 +106,11 @@ typedef struct Viewer GtkWidget *despeckle; GtkWidget *blur; + GtkWidget *cms_proofing_widget[3]; + GtkWidget *cms_intent_widget[4]; + GtkWidget *cms_proofing_intent_widget[2]; + GtkWidget *cms_gamut_alarm_color_widget[6]; + GtkWidget *image_info_label; GtkProgressBar *progress_bar; diff --git a/src/xsane.c b/src/xsane.c index 9254ea7..38ee7d1 100644 --- a/src/xsane.c +++ b/src/xsane.c @@ -3,7 +3,7 @@ xsane.c Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -56,6 +56,7 @@ struct option long_options[] = {"version", no_argument, 0, 'v'}, {"license", no_argument, 0, 'l'}, {"device-settings", required_argument, 0, 'd'}, + {"xsane-rc", required_argument, 0, 'r'}, {"save", no_argument, 0, 's'}, {"viewer", no_argument, 0, 'V'}, {"copy", no_argument, 0, 'c'}, @@ -752,7 +753,7 @@ static void xsane_resolution_list_callback(GtkWidget *widget, gpointer data) static int xsane_resolution_widget_new(GtkWidget *parent, int well_known_option, double *resolution, const char *image_xpm[], const gchar *desc, const gchar *widget_name) { - GtkObject *resolution_widget; + GtkWidget *resolution_widget; const SANE_Option_Descriptor *opt; DBG(DBG_proc, "xsane_resolution_widget_new\n"); @@ -1153,6 +1154,14 @@ static void xsane_scanmode_menu_callback(GtkWidget *widget, gpointer data) } } +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_cms_function_menu_callback(GtkWidget *widget, gpointer data) +{ + preferences.cms_function = (int) data; + DBG(DBG_proc, "xsane_cms_function_menu_callback(%d)\n", preferences.cms_function); +} + /* ---------------------------------------------------------------------------------------------------------------------- */ static void xsane_adf_pages_max_callback(GtkWidget *widget, gpointer data) @@ -1444,6 +1453,31 @@ GtkWidget *xsane_update_xsane_callback() /* creates the XSane option window */ gtk_widget_show(xsane_spinbutton); } +#ifdef HAVE_LIBLCMS + if ((xsane.enable_color_management) && + ( (xsane.xsane_mode == XSANE_VIEWER) || + (xsane.xsane_mode == XSANE_SAVE) || + (xsane.xsane_mode == XSANE_EMAIL) || + (xsane.xsane_mode == XSANE_MULTIPAGE) + ) + ) + { + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); + gtk_box_pack_start(GTK_BOX(xsane_vbox_xsane_modus), hbox, FALSE, FALSE, 1); + gtk_widget_show(hbox); + + pixmap = gdk_pixmap_create_from_xpm_d(xsane.histogram_dialog->window, &mask, xsane.bg_trans, (gchar **) cms_xpm); + pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask); + gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); + gdk_drawable_unref(pixmap); + gtk_widget_show(pixmapwidget); + + xsane.cms_function_option_menu = xsane_back_gtk_cms_function_menu_new(preferences.cms_function, (GtkSignalFunc) xsane_cms_function_menu_callback); + gtk_box_pack_end(GTK_BOX(hbox), xsane.cms_function_option_menu, FALSE, FALSE, 2); + gtk_widget_show(xsane.cms_function_option_menu); + } +#endif /* input selection */ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.scansource); @@ -1526,7 +1560,8 @@ GtkWidget *xsane_update_xsane_callback() /* creates the XSane option window */ } - if (xsane.param.depth != 1) /* show medium selection of not lineart mode */ + /* show medium selection when not lineart mode and no color management */ + if ((xsane.param.depth != 1) && (!xsane.enable_color_management)) { /* medium selection */ hbox = gtk_hbox_new(FALSE, 2); @@ -1658,33 +1693,31 @@ GtkWidget *xsane_update_xsane_callback() /* creates the XSane option window */ } #endif - /* test if scanner gamma table is selected */ + /* test if scanner gamma table is selected */ - xsane.scanner_gamma_gray = FALSE; - if (xsane.well_known.gamma_vector >0) - { - const SANE_Option_Descriptor *opt; - - opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector); - if (SANE_OPTION_IS_ACTIVE(opt->cap)) - { - xsane.scanner_gamma_gray = TRUE; - } - } - - xsane.scanner_gamma_color = FALSE; - if (xsane.well_known.gamma_vector_r >0) - { - const SANE_Option_Descriptor *opt; + xsane.scanner_gamma_gray = FALSE; + if (xsane.well_known.gamma_vector >0) + { + const SANE_Option_Descriptor *opt; - opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_r); - if (SANE_OPTION_IS_ACTIVE(opt->cap)) - { - xsane.scanner_gamma_color = TRUE; - } - } + opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector); + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + xsane.scanner_gamma_gray = TRUE; + } + } + xsane.scanner_gamma_color = FALSE; + if (xsane.well_known.gamma_vector_r >0) + { + const SANE_Option_Descriptor *opt; + opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_r); + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + xsane.scanner_gamma_color = TRUE; + } + } /* XSane Frame Enhancement */ @@ -1717,7 +1750,41 @@ GtkWidget *xsane_update_xsane_callback() /* creates the XSane option window */ xsane.slider_gray.active = XSANE_SLIDER_ACTIVE; /* mark slider active */ - if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) ) + + if (xsane.enable_color_management) /* do not show gamma widgets when color management is active */ + { + xsane.gamma = 1.0; + xsane.gamma_red = 1.0; + xsane.gamma_green = 1.0; + xsane.gamma_blue = 1.0; + xsane.brightness = 0.0; + xsane.brightness_red = 0.0; + xsane.brightness_green = 0.0; + xsane.brightness_blue = 0.0; + xsane.contrast = 0.0; + xsane.contrast_red = 0.0; + xsane.contrast_green = 0.0; + xsane.contrast_blue = 0.0; + xsane.threshold = 50.0; + + xsane.slider_gray.value[2] = 100.0; + xsane.slider_gray.value[1] = 50.0; + xsane.slider_gray.value[0] = 0.0; + xsane.slider_red.value[2] = 100.0; + xsane.slider_red.value[1] = 50.0; + xsane.slider_red.value[0] = 0.0; + xsane.slider_green.value[2] = 100.0; + xsane.slider_green.value[1] = 50.0; + xsane.slider_green.value[0] = 0.0; + xsane.slider_blue.value[2] = 100.0; + xsane.slider_blue.value[1] = 50.0; + xsane.slider_blue.value[0] = 0.0; + + return(xsane_hbox); + } + + + if ( (xsane.xsane_channels > 1) && (!xsane.enhancement_rgb_default) ) { xsane_separator_new(xsane_vbox_xsane_modus, 2); } @@ -1725,7 +1792,7 @@ GtkWidget *xsane_update_xsane_callback() /* creates the XSane option window */ xsane_range_new_with_pixmap(xsane.xsane_window->window, GTK_BOX(xsane_vbox_xsane_modus), Gamma_xpm, DESC_GAMMA, XSANE_GAMMA_MIN, XSANE_GAMMA_MAX, 0.01, 0.1, 2, &xsane.gamma, &xsane.gamma_widget, 0, xsane_gamma_changed, TRUE); - if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) ) + if ( (xsane.xsane_channels > 1) && (!xsane.enhancement_rgb_default) ) { xsane_range_new_with_pixmap(xsane.xsane_window->window, GTK_BOX(xsane_vbox_xsane_modus), Gamma_red_xpm, DESC_GAMMA_R, XSANE_GAMMA_MIN, XSANE_GAMMA_MAX, 0.01, 0.1, 2, @@ -1743,7 +1810,7 @@ GtkWidget *xsane_update_xsane_callback() /* creates the XSane option window */ xsane_range_new_with_pixmap(xsane.xsane_window->window, GTK_BOX(xsane_vbox_xsane_modus), brightness_xpm, DESC_BRIGHTNESS, xsane.brightness_min, xsane.brightness_max, 0.1, 1.0, 1, &xsane.brightness, &xsane.brightness_widget, 0, xsane_gamma_changed, TRUE); - if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) ) + if ( (xsane.xsane_channels > 1) && (!xsane.enhancement_rgb_default) ) { xsane_range_new_with_pixmap(xsane.xsane_window->window, GTK_BOX(xsane_vbox_xsane_modus), brightness_red_xpm, DESC_BRIGHTNESS_R, xsane.brightness_min, xsane.brightness_max, 0.1, 1.0, 1, @@ -1761,7 +1828,7 @@ GtkWidget *xsane_update_xsane_callback() /* creates the XSane option window */ xsane_range_new_with_pixmap(xsane.xsane_window->window, GTK_BOX(xsane_vbox_xsane_modus), contrast_xpm, DESC_CONTRAST, xsane.contrast_gray_min, xsane.contrast_max, 0.1, 1.0, 1, &xsane.contrast, &xsane.contrast_widget, 0, xsane_gamma_changed, TRUE); - if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) ) + if ( (xsane.xsane_channels > 1) && (!xsane.enhancement_rgb_default) ) { xsane_range_new_with_pixmap(xsane.xsane_window->window, GTK_BOX(xsane_vbox_xsane_modus), contrast_red_xpm, DESC_CONTRAST_R, xsane.contrast_min, xsane.contrast_max, 0.1, 1.0, 1, @@ -1782,7 +1849,7 @@ GtkWidget *xsane_update_xsane_callback() /* creates the XSane option window */ gtk_box_pack_start(GTK_BOX(xsane_vbox_xsane_modus), xsane_hbox_xsane_enhancement, FALSE, FALSE, 0); gtk_widget_show(xsane_hbox_xsane_enhancement); - if (xsane.xsane_colors > 1) + if (xsane.xsane_channels > 1) { button = xsane_toggle_button_new_with_pixmap(xsane.xsane_window->window, xsane_hbox_xsane_enhancement, rgb_default_xpm, DESC_RGB_DEFAULT, &xsane.enhancement_rgb_default, xsane_enhancement_rgb_default_callback); @@ -1795,7 +1862,7 @@ GtkWidget *xsane_update_xsane_callback() /* creates the XSane option window */ button = xsane_button_new_with_pixmap(xsane.xsane_window->window, xsane_hbox_xsane_enhancement, enhance_xpm, DESC_ENH_AUTO, xsane_auto_enhancement_callback, NULL); - gtk_widget_add_accelerator(button, "clicked", xsane.accelerator_group, GDK_E, GDK_CONTROL_MASK, DEF_GTK_ACCEL_LOCKED); + gtk_widget_add_accelerator(button, "clicked", xsane.accelerator_group, GDK_A, GDK_CONTROL_MASK, DEF_GTK_ACCEL_LOCKED); button = xsane_button_new_with_pixmap(xsane.xsane_window->window, xsane_hbox_xsane_enhancement, default_enhancement_xpm, DESC_ENH_DEFAULT, xsane_enhancement_restore_default, NULL); @@ -1831,7 +1898,8 @@ void xsane_pref_save(void) DBG(DBG_proc, "xsane_pref_save\n"); /* first save xsane-specific preferences: */ - xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", NULL, "xsane", NULL, ".rc", XSANE_PATH_LOCAL_SANE); + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", NULL, NULL, xsane.xsane_rc_set_filename, ".rc", XSANE_PATH_LOCAL_SANE); +// xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", NULL, "xsane", NULL, ".rc", XSANE_PATH_LOCAL_SANE); DBG(DBG_info2, "saving preferences to \"%s\"\n", filename); @@ -1862,7 +1930,8 @@ static int xsane_pref_restore(void) DBG(DBG_proc, "xsane_pref_restore\n"); - xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", NULL, "xsane", NULL, ".rc", XSANE_PATH_LOCAL_SANE); + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", NULL, NULL, xsane.xsane_rc_set_filename, ".rc", XSANE_PATH_LOCAL_SANE); +// xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", NULL, "xsane", NULL, ".rc", XSANE_PATH_LOCAL_SANE); fd = open(filename, O_RDONLY); if (fd >= 0) @@ -1947,7 +2016,23 @@ static int xsane_pref_restore(void) if (!preferences.filename) { - preferences.filename = strdup(OUT_FILENAME); + char filename[PATH_MAX]; + char buf[PATH_MAX]; + + if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL) + { + snprintf(buf, sizeof(buf)-2, "%s%c%s", getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)), SLASH, OUT_FILENAME); + preferences.filename = strdup(buf); + } + else if (getcwd(filename, sizeof(filename))) + { + snprintf(buf, sizeof(buf)-2, "%s%c%s", filename, SLASH, OUT_FILENAME); + preferences.filename = strdup(buf); + } + else + { + preferences.filename = strdup(""); + } } if (!preferences.filetype) @@ -1962,7 +2047,23 @@ static int xsane_pref_restore(void) if (!preferences.fax_project) { - preferences.fax_project = strdup(FAXPROJECT); + char filename[PATH_MAX]; + char buf[PATH_MAX]; + + if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL) + { + snprintf(buf, sizeof(buf)-2, "%s%c%s", getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)), SLASH, FAXPROJECT); + preferences.fax_project = strdup(buf); + } + else if (getcwd(filename, sizeof(filename))) + { + snprintf(buf, sizeof(buf)-2, "%s%c%s", filename, SLASH, FAXPROJECT); + preferences.fax_project = strdup(buf); + } + else + { + preferences.fax_project = strdup(""); + } } if (!preferences.fax_command) @@ -2028,7 +2129,23 @@ static int xsane_pref_restore(void) if (!preferences.email_project) { - preferences.email_project = strdup(EMAILPROJECT); + char filename[PATH_MAX]; + char buf[PATH_MAX]; + + if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL) + { + snprintf(buf, sizeof(buf)-2, "%s%c%s", getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)), SLASH, EMAILPROJECT); + preferences.email_project = strdup(buf); + } + else if (getcwd(filename, sizeof(filename))) + { + snprintf(buf, sizeof(buf)-2, "%s%c%s", filename, SLASH, EMAILPROJECT); + preferences.email_project = strdup(buf); + } + else + { + preferences.email_project = strdup(""); + } } if (!preferences.email_filetype) @@ -2039,7 +2156,23 @@ static int xsane_pref_restore(void) if (!preferences.multipage_project) { - preferences.multipage_project = strdup(MULTIPAGEPROJECT); + char filename[PATH_MAX]; + char buf[PATH_MAX]; + + if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL) + { + snprintf(buf, sizeof(buf)-2, "%s%c%s", getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)), SLASH, MULTIPAGEPROJECT); + preferences.multipage_project = strdup(buf); + } + else if (getcwd(filename, sizeof(filename))) + { + snprintf(buf, sizeof(buf)-2, "%s%c%s", filename, SLASH, MULTIPAGEPROJECT); + preferences.multipage_project = strdup(buf); + } + else + { + preferences.multipage_project = strdup(""); + } } if (!preferences.multipage_filetype) @@ -2076,7 +2209,7 @@ static int xsane_pref_restore(void) { if (getenv(STRINGIFY(ENVIRONMENT_BROWSER_NAME))) { - preferences.browser = getenv(STRINGIFY(ENVIRONMENT_BROWSER_NAME)); + preferences.browser = strdup(getenv(STRINGIFY(ENVIRONMENT_BROWSER_NAME))); } else { @@ -2871,6 +3004,55 @@ static void xsane_set_pref_unit_callback(GtkWidget *widget, gpointer data) } /* ---------------------------------------------------------------------------------------------------------------------- */ +#ifdef HAVE_LIBLCMS +static void xsane_enable_color_management_callback(GtkWidget *widget, gpointer data) +{ + DBG(DBG_proc, "xsane_enable_color_management_callback\n"); + + xsane.enable_color_management = (GTK_CHECK_MENU_ITEM(widget)->active); + + gtk_widget_set_sensitive(xsane.edit_medium_definition_widget, (xsane.enable_color_management) == 0); + + if (xsane.enable_color_management) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.edit_medium_definition_widget), FALSE); + xsane.medium_calibration = FALSE; + } + + xsane.gamma = 1.0; + xsane.gamma_red = 1.0; + xsane.gamma_green = 1.0; + xsane.gamma_blue = 1.0; + xsane.brightness = 0.0; + xsane.brightness_red = 0.0; + xsane.brightness_green = 0.0; + xsane.brightness_blue = 0.0; + xsane.contrast = 0.0; + xsane.contrast_red = 0.0; + xsane.contrast_green = 0.0; + xsane.contrast_blue = 0.0; + xsane.threshold = 50.0; + + xsane.slider_gray.value[2] = 100.0; + xsane.slider_gray.value[1] = 50.0; + xsane.slider_gray.value[0] = 0.0; + xsane.slider_red.value[2] = 100.0; + xsane.slider_red.value[1] = 50.0; + xsane.slider_red.value[0] = 0.0; + xsane.slider_green.value[2] = 100.0; + xsane.slider_green.value[1] = 50.0; + xsane.slider_green.value[0] = 0.0; + xsane.slider_blue.value[2] = 100.0; + xsane.slider_blue.value[1] = 50.0; + xsane.slider_blue.value[0] = 0.0; + + xsane_update_sliders(); + xsane_update_gamma_curve(FALSE); + xsane_batch_scan_update_icon_list(); + xsane_refresh_dialog(); +} +#endif +/* ---------------------------------------------------------------------------------------------------------------------- */ static void xsane_edit_medium_definition_callback(GtkWidget *widget, gpointer data) { @@ -3087,7 +3269,7 @@ static void xsane_info_dialog(GtkWidget *widget, gpointer data) gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 5); gtk_widget_show(table); - if ((xsane.xsane_colors > 1) && (xsane.scanner_gamma_color)) /* color gamma correction by scanner */ + if ((xsane.xsane_channels > 1) && (xsane.scanner_gamma_color)) /* color gamma correction by scanner */ { const SANE_Option_Descriptor *opt; @@ -3108,7 +3290,7 @@ static void xsane_info_dialog(GtkWidget *widget, gpointer data) snprintf(buf, sizeof(buf), "%d bit", (int) (0.5 + log(opt->constraint.range->max+1.0) / log(2.0))); label = xsane_info_table_text_new(table, buf, 1, 2); } - else if ((!xsane.xsane_colors > 1) && (xsane.scanner_gamma_gray)) /* gray gamma correction by scanner */ + else if ((!xsane.xsane_channels > 1) && (xsane.scanner_gamma_gray)) /* gray gamma correction by scanner */ { const SANE_Option_Descriptor *opt; @@ -3996,7 +4178,7 @@ static GtkWidget *xsane_preferences_build_menu(void) gtk_widget_show(item); - +#if 0 /* change working directory */ item = gtk_menu_item_new_with_label(MENU_ITEM_CHANGE_WORKING_DIR); @@ -4010,6 +4192,18 @@ static GtkWidget *xsane_preferences_build_menu(void) item = gtk_menu_item_new(); gtk_menu_append(GTK_MENU(menu), item); gtk_widget_show(item); +#endif + +#ifdef HAVE_LIBLCMS + /* enable color management */ + + item = gtk_check_menu_item_new_with_label(MENU_ITEM_ENABLE_COLOR_MANAGEMENT); + g_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_enable_color_management_callback, NULL); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + xsane.enable_color_management_widget = item; +#endif + /* edit medium definitions */ @@ -4017,6 +4211,7 @@ static GtkWidget *xsane_preferences_build_menu(void) g_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_edit_medium_definition_callback, NULL); gtk_menu_append(GTK_MENU(menu), item); gtk_widget_show(item); + xsane.edit_medium_definition_widget = item; /* insert separator: */ @@ -4705,12 +4900,16 @@ static void xsane_device_dialog(void) GtkWidget *xsane_vbox_advanced; GdkColormap *colormap; SANE_Status status; + SANE_Handle sane_handle; DBG(DBG_proc, "xsane_device_dialog\n"); devname = xsane.devlist[xsane.selected_dev]->name; - status = sane_open(devname, (SANE_Handle *) &xsane.dev); +/* status = sane_open(devname, (SANE_Handle *) &xsane.dev); // old version */ + status = sane_open(devname, &sane_handle); + xsane.dev = sane_handle; + if (status != SANE_STATUS_GOOD) { snprintf(buf, sizeof(buf), "%s `%s':\n %s.", ERR_DEVICE_OPEN_FAILED, devname, XSANE_STRSTATUS(status)); @@ -4802,7 +5001,6 @@ static void xsane_device_dialog(void) xsane.device_text = strdup(devicetext); - /* if no preferences filename is given on commandline create one from devicenaname */ if (!xsane.device_set_filename) @@ -5383,27 +5581,27 @@ static void xsane_choose_device(void) gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); gtk_widget_show(hbox); - /* The OK button */ + /* The Cancel button */ #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_OK); + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); #else - button = gtk_button_new_with_label(BUTTON_OK); + button = gtk_button_new_with_label(BUTTON_CANCEL); #endif - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_choose_dialog_ok_callback, NULL); + gtk_widget_add_accelerator(button, "clicked", device_selection_accelerator_group, GDK_Escape, 0, DEF_GTK_ACCEL_LOCKED); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_exit, NULL); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); - gtk_widget_grab_default(button); gtk_widget_show(button); - /* The Cancel button */ + /* The OK button */ #ifdef HAVE_GTK2 - button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + button = gtk_button_new_from_stock(GTK_STOCK_OK); #else - button = gtk_button_new_with_label(BUTTON_CANCEL); + button = gtk_button_new_with_label(BUTTON_OK); #endif - gtk_widget_add_accelerator(button, "clicked", device_selection_accelerator_group, GDK_Escape, 0, DEF_GTK_ACCEL_LOCKED); - g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_exit, NULL); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_choose_dialog_ok_callback, NULL); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_grab_default(button); gtk_widget_show(button); gtk_widget_show(xsane.choose_device_dialog); @@ -5478,7 +5676,7 @@ static int xsane_init(int argc, char **argv) { int ch; - while((ch = getopt_long(argc, argv, "cd:efghlmnpsvFN:RV", long_options, 0)) != EOF) + while((ch = getopt_long(argc, argv, "cd:efghlmnpr:svFN:RV", long_options, 0)) != EOF) { switch(ch) { @@ -5497,7 +5695,9 @@ static int xsane_init(int argc, char **argv) g_print(" %s %s\n", TEXT_EMAIL_ADR, XSANE_EMAIL_ADR); g_print(" %s %s\n", TEXT_PACKAGE, XSANE_PACKAGE_VERSION); g_print(" %s%d.%d.%d\n", TEXT_GTK_VERSION, GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); - +#ifdef HAVE_LIBLCMS + g_print(" %s\n", TEXT_WITH_CMS_FUNCTION); +#endif #ifdef HAVE_ANY_GIMP g_print(" %s, %s%s\n", TEXT_WITH_GIMP_SUPPORT, TEXT_GIMP_VERSION, GIMP_VERSION); #else @@ -5553,6 +5753,10 @@ static int xsane_init(int argc, char **argv) xsane.device_set_filename = strdup(optarg); break; + case 'r': /* --xsane-rc */ + xsane.xsane_rc_set_filename = strdup(optarg); + break; + case 'V': /* --viewer, default */ xsane.xsane_mode = XSANE_VIEWER; break; @@ -5606,6 +5810,14 @@ static int xsane_init(int argc, char **argv) } } + /* if no xsane_rc filename is given on commandline then use "xsane.rc" */ + + if (!xsane.xsane_rc_set_filename) + { + xsane.xsane_rc_set_filename = strdup("xsane"); /* ".rc" is appended later */ + } + + if (xsane_pref_restore()) /* restore preferences, returns TRUE if license is not accpted yet */ { if (xsane_display_eula(1)) /* show license and ask for accept/not accept */ @@ -5649,6 +5861,9 @@ static int xsane_init(int argc, char **argv) device_scanning_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(device_scanning_dialog), GTK_WIN_POS_CENTER); gtk_window_set_resizable(GTK_WINDOW(device_scanning_dialog), FALSE); +/* + gtk_window_set_deletable(GTK_WINDOW(device_scanning_dialog), FALSE); +*/ snprintf(buf, sizeof(buf), "%s %s", xsane.prog_name, XSANE_VERSION); gtk_window_set_title(GTK_WINDOW(device_scanning_dialog), buf); g_signal_connect(GTK_OBJECT(device_scanning_dialog), "delete_event", GTK_SIGNAL_FUNC(xsane_quit), NULL); @@ -5914,11 +6129,13 @@ int main(int argc, char **argv) xsane.histogram_int = 1; xsane.histogram_log = 1; - xsane.xsane_colors = -1; /* unused value to make sure that change of this vlaue is detected */ + xsane.xsane_channels = -1; /* unused value to make sure that change of this vlaue is detected */ xsane.scanner_gamma_color = FALSE; xsane.scanner_gamma_gray = FALSE; xsane.enhancement_rgb_default = TRUE; + xsane.enable_color_management = FALSE; + xsane.adf_page_counter = 0; xsane.print_filenames = FALSE; xsane.force_filename = FALSE; diff --git a/src/xsane.h b/src/xsane.h index 154bb52..4e4ddd8 100644 --- a/src/xsane.h +++ b/src/xsane.h @@ -3,7 +3,7 @@ xsane.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify @@ -69,6 +69,12 @@ #include <gdk/gdk.h> #include <gtk/gtk.h> +#ifdef HAVE_LIBLCMS +# include "lcms.h" +#else +# define cmsHTRANSFORM void * +#endif + /* ---------------------------------------------------------------------------------------------------------------------- */ #if 0 @@ -85,10 +91,10 @@ /* ---------------------------------------------------------------------------------------------------------------------- */ -#define XSANE_VERSION "0.991" +#define XSANE_VERSION "0.993" #define XSANE_AUTHOR "Oliver Rauch" #define XSANE_COPYRIGHT "Oliver Rauch" -#define XSANE_DATE "1998-2006" +#define XSANE_DATE "1998-2007" #define XSANE_EMAIL_ADR "Oliver.Rauch@xsane.org" #define XSANE_HOMEPAGE "http://www.xsane.org" #define XSANE_COPYRIGHT_TXT XSANE_DATE " " XSANE_COPYRIGHT @@ -381,7 +387,7 @@ typedef struct Image_info int image_height; int depth; - int colors; + int channels; double resolution_x; double resolution_y; @@ -404,6 +410,13 @@ typedef struct Image_info double threshold; int reduce_to_lineart; + + int enable_color_management; + int cms_function; + int cms_intent; + int cms_bpc; + + char icm_profile[PATH_MAX]; } Image_info; @@ -469,7 +482,14 @@ enum EMAIL_AUTH_ASMTP_LOGIN, EMAIL_AUTH_ASMTP_CRAM_MD5 }; - + +enum +{ + XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE = 0, + XSANE_CMS_FUNCTION_CONVERT_TO_SRGB, + XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS +}; + /* ---------------------------------------------------------------------------------------------------------------------- */ extern void xsane_pref_save(void); @@ -617,6 +637,7 @@ typedef struct Xsane char *backend; char *backend_translation; char *device_set_filename; + char *xsane_rc_set_filename; char *output_filename; char *dummy_filename; @@ -739,6 +760,9 @@ typedef struct Xsane GtkWidget *filename_entry; GtkWidget *filetype_option_menu; + /* for all modes */ + GtkWidget *cms_function_option_menu; + /* saving and transformation values: */ FILE *out; int xsane_mode; @@ -816,22 +840,24 @@ typedef struct Xsane GtkWidget *show_standard_options_widget; GtkWidget *show_advanced_options_widget; GtkWidget *show_resolution_list_widget; - GtkObject *zoom_widget; - GtkObject *gamma_widget; - GtkObject *gamma_red_widget; - GtkObject *gamma_green_widget; - GtkObject *gamma_blue_widget; - GtkObject *brightness_widget; - GtkObject *brightness_red_widget; - GtkObject *brightness_green_widget; - GtkObject *brightness_blue_widget; - GtkObject *contrast_widget; - GtkObject *contrast_red_widget; - GtkObject *contrast_green_widget; - GtkObject *contrast_blue_widget; - GtkObject *threshold_widget; - - SANE_Int xsane_colors; + GtkWidget *enable_color_management_widget; + GtkWidget *edit_medium_definition_widget; + GtkWidget *zoom_widget; + GtkWidget *gamma_widget; + GtkWidget *gamma_red_widget; + GtkWidget *gamma_green_widget; + GtkWidget *gamma_blue_widget; + GtkWidget *brightness_widget; + GtkWidget *brightness_red_widget; + GtkWidget *brightness_green_widget; + GtkWidget *brightness_blue_widget; + GtkWidget *contrast_widget; + GtkWidget *contrast_red_widget; + GtkWidget *contrast_green_widget; + GtkWidget *contrast_blue_widget; + GtkWidget *threshold_widget; + + SANE_Int xsane_channels; SANE_Bool scanner_gamma_color; SANE_Bool scanner_gamma_gray; @@ -945,10 +971,17 @@ typedef struct Xsane int enhancement_rgb_default; int negative; int show_preview; + + int enable_color_management; + char *scanner_active_icm_profile; + char *scanner_default_color_icm_profile; + char *scanner_default_gray_icm_profile; + int print_filenames; int force_filename; char *external_filename; + /* -------------------------------------------------- */ int ipc_pipefd[2]; /* for inter process communication error messages */ @@ -974,9 +1007,12 @@ typedef struct XsaneSetup GtkWidget *printer_gamma_red_entry; GtkWidget *printer_gamma_green_entry; GtkWidget *printer_gamma_blue_entry; + GtkWidget *printer_icm_profile_entry; + GtkWidget *printer_embed_csa_button; + GtkWidget *printer_embed_crd_button; GtkWidget *printer_width_entry; GtkWidget *printer_height_entry; - GtkWidget *printer_ps_flatdecoded_button; + GtkWidget *printer_ps_flatedecoded_button; GtkWidget *jpeg_image_quality_scale; GtkWidget *png_image_compression_scale; @@ -985,8 +1021,8 @@ typedef struct XsaneSetup GtkWidget *overwrite_warning_button; GtkWidget *increase_filename_counter_button; GtkWidget *skip_existing_numbers_button; - GtkWidget *save_ps_flatdecoded_button; - GtkWidget *save_pdf_flatdecoded_button; + GtkWidget *save_ps_flatedecoded_button; + GtkWidget *save_pdf_flatedecoded_button; GtkWidget *save_pnm16_as_ascii_button; GtkWidget *reduce_16bit_to_8bit_button; @@ -1020,7 +1056,7 @@ typedef struct XsaneSetup GtkWidget *fax_leftoffset_entry; GtkWidget *fax_bottomoffset_entry; GtkWidget *fax_height_entry; - GtkWidget *fax_ps_flatdecoded_button; + GtkWidget *fax_ps_flatedecoded_button; GtkWidget *tmp_path_entry; @@ -1041,6 +1077,15 @@ typedef struct XsaneSetup GtkWidget *ocr_gui_outfd_option_entry; GtkWidget *ocr_progress_keyword_entry; + GtkWidget *cms_intent_option_menu; + GtkWidget *cms_bpc_button; + GtkWidget *embed_scanner_icm_profile_for_gimp_button; + GtkWidget *scanner_default_color_icm_profile_entry; + GtkWidget *scanner_default_gray_icm_profile_entry; + GtkWidget *display_icm_profile_entry; + GtkWidget *custom_proofing_icm_profile_entry; + GtkWidget *working_color_space_icm_profile_entry; + int filename_counter_len; int tiff_compression16_nr; diff --git a/src/xsaneopts.h b/src/xsaneopts.h index 8dbd655..5e03f54 100644 --- a/src/xsaneopts.h +++ b/src/xsaneopts.h @@ -3,7 +3,7 @@ xsaneopts.h Oliver Rauch <Oliver.Rauch@rauch-domain.de> - Copyright (C) 1998-2005 Oliver Rauch + Copyright (C) 1998-2007 Oliver Rauch This file is part of the XSANE package. This program is free software; you can redistribute it and/or modify |