diff options
author | Mattia Rizzolo <mattia@mapreri.org> | 2014-10-03 14:04:58 +0000 |
---|---|---|
committer | Mattia Rizzolo <mattia@mapreri.org> | 2014-10-03 14:04:58 +0000 |
commit | 2d113e8792747151bf5d830f1a1485f2f951f940 (patch) | |
tree | f29e273d53fe5735cdac171504d798bf45ea2007 /frontend |
Imported Upstream version 0.50upstream/0.50
Diffstat (limited to 'frontend')
33 files changed, 23592 insertions, 0 deletions
diff --git a/frontend/Makefile.in b/frontend/Makefile.in new file mode 100644 index 0000000..439369d --- /dev/null +++ b/frontend/Makefile.in @@ -0,0 +1,85 @@ +SHELL = /bin/sh + +VPATH = @srcdir@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = .. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +configdir = ${sysconfdir}/sane.d +sanedatadir = ${datadir}/sane + +MKINSTALLDIRS = @MKINSTALLDIRS@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include \ + @GTK_CFLAGS@ @INCLUDES@ \ + -DLOCALEDIR=\""$(datadir)/locale"\" +DEFS = @DEFS@ +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @INTLLIBS@ @LIBS@ +GTK_LIBS = @GTK_LIBS@ +GIMP_LIBS = @GIMP_LIBS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(LDFLAGS) -o $@ + +BINPROGS = @BINPROGS@ + +@SET_MAKE@ + +PROGRAMS = $(BINPROGS) +LIBLIB = ../lib/liblib.a + +XSANE_OBJS = xsane-back-gtk.o xsane-front-gtk.o xsane-gamma.o xsane-preview.o \ + xsane-rc-io.o xsane-device-preferences.o xsane-preferences.o \ + xsane-setup.o xsane-save.o xsane-scan.o xsane-icons.o xsane.o + + +.c.o: + $(COMPILE) $< + +all: $(PROGRAMS) + +install: $(PROGRAMS) + $(MKINSTALLDIRS) $(bindir) $(sbindir) $(datadir) $(sanedatadir) $(sanedatadir)/xsane + @for program in $(BINPROGS); do \ + $(INSTALL_PROGRAM) $${program} $(bindir)/$${program}; \ + done + $(INSTALL_DATA) $(srcdir)/xsane-style.rc $(sanedatadir)/xsane/xsane-style.rc + $(INSTALL_DATA) $(srcdir)/xsane-logo.xpm $(sanedatadir)/xsane-logo.xpm + +xsane: $(XSANE_OBJS) $(LIBLIB) + $(LINK) $(XSANE_OBJS) \ + $(LIBLIB) $(GIMP_LIBS) $(GTK_LIBS) $(LIBS) + + +clean: + rm -f *.o *~ .*~ *.bak + rm -rf .libs + +distclean: clean + rm -f Makefile $(PROGRAMS) + +depend: + makedepend $(INCLUDES) *.c + +.PHONY: all install depend clean distclean diff --git a/frontend/cursor/cursor_pipette_black b/frontend/cursor/cursor_pipette_black new file mode 100644 index 0000000..9fc4d56 --- /dev/null +++ b/frontend/cursor/cursor_pipette_black @@ -0,0 +1,8 @@ +#define cursor_pipette_black_width 16 +#define cursor_pipette_black_height 16 +#define cursor_pipette_black_x_hot 1 +#define cursor_pipette_black_y_hot 14 +static unsigned char cursor_pipette_black_bits[] = { + 0x00, 0x70, 0x00, 0xf8, 0x80, 0xff, 0x00, 0xfe, 0x00, 0x7d, 0x80, 0x38, + 0x40, 0x18, 0xe0, 0x17, 0xf0, 0x13, 0xf8, 0x01, 0xfc, 0x00, 0x7c, 0x00, + 0x3e, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x00}; diff --git a/frontend/cursor/cursor_pipette_gray b/frontend/cursor/cursor_pipette_gray new file mode 100644 index 0000000..7cbea80 --- /dev/null +++ b/frontend/cursor/cursor_pipette_gray @@ -0,0 +1,8 @@ +#define cursor_pipette_gray_width 16 +#define cursor_pipette_gray_height 16 +#define cursor_pipette_gray_x_hot 1 +#define cursor_pipette_gray_y_hot 14 +static unsigned char cursor_pipette_gray_bits[] = { + 0x00, 0x70, 0x00, 0xf8, 0x80, 0xff, 0x00, 0xfe, 0x00, 0x7d, 0x80, 0x38, + 0x40, 0x18, 0x20, 0x14, 0x10, 0x12, 0xf8, 0x01, 0xfc, 0x00, 0x7c, 0x00, + 0x3e, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x00}; diff --git a/frontend/cursor/cursor_pipette_mask b/frontend/cursor/cursor_pipette_mask new file mode 100644 index 0000000..36c7757 --- /dev/null +++ b/frontend/cursor/cursor_pipette_mask @@ -0,0 +1,8 @@ +#define cursor_pipette_mask_width 16 +#define cursor_pipette_mask_height 16 +#define cursor_pipette_mask_x_hot 1 +#define cursor_pipette_mask_y_hot 14 +static unsigned char cursor_pipette_mask_bits[] = { + 0x00, 0x70, 0x00, 0xf8, 0x80, 0xff, 0x00, 0xfe, 0x00, 0x7f, 0x80, 0x3f, + 0xc0, 0x1f, 0xe0, 0x17, 0xf0, 0x13, 0xf8, 0x01, 0xfc, 0x00, 0x7c, 0x00, + 0x3e, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x00}; diff --git a/frontend/cursor/cursor_pipette_white b/frontend/cursor/cursor_pipette_white new file mode 100644 index 0000000..9952441 --- /dev/null +++ b/frontend/cursor/cursor_pipette_white @@ -0,0 +1,8 @@ +#define cursor_pipette_white_width 16 +#define cursor_pipette_white_height 16 +#define cursor_pipette_white_x_hot 1 +#define cursor_pipette_white_y_hot 14 +static unsigned char cursor_pipette_white_bits[] = { + 0x00, 0x70, 0x00, 0xf8, 0x80, 0xff, 0x00, 0xfe, 0x00, 0x7d, 0x80, 0x38, + 0x40, 0x18, 0x20, 0x14, 0x10, 0x12, 0x08, 0x01, 0x84, 0x00, 0x44, 0x00, + 0x32, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00}; diff --git a/frontend/xsane-back-gtk.c b/frontend/xsane-back-gtk.c new file mode 100644 index 0000000..8bde762 --- /dev/null +++ b/frontend/xsane-back-gtk.c @@ -0,0 +1,1426 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-back-gtk.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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-preferences.h" +#include "xsane-text.h" + +/* ----------------------------------------------------------------------------------------------------------------- */ + +/* extern declarations */ +extern void xsane_panel_build(GSGDialog *dialog); + +/* ----------------------------------------------------------------------------------------------------------------- */ + +/* forward declarations: */ +static void xsane_back_gtk_panel_rebuild(GSGDialog *dialog); +void xsane_set_sensitivity(SANE_Int sensitivity); +void xsane_set_window_icon(GtkWidget *gtk_window, gchar **xpm_d); + +/* ----------------------------------------------------------------------------------------------------------------- */ + +const char *xsane_back_gtk_unit_string(SANE_Unit unit) +{ + double d; + + switch (unit) + { + case SANE_UNIT_NONE: return "none"; + case SANE_UNIT_PIXEL: return "pixel"; + case SANE_UNIT_BIT: return "bit"; + case SANE_UNIT_DPI: return "dpi"; + case SANE_UNIT_PERCENT: return "%"; + case SANE_UNIT_MM: + d = preferences.length_unit; + if (d > 9.9 && d < 10.1) + { + return "cm"; + } + else if (d > 25.3 && d < 25.5) + { + return "in"; + } + return "mm"; + case SANE_UNIT_MICROSECOND: return "\265s"; + } + return 0; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_set_tooltip(GtkTooltips *tooltips, GtkWidget *widget, const char *desc) +{ + if (desc && desc[0]) + { + gtk_tooltips_set_tip(tooltips, widget, desc, 0); + } +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +int xsane_back_gtk_make_path(size_t buf_size, char *buf, + const char *prog_name, + const char *dir_name, + const char *prefix, const char *dev_name, + const char *postfix, + int location) +{ + struct passwd *pw; + size_t len, extra; + int i; + + if (location == XSANE_PATH_LOCAL_SANE) /* make path to local file */ + { + pw = getpwuid(getuid()); /* get homedirectory */ + if (!pw) + { + snprintf(buf, buf_size, "%s %s", ERR_HOME_DIR, strerror(errno)); + xsane_back_gtk_error(buf, FALSE); + return -1; + } + + snprintf(buf, buf_size, "%s/.sane", pw->pw_dir); + mkdir(buf, 0777); /* ensure ~/.sane directory exists */ + } + else if (location == XSANE_PATH_SYSTEM) /* make path to system file */ + { + snprintf(buf, buf_size, "%s", STRINGIFY(PATH_SANE_DATA_DIR)); + } + else /* make path to temporary file */ + { + snprintf(buf, buf_size, "%s", PATH_SANE_TMP); + } + + len = strlen(buf); + + if (prog_name) + { + extra = strlen(prog_name); + if (len + extra + 1 >= buf_size) + { + goto filename_too_long; + } + + buf[len++] = '/'; + memcpy(buf + len, prog_name, extra); + len += extra; + buf[len] = '\0'; + mkdir(buf, 0777); /* ensure ~/.sane/PROG_NAME directory exists */ + } + if (len >= buf_size) + { + goto filename_too_long; + } + + buf[len++] = '/'; + + + if (dir_name) + { + extra = strlen(dir_name); + if (len + extra + 1 >= buf_size) + { + goto filename_too_long; + } + + buf[len++] = '/'; + memcpy(buf + len, dir_name, extra); + len += extra; + buf[len] = '\0'; + mkdir(buf, 0777); /* ensure DIR_NAME directory exists */ + } + + if (len >= buf_size) + { + goto filename_too_long; + } + + buf[len++] = '/'; + + + if (prefix) + { + extra = strlen(prefix); + if (len + extra >= buf_size) + { + goto filename_too_long; + } + + memcpy(buf + len, prefix, extra); + len += extra; + } + + if (location == XSANE_PATH_TMP) /* system tmp dir, add uid */ + { + char uid_prefix[256]; + uid_t uid; + + uid = getuid(); + snprintf(uid_prefix, sizeof(uid_prefix), "%d-", uid); + + extra = strlen(uid_prefix); + if (len + extra >= buf_size) + { + goto filename_too_long; + } + + memcpy(buf + len, uid_prefix, extra); + len += extra; + } + + if (dev_name) + { + /* Turn devicename into valid filename by replacing slashes by "_", "_" gets "__", spaces are erased */ + + for (i = 0; dev_name[i]; ++i) + { + if (len + 2 >= buf_size) + { + goto filename_too_long; + } + + switch (dev_name[i]) + { + case '/': /* "/" -> "_" */ + buf[len++] = '_'; + break; + + case ' ': /* erase " " */ + break; + + case '_': /* "_" -> "__" */ + buf[len++] = '_'; + /* fall through */ + default: + buf[len++] = dev_name[i]; + break; + } + } + } + + if (postfix) + { + extra = strlen(postfix); + if (len + extra >= buf_size) + { + goto filename_too_long; + } + memcpy(buf + len, postfix, extra); + len += extra; + } + if (len >= buf_size) + goto filename_too_long; + + buf[len++] = '\0'; + return 0; + +filename_too_long: + xsane_back_gtk_error(ERR_FILENAME_TOO_LONG, FALSE); + errno = E2BIG; + return -1; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_set_option(GSGDialog * dialog, int opt_num, void *val, SANE_Action action) +{ + SANE_Status status; + SANE_Int info; + char buf[256]; + + status = sane_control_option(dialog->dev, opt_num, action, val, &info); + if (status != SANE_STATUS_GOOD) + { + snprintf(buf, sizeof(buf), "%s %s: %s.", ERR_SET_OPTION, sane_get_option_descriptor(dialog->dev, opt_num)->name, + XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, FALSE); + return; + } + + if ((info & SANE_INFO_RELOAD_PARAMS) && dialog->param_change_callback) + { + (*dialog->param_change_callback) (dialog, dialog->param_change_arg); + } + + if (info & SANE_INFO_RELOAD_OPTIONS) + { + xsane_back_gtk_panel_rebuild(dialog); + if (dialog->option_reload_callback) + { + (*dialog->option_reload_callback) (dialog, dialog->option_reload_arg); + } + } +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_close_dialog_callback(GtkWidget * widget, gpointer data) +{ + gtk_widget_destroy(data); + xsane_back_gtk_message_dialog_active = 0; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static gint decision_flag; +static GtkWidget *decision_dialog; + +void xsane_back_gtk_decision_callback(GtkWidget * widget, gpointer data) +{ + gtk_widget_destroy(decision_dialog); + xsane_back_gtk_message_dialog_active = 0; + decision_flag = (long) data; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +gint xsane_back_gtk_decision(gchar *title, gchar **xpm_d, gchar *message, gchar *oktext, gchar *rejecttext, gint wait) +{ + GtkWidget *main_vbox, *hbox, *label, *button; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkWidget *pixmapwidget; + + if (xsane_back_gtk_message_dialog_active) + { + fprintf(stderr, "%s: %s\n", title, message); + return TRUE; + } + xsane_back_gtk_message_dialog_active = 1; + decision_dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_position(GTK_WINDOW(decision_dialog), GTK_WIN_POS_MOUSE); + gtk_window_set_title(GTK_WINDOW(decision_dialog), title); + gtk_signal_connect(GTK_OBJECT(decision_dialog), "delete_event", + GTK_SIGNAL_FUNC(xsane_back_gtk_decision_callback), (void *) -1); /* -1 = cancel */ + + xsane_set_window_icon(decision_dialog, 0); + + /* create the main vbox */ + main_vbox = gtk_vbox_new(TRUE, 5); + gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 5); + gtk_widget_show(main_vbox); + + gtk_container_add(GTK_CONTAINER(decision_dialog), main_vbox); + + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 4); + gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, FALSE, 0); + + /* the info icon */ + if (xpm_d) + { + pixmap = gdk_pixmap_create_from_xpm_d(decision_dialog->window, &mask, xsane.bg_trans, xpm_d); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 10); + gtk_widget_show(pixmapwidget); + gdk_pixmap_unref(pixmap); + } + + /* the message */ + label = gtk_label_new(message); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + gtk_widget_show(hbox); + + + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 4); + gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, FALSE, 0); + + /* the confirmation button */ + button = gtk_button_new_with_label(oktext); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_back_gtk_decision_callback, (void *) 1 /* confirm */); + gtk_container_add(GTK_CONTAINER(hbox), button); + gtk_widget_grab_default(button); + gtk_widget_show(button); + + + if (rejecttext) /* the rejection button */ + { + button = gtk_button_new_with_label(rejecttext); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_back_gtk_decision_callback, (void *) -1 /* reject */); + gtk_container_add(GTK_CONTAINER(hbox), button); + gtk_widget_show(button); + } + gtk_widget_show(hbox); + + gtk_widget_show(decision_dialog); + + if (!wait) + { + return TRUE; + } + + decision_flag = 0; + + while (decision_flag == 0) + { + gtk_main_iteration(); + } + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (decision_flag == 1) + { + return TRUE; + } + + return FALSE; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_message(gchar *title, gchar **icon_xpm, gchar *message, gint wait) +{ + xsane_back_gtk_decision(title, icon_xpm, message, ERR_BUTTON_OK, 0 /* no reject text */, wait); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_error(gchar *error, gint wait) +{ + if (wait) + { + SANE_Int old_sensitivity = xsane.sensitivity; + + xsane_set_sensitivity(FALSE); + xsane_back_gtk_message(ERR_HEADER_ERROR, (gchar**) error_xpm, error, wait); + xsane_set_sensitivity(old_sensitivity); + } + else + { + xsane_back_gtk_message(ERR_HEADER_ERROR, (gchar **) error_xpm, error, wait); + } +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_warning(gchar *warning, gint wait) +{ + if (wait) + { + SANE_Int old_sensitivity = xsane.sensitivity; + + xsane_set_sensitivity(FALSE); + xsane_back_gtk_message(ERR_HEADER_WARNING, (gchar**) warning_xpm, warning, wait); + xsane_set_sensitivity(old_sensitivity); + } + else + { + xsane_back_gtk_message(ERR_HEADER_WARNING, (gchar**) warning_xpm, warning, wait); + } +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_back_gtk_get_filename_button_clicked(GtkWidget *w, gpointer data) +{ + int *clicked = data; + *clicked = 1; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +int xsane_back_gtk_get_filename(const char *label, const char *default_name, size_t max_len, char *filename, int show_fileopts) +{ + int cancel = 0, ok = 0, destroy = 0; + GtkWidget *fileselection; + + fileselection = gtk_file_selection_new((char *) label); + + gtk_signal_connect(GTK_OBJECT(fileselection), + "destroy", GTK_SIGNAL_FUNC(xsane_back_gtk_get_filename_button_clicked), &destroy); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fileselection)->cancel_button), + "clicked", (GtkSignalFunc) xsane_back_gtk_get_filename_button_clicked, &cancel); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fileselection)->ok_button), + "clicked", (GtkSignalFunc) xsane_back_gtk_get_filename_button_clicked, &ok); + if (default_name) + { + gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection), (char *) default_name); + } + + if (show_fileopts) + { + gtk_file_selection_show_fileop_buttons(GTK_FILE_SELECTION(fileselection)); + } + else + { + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(fileselection)); + } + + gtk_widget_show(fileselection); + + while (!cancel && !ok && !destroy) + { + if (!gtk_events_pending()) + { + usleep(100000); + } + gtk_main_iteration(); + } + + if (ok) + { + size_t len, cwd_len; + char *cwd; + + strncpy(filename, gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection)), max_len - 1); + filename[max_len - 1] = '\0'; + + len = strlen(filename); + cwd = alloca(len + 2); + getcwd(cwd, len + 1); + cwd_len = strlen(cwd); + cwd[cwd_len++] = '/'; + cwd[cwd_len] = '\0'; + if (strncmp(filename, cwd, cwd_len) == 0) + { + memcpy(filename, filename + cwd_len, len - cwd_len + 1); + } + } + + if (!destroy) + { + gtk_widget_destroy(fileselection); + } + + return ok ? 0 : -1; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static gint xsane_back_gtk_autobutton_update(GtkWidget *widget, GSGDialogElement *elem) +{ + GSGDialog *dialog = elem->dialog; + int opt_num = elem - dialog->element; + const SANE_Option_Descriptor *opt; + SANE_Status status; + SANE_Word val; + char buf[256]; + + opt = sane_get_option_descriptor(dialog->dev, opt_num); + if (GTK_TOGGLE_BUTTON(widget)->active) + { + xsane_back_gtk_set_option(dialog, opt_num, 0, SANE_ACTION_SET_AUTO); + } + else + { + status = sane_control_option(dialog->dev, opt_num, SANE_ACTION_GET_VALUE, &val, 0); + if (status != SANE_STATUS_GOOD) + { + snprintf(buf, sizeof(buf), "%s %s: %s.", ERR_GET_OPTION, opt->name, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, FALSE); + } + xsane_back_gtk_set_option(dialog, opt_num, &val, SANE_ACTION_SET_VALUE); + } + return FALSE; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_back_gtk_autobutton_new(GtkWidget *parent, GSGDialogElement *elem, + GtkWidget *label, GtkTooltips *tooltips) +{ + GtkWidget *button, *alignment; + + button = gtk_check_button_new(); + gtk_container_set_border_width(GTK_CONTAINER(button), 0); + gtk_widget_set_usize(button, 20, 20); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_back_gtk_autobutton_update, elem); + xsane_back_gtk_set_tooltip(tooltips, button, "Turns on automatic mode."); + + alignment = gtk_alignment_new(0.0, 1.0, 0.5, 0.5); + gtk_container_add(GTK_CONTAINER(alignment), button); + + gtk_box_pack_end(GTK_BOX(parent), label, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(parent), alignment, FALSE, FALSE, 2); + + gtk_widget_show(alignment); + gtk_widget_show(button); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static gint xsane_back_gtk_button_update(GtkWidget * widget, GSGDialogElement * elem) +{ + GSGDialog *dialog = elem->dialog; + int opt_num = elem - dialog->element; + const SANE_Option_Descriptor *opt; + SANE_Word val = SANE_FALSE; + + opt = sane_get_option_descriptor(dialog->dev, opt_num); + if (GTK_TOGGLE_BUTTON(widget)->active) + { + val = SANE_TRUE; + } + xsane_back_gtk_set_option(dialog, opt_num, &val, SANE_ACTION_SET_VALUE); + + return FALSE; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_button_new(GtkWidget * parent, const char *name, SANE_Word val, + GSGDialogElement * elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable) +{ + GtkWidget *button; + + button = gtk_check_button_new_with_label((char *) name); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), val); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_back_gtk_button_update, elem); + gtk_box_pack_start(GTK_BOX(parent), button, FALSE, TRUE, 0); + gtk_widget_show(button); + xsane_back_gtk_set_tooltip(tooltips, button, desc); + + gtk_widget_set_sensitive(button, settable); + + elem->widget = button; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_back_gtk_scale_update(GtkAdjustment * adj_data, GSGDialogElement * elem) +{ + const SANE_Option_Descriptor *opt; + GSGDialog *dialog = elem->dialog; + SANE_Word val, new_val; + int opt_num; + double d; + + opt_num = elem - dialog->element; + opt = sane_get_option_descriptor(dialog->dev, opt_num); + switch(opt->type) + { + case SANE_TYPE_INT: + val = adj_data->value + 0.5; + break; + + case SANE_TYPE_FIXED: + d = adj_data->value; + if (opt->unit == SANE_UNIT_MM) + { + d *= preferences.length_unit; + } + val = SANE_FIX(d); + break; + + default: + fprintf(stderr, "xsane_back_gtk_scale_update: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + return; + } + + xsane_back_gtk_set_option(dialog, opt_num, &val, SANE_ACTION_SET_VALUE); + sane_control_option(dialog->dev, opt_num, SANE_ACTION_GET_VALUE, &new_val, 0); + if (new_val != val) + { + val = new_val; + goto value_changed; + } + return; /* value didn't change */ + +value_changed: + switch(opt->type) + { + case SANE_TYPE_INT: + adj_data->value = val; + break; + + case SANE_TYPE_FIXED: + d = SANE_UNFIX(val); + if (opt->unit == SANE_UNIT_MM) + { + d /= preferences.length_unit; + } + adj_data->value = d; + break; + + default: + break; + } + /* Let widget know that value changed _again_. This must converge + quickly---otherwise things would get very slow very quickly (as + in "infinite recursion"): */ + gtk_signal_emit_by_name(GTK_OBJECT(adj_data), "value_changed"); + return; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_scale_new(GtkWidget * parent, const char *name, gfloat val, + gfloat min, gfloat max, gfloat quant, int automatic, + GSGDialogElement * elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable) +{ + GtkWidget *hbox, *label, *scale; + + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 0); + gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0); + + label = gtk_label_new((char *) name); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + + elem->data = gtk_adjustment_new(val, min, max, quant, 1.0, 0.0); + scale = gtk_hscale_new(GTK_ADJUSTMENT(elem->data)); + xsane_back_gtk_set_tooltip(tooltips, scale, desc); + gtk_widget_set_usize(scale, 150, 0); + + if (automatic) + { + xsane_back_gtk_autobutton_new(hbox, elem, scale, tooltips); + } + else + { + gtk_box_pack_end(GTK_BOX(hbox), scale, FALSE, FALSE, 0); /* make scales fixed */ +/* gtk_box_pack_end(GTK_BOX(hbox), scale, TRUE, TRUE, 0); */ /* make scales sizeable */ + } + + gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); + gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP); + if (quant - (int) quant == 0.0) + { + gtk_scale_set_digits(GTK_SCALE(scale), 0); + } + else + { + /* one place behind decimal point */ + gtk_scale_set_digits(GTK_SCALE(scale), 1); + } + + gtk_signal_connect(elem->data, "value_changed", (GtkSignalFunc) xsane_back_gtk_scale_update, elem); + + gtk_widget_show(label); + gtk_widget_show(scale); + gtk_widget_show(hbox); + + gtk_widget_set_sensitive(scale, settable); + + elem->widget = scale; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_push_button_callback(GtkWidget * widget, gpointer data) +{ + GSGDialogElement *elem = data; + GSGDialog *dialog = elem->dialog; + int opt_num; + + opt_num = elem - dialog->element; + xsane_back_gtk_set_option(dialog, opt_num, 0, SANE_ACTION_SET_VALUE); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static int xsane_back_gtk_option_menu_lookup(GSGMenuItem menu_items[], const char *string) +{ + int i; + + for (i = 0; strcmp(menu_items[i].label, string) != 0; ++i); + + return i; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_back_gtk_option_menu_callback(GtkWidget * widget, gpointer data) +{ + GSGMenuItem *menu_item = data; + GSGDialogElement *elem = menu_item->elem; + const SANE_Option_Descriptor *opt; + GSGDialog *dialog = elem->dialog; + int opt_num; + double dval; + SANE_Word val; + void *valp = &val; + + opt_num = elem - dialog->element; + opt = sane_get_option_descriptor(dialog->dev, opt_num); + switch(opt->type) + { + case SANE_TYPE_INT: + sscanf(menu_item->label, "%d", &val); + break; + + case SANE_TYPE_FIXED: + sscanf(menu_item->label, "%lg", &dval); + val = SANE_FIX(dval); + break; + + case SANE_TYPE_STRING: + valp = menu_item->label; + break; + + default: + fprintf(stderr, "xsane_back_gtk_option_menu_callback: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + break; + } + xsane_back_gtk_set_option(dialog, opt_num, valp, SANE_ACTION_SET_VALUE); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_option_menu_new(GtkWidget *parent, const char *name, char *str_list[], + const char *val, GSGDialogElement * elem, + GtkTooltips *tooltips, const char *desc, SANE_Int settable) +{ + GtkWidget *hbox, *label, *option_menu, *menu, *item; + GSGMenuItem *menu_items; + int i, num_items; + + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 0); + gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0); + + label = gtk_label_new((char *) name); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + + for (num_items = 0; str_list[num_items]; ++num_items); + menu_items = malloc(num_items * sizeof(menu_items[0])); + + menu = gtk_menu_new(); + for (i = 0; i < num_items; ++i) + { + item = gtk_menu_item_new_with_label(_BGT(str_list[i])); + gtk_container_add(GTK_CONTAINER(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_back_gtk_option_menu_callback, menu_items + i); + + gtk_widget_show(item); + + menu_items[i].label = str_list[i]; + menu_items[i].elem = elem; + menu_items[i].index = i; + } + + option_menu = gtk_option_menu_new(); + gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 2); + gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), xsane_back_gtk_option_menu_lookup(menu_items, val)); + xsane_back_gtk_set_tooltip(tooltips, option_menu, desc); + + gtk_widget_show(label); + gtk_widget_show(option_menu); + gtk_widget_show(hbox); + + gtk_widget_set_sensitive(option_menu, settable); + + elem->widget = option_menu; + elem->menu_size = num_items; + elem->menu = menu_items; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_back_gtk_text_entry_callback(GtkWidget *w, gpointer data) +{ + GSGDialogElement *elem = data; + const SANE_Option_Descriptor *opt; + GSGDialog *dialog = elem->dialog; + gchar *text; + int opt_num; + char *buf; + + opt_num = elem - dialog->element; + opt = sane_get_option_descriptor(dialog->dev, opt_num); + + buf = alloca(opt->size); + buf[0] = '\0'; + + text = gtk_entry_get_text(GTK_ENTRY(elem->widget)); + if (text) + { + strncpy(buf, text, opt->size); + } + buf[opt->size - 1] = '\0'; + + xsane_back_gtk_set_option(dialog, opt_num, buf, SANE_ACTION_SET_VALUE); + + if (strcmp(buf, text) != 0) /* the backend modified the option value; update widget: */ + { + gtk_entry_set_text(GTK_ENTRY(elem->widget), buf); + } +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_text_entry_new(GtkWidget * parent, const char *name, const char *val, GSGDialogElement *elem, + GtkTooltips *tooltips, const char *desc, SANE_Int settable) +{ + GtkWidget *hbox, *text, *label; + + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 0); + gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0); + + label = gtk_label_new((char *) name); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + + text = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(text), (char *) val); +/* gtk_box_pack_start(GTK_BOX(hbox), text, FALSE, TRUE, 0); */ /* text entry fixed */ + gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 0); /* text entry sizeable */ + gtk_signal_connect(GTK_OBJECT(text), "changed", (GtkSignalFunc) xsane_back_gtk_text_entry_callback, elem); + xsane_back_gtk_set_tooltip(tooltips, text, desc); + + gtk_widget_show(hbox); + gtk_widget_show(label); + gtk_widget_show(text); + + gtk_widget_set_sensitive(text, settable); + + elem->widget = text; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +GtkWidget *xsane_back_gtk_group_new(GtkWidget *parent, const char * title) +{ + GtkWidget * frame, * vbox; + + frame = gtk_frame_new((char *) title); + gtk_container_set_border_width(GTK_CONTAINER(frame), 4); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0); + + vbox = gtk_vbox_new(FALSE, 4); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 2); + gtk_container_add(GTK_CONTAINER(frame), vbox); + gtk_widget_show(vbox); + return vbox; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ +#if 0 +static GtkWidget* xsane_back_gtk_curve_new(GSGDialog *dialog, int optnum) +{ + const SANE_Option_Descriptor * opt; + gfloat fmin, fmax, val, *vector; + SANE_Word *optval, min, max; + GtkWidget *curve, *gamma; + SANE_Status status; + SANE_Handle dev; + int i, optlen; + + gamma = gtk_gamma_curve_new(); + curve = GTK_GAMMA_CURVE(gamma)->curve; + dev = dialog->dev; + + opt = sane_get_option_descriptor(dev, optnum); + optlen = opt->size / sizeof(SANE_Word); + vector = alloca(optlen * (sizeof(vector[0]) + sizeof(optval[0]))); + optval = (SANE_Word *) (vector + optlen); + + min = max = 0; + switch(opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + min = opt->constraint.range->min; + max = opt->constraint.range->max; + break; + + case SANE_CONSTRAINT_WORD_LIST: + if (opt->constraint.word_list[0] > 1) + { + min = max = opt->constraint.word_list[1]; + for (i = 2; i < opt->constraint.word_list[0]; ++i) + { + if (opt->constraint.word_list[i] < min) + { + min = opt->constraint.word_list[i]; + } + + if (opt->constraint.word_list[i] > max) + { + max = opt->constraint.word_list[i]; + } + } + } + break; + + default: + break; + } + if (min == max) + { + fprintf(stderr, "xsane_back_gtk_curve_new: %s: `%s'\n", WARN_NO_VALUE_CONSTRAINT, opt->name); + fmin = 0; + fmax = 255; + } + else if (opt->type == SANE_TYPE_FIXED) + { + fmin = SANE_UNFIX(min); + fmax = SANE_UNFIX(max); + } + else + { + fmin = min; + fmax = max; + } + gtk_curve_set_range(GTK_CURVE(curve), 0, optlen - 1, fmin, fmax); + + status = sane_control_option(dev, optnum, SANE_ACTION_GET_VALUE, optval, 0); + if (status == SANE_STATUS_GOOD) + { + for (i = 0; i < optlen; ++i) + { + if (opt->type == SANE_TYPE_FIXED) + { + val = SANE_UNFIX(optval[i]); + } + else + { + val = optval[i]; + } + vector[i] = val; + } + gtk_curve_set_vector(GTK_CURVE(curve), optlen, vector); + } + else + { + gtk_widget_set_sensitive(gamma, FALSE); + } + + return gamma; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_back_gtk_vector_new(GSGDialog * dialog, GtkWidget *vbox, int num_vopts, int *vopts) +{ + GtkWidget *notebook, *label, *curve; + const SANE_Option_Descriptor *opt; + int i; + + notebook = gtk_notebook_new(); + gtk_container_set_border_width(GTK_CONTAINER(notebook), 4); + gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + + for (i = 0; i < num_vopts; ++i) + { + opt = sane_get_option_descriptor(dialog->dev, vopts[i]); + + label = gtk_label_new((char *) opt->title); + vbox = gtk_vbox_new(/* homogeneous */ FALSE, 0); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label); + gtk_widget_show(vbox); + gtk_widget_show(label); + + curve = xsane_back_gtk_curve_new(dialog, vopts[i]); + gtk_container_set_border_width(GTK_CONTAINER(curve), 4); + gtk_box_pack_start(GTK_BOX(vbox), curve, TRUE, TRUE, 0); + gtk_widget_show(curve); + + dialog->element[vopts[i]].widget = curve; + } + gtk_widget_show(notebook); +} +#endif +/* ----------------------------------------------------------------------------------------------------------------- */ +#if 0 +static void tooltips_destroy(GSGDialog * dialog) +{ + gtk_object_unref(GTK_OBJECT(dialog->tooltips)); + dialog->tooltips = 0; +} +#endif +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_back_gtk_panel_destroy(GSGDialog * dialog) +{ + const SANE_Option_Descriptor *opt; + GSGDialogElement *elem; + int i, j; + + gtk_widget_destroy(dialog->xsane_hbox); + gtk_widget_destroy(dialog->standard_hbox); + gtk_widget_destroy(dialog->advanced_hbox); + + /* free the menu labels of integer/fix-point word-lists: */ + for (i = 0; i < dialog->num_elements; ++i) + { + if (dialog->element[i].menu) + { + opt = sane_get_option_descriptor(dialog->dev, i); + elem = dialog->element + i; + if (opt->type != SANE_TYPE_STRING) + { + for (j = 0; j < elem->menu_size; ++j) + { + if (elem->menu[j].label) + { + free(elem->menu[j].label); + elem->menu[j].label = 0; + } + } + free(elem->menu); + elem->menu = 0; + } + } + } + memset(dialog->element, 0, dialog->num_elements * sizeof(dialog->element[0])); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +/* When an setting an option changes the dialog, everything may + change: the option titles, the activity-status of the option, its + constraints or what not. Thus, rather than trying to be clever in + detecting what exactly changed, we use a brute-force method of + rebuilding the entire dialog. */ + +static void xsane_back_gtk_panel_rebuild(GSGDialog * dialog) +{ + xsane_back_gtk_panel_destroy(dialog); + xsane_panel_build(dialog); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_refresh_dialog(GSGDialog *dialog) +{ + xsane_back_gtk_panel_rebuild(dialog); + if (dialog->param_change_callback) + { + (*dialog->param_change_callback) (dialog, dialog->param_change_arg); + } +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_update_scan_window(GSGDialog *dialog) +{ + const SANE_Option_Descriptor *opt; + double old_val, new_val; + GSGDialogElement *elem; + SANE_Status status; + SANE_Word word; + int i, optnum; + char str[64]; + + for (i = 0; i < 4; ++i) + { + if (dialog->well_known.coord[i] > 0) + { + optnum = dialog->well_known.coord[i]; + elem = dialog->element + optnum; + opt = sane_get_option_descriptor(dialog->dev, optnum); + + status = sane_control_option(dialog->dev, optnum, SANE_ACTION_GET_VALUE, &word, 0); + if (status != SANE_STATUS_GOOD) + { + continue; /* sliently ignore errors */ + } + + switch(opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + if (opt->type == SANE_TYPE_INT) + { + old_val = GTK_ADJUSTMENT(elem->data)->value; + new_val = word; + GTK_ADJUSTMENT(elem->data)->value = new_val; + } + else + { + old_val = GTK_ADJUSTMENT(elem->data)->value; + new_val = SANE_UNFIX(word); + if (opt->unit == SANE_UNIT_MM) + { + new_val /= preferences.length_unit; + } + GTK_ADJUSTMENT(elem->data)->value = new_val; + } + + if (old_val != new_val) + { + gtk_signal_emit_by_name(GTK_OBJECT(elem->data), "value_changed"); + } + break; + + case SANE_CONSTRAINT_WORD_LIST: + if (opt->type == SANE_TYPE_INT) + { + sprintf(str, "%d", word); + } + else + { + sprintf(str, "%g", SANE_UNFIX(word)); + } + /* XXX maybe we should call this only when the value changes... */ + gtk_option_menu_set_history(GTK_OPTION_MENU(elem->widget), xsane_back_gtk_option_menu_lookup(elem->menu, str)); + break; + + default: + break; + } + } + } +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +/* Ensure sure the device has up-to-date option values. Except for + vectors, all option values are kept current. Vectors are + downloaded into the device during this call. */ +void xsane_back_gtk_sync(GSGDialog *dialog) +{ + const SANE_Option_Descriptor *opt; + gfloat val, *vector; + SANE_Word *optval; + int i, j, optlen; + GtkWidget *curve; + + for (i = 1; i < dialog->num_elements; ++i) + { + opt = sane_get_option_descriptor(dialog->dev, i); + + if (!SANE_OPTION_IS_ACTIVE(opt->cap)) + { + continue; + } + + if (opt->type != SANE_TYPE_INT && opt->type != SANE_TYPE_FIXED) + { + continue; + } + + if (opt->size == sizeof(SANE_Word)) + { + continue; + } + + /* ok, we're dealing with an active vector */ + + optlen = opt->size / sizeof(SANE_Word); + optval = alloca(optlen * sizeof(optval[0])); + vector = alloca(optlen * sizeof(vector[0])); + + curve = GTK_GAMMA_CURVE(dialog->element[i].widget)->curve; + gtk_curve_get_vector(GTK_CURVE(curve), optlen, vector); + for (j = 0; j < optlen; ++j) + { + val = vector[j]; + if (opt->type == SANE_TYPE_FIXED) + { + optval[j] = SANE_FIX(val); + } + else + { + optval[j] = val + 0.5; + } + } + + xsane_back_gtk_set_option(dialog, i, optval, SANE_ACTION_SET_VALUE); + } +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_update_vector(GSGDialog *dialog, int opt_num, SANE_Int *vector) +{ + const SANE_Option_Descriptor *opt; + gfloat val; + SANE_Word *optval; + int j, optlen; + + if (opt_num < 1) + return; /* not defined */ + + opt = sane_get_option_descriptor(dialog->dev, opt_num); + if (!SANE_OPTION_IS_ACTIVE(opt->cap)) + { + return; /* inactive */ + } + + if (opt->type != SANE_TYPE_INT && opt->type != SANE_TYPE_FIXED) + { + return; + } + + if (opt->size == sizeof(SANE_Word)) + { + return; + } + + /* ok, we're dealing with an active vector */ + + optlen = opt->size / sizeof(SANE_Word); + optval = alloca(optlen * sizeof(optval[0])); + for (j = 0; j < optlen; ++j) + { + val = vector[j]; + if (opt->type == SANE_TYPE_FIXED) + { + optval[j] = SANE_FIX(val); + } + else + { + optval[j] = val + 0.5; + } + } + + xsane_back_gtk_set_option(dialog, opt_num, optval, SANE_ACTION_SET_VALUE); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_set_tooltips(GSGDialog *dialog, int enable) +{ + if (!dialog->tooltips) + { + return; + } + + if (enable) + { + gtk_tooltips_enable(dialog->tooltips); + } + else + { + gtk_tooltips_disable(dialog->tooltips); + } +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_set_sensitivity(GSGDialog *dialog, int sensitive) +{ + const SANE_Option_Descriptor *opt; + int i; + + for (i = 0; i < dialog->num_elements; ++i) + { + opt = sane_get_option_descriptor(dialog->dev, i); + + if (!SANE_OPTION_IS_ACTIVE(opt->cap) || !SANE_OPTION_IS_SETTABLE(opt->cap) || + opt->type == SANE_TYPE_GROUP || !dialog->element[i].widget) + { + continue; + } + + if (!(opt->cap & SANE_CAP_ALWAYS_SETTABLE)) + { + gtk_widget_set_sensitive(dialog->element[i].widget, sensitive); + } + } + + if (dialog) + { + if (dialog->xsanemode_widget) + { + gtk_widget_set_sensitive(dialog->xsanemode_widget, sensitive); + } + } + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } +} +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_set_sensitivity(SANE_Int sensitivity) +{ + if (xsane.shell) + { + gtk_widget_set_sensitive(xsane.shell, sensitivity); + gtk_widget_set_sensitive(xsane.standard_options_shell, sensitivity); + gtk_widget_set_sensitive(xsane.advanced_options_shell, sensitivity); + gtk_widget_set_sensitive(xsane.histogram_dialog, sensitivity); + } + + if (xsane.preview) + { + gtk_widget_set_sensitive(xsane.preview->button_box, sensitivity); /* button box at top of window */ +#if 0 + gtk_widget_set_sensitive(xsane.preview->viewport, sensitivity); /* Preview image selection */ +#endif + gtk_widget_set_sensitive(xsane.preview->start, sensitivity); /* Acquire preview button */ + } + + if (xsane.fax_dialog) + { + gtk_widget_set_sensitive(xsane.fax_dialog, sensitivity); + } + + if (dialog) + { + xsane_back_gtk_set_sensitivity(dialog, sensitivity); + } + + while (gtk_events_pending()) /* make sure set_sensitivity is displayed */ + { + gtk_main_iteration(); + } + + xsane.sensitivity = sensitivity; +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +void xsane_back_gtk_destroy_dialog(GSGDialog * dialog) +{ + SANE_Handle dev = dialog->dev; + + xsane_back_gtk_panel_destroy(dialog); + free((void *) dialog->dev_name); + free(dialog->element); + free(dialog); + + sane_close(dev); +} +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_set_window_icon(GtkWidget *gtk_window, gchar **xpm_d) +{ + GdkPixmap *pixmap; + GdkBitmap *mask; + + gtk_widget_realize(gtk_window); + if (xpm_d) + { + pixmap = gdk_pixmap_create_from_xpm_d(gtk_window->window, &mask, xsane.bg_trans, xpm_d); + } + else + { + if (xsane.window_icon_pixmap) + { + pixmap = xsane.window_icon_pixmap; + mask = xsane.window_icon_mask; + } + else + { + pixmap = gdk_pixmap_create_from_xpm_d(gtk_window->window, &mask, xsane.bg_trans, (gchar **) xsane_window_icon_xpm); + } + } + + gdk_window_set_icon(gtk_window->window, 0, pixmap, mask); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-back-gtk.h b/frontend/xsane-back-gtk.h new file mode 100644 index 0000000..af1d55a --- /dev/null +++ b/frontend/xsane-back-gtk.h @@ -0,0 +1,188 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-back-gtk.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifndef xsane_back_gtk_h +#define xsane_back_gtk_h + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#include <sys/types.h> + +#include <gtk/gtk.h> + +#include <sane/config.h> +#include <sane/sane.h> + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +enum +{ + XSANE_PATH_LOCAL_SANE = 0, + XSANE_PATH_SYSTEM, + XSANE_PATH_TMP +}; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +struct GSGDialog; + +typedef void (*GSGCallback) (struct GSGDialog *dialog, void *arg); +typedef GtkWidget *(*XSANECallback) (void); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +typedef enum + { + xsane_back_gtk_TL_X, /* top-left x */ + xsane_back_gtk_TL_Y, /* top-left y */ + xsane_back_gtk_BR_X, /* bottom-right x */ + xsane_back_gtk_BR_Y /* bottom-right y */ + } +GSGCornerCoordinates; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +typedef struct + { + /* The option number of the well-known options. Each of these may + be -1 in case the backend doesn't define the respective option. */ + int scanmode; + int scansource; + int preview; + int dpi; + int dpi_x; + int dpi_y; + int coord[4]; + int gamma_vector; + int gamma_vector_r; + int gamma_vector_g; + int gamma_vector_b; + int bit_depth; + } +GSGWellKnownOptions; + +typedef struct + { + gchar *label; + struct GSGDialogElement *elem; + gint index; + } +GSGMenuItem; + +typedef struct GSGDialogElement + { + struct GSGDialog *dialog; /* wasteful, but is there a better solution? */ + GtkWidget *automatic; /* auto button for options that support this */ + GtkWidget *widget; + GtkObject *data; + int menu_size; /* # of items in menu (if any) */ + GSGMenuItem *menu; + } +GSGDialogElement; + +typedef struct GSGDialog + { + GtkWidget *xsane_window; + GtkWidget *standard_window; + GtkWidget *advanced_window; + GtkWidget *xsane_hbox; + GtkWidget *standard_hbox; + GtkWidget *advanced_hbox; + GtkWidget *xsanemode_widget; + GtkTooltips *tooltips; + GdkColor tooltips_fg; + GdkColor tooltips_bg; + SANE_Handle *dev; + const char *dev_name; + GSGWellKnownOptions well_known; + int num_elements; + GSGDialogElement *element; + gint idle_id; + u_int rebuild : 1; + /* This callback gets invoked whenever the backend notifies us + that the option descriptors have changed. */ + GSGCallback option_reload_callback; + void *option_reload_arg; + /* This callback gets invoked whenever the backend notifies us + that the parameters have changed. */ + GSGCallback param_change_callback; + void *param_change_arg; + XSANECallback update_xsane_callback; + void *update_xsane_arg; + int pixelcolor; + } +GSGDialog; + +extern int xsane_back_gtk_message_dialog_active; + +/* Construct the path and return it in filename_ret (this buffer must + be at least max_len bytes long). The path is constructed as + follows: + + ~/.sane/${PROG_NAME}/${PREFIX}${DEV_NAME}${POSTFIX} + + If PROG_NAME is NULL, an empty string is used and the leading slash + is removed. On success, 0 is returned, on error a negative number and + ERRNO is set to the appropriate value. */ +extern int xsane_back_gtk_make_path(size_t max_len, char *filename_ret, + const char *prog_name, + const char *dir_name, + const char *prefix, const char *dev_name, + const char *postfix, + int local); +extern gint xsane_back_gtk_decision(gchar *title, gchar** icon_xpm, gchar *message, gchar *oktext, gchar *rejecttext, gint wait); +extern void xsane_back_gtk_message(gchar *title, gchar** icon_xpm, gchar *message, gint wait); +extern void xsane_back_gtk_error(gchar *error_message, gint wait); +extern void xsane_back_gtk_warning(gchar *warning_message, gint wait); +extern int xsane_back_gtk_get_filename(const char *label, const char *default_name, + size_t max_len, char *filename, int show_fileopts); + +extern void xsane_back_gtk_sync(GSGDialog *dialog); +extern void xsane_back_gtk_update_vector(GSGDialog *dialog, int opt_num, SANE_Int *vector); +extern void xsane_back_gtk_refresh_dialog(GSGDialog *dialog); +extern void xsane_back_gtk_update_scan_window(GSGDialog *dialog); +extern void xsane_back_gtk_set_advanced(GSGDialog *dialog, int advanced); +extern void xsane_back_gtk_set_tooltips(GSGDialog *dialog, int enable); +extern void xsane_back_gtk_set_tooltip(GtkTooltips *tooltips, GtkWidget *widget, const char *desc); +extern void xsane_back_gtk_set_sensitivity(GSGDialog *dialog, int sensitive); +extern void xsane_set_sensitivity(SANE_Int sensitivity); +extern void xsane_back_gtk_destroy_dialog(GSGDialog *dialog); +extern void xsane_back_gtk_set_option(GSGDialog * dialog, int opt_num, void *val, SANE_Action action); +extern GtkWidget *xsane_back_gtk_group_new (GtkWidget *parent, const char * title); +extern void xsane_back_gtk_button_new(GtkWidget * parent, const char *name, SANE_Word val, + GSGDialogElement *elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable); +extern void xsane_back_gtk_scale_new(GtkWidget * parent, const char *name, gfloat val, + gfloat min, gfloat max, gfloat quant, int automatic, + GSGDialogElement *elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable); +extern void xsane_back_gtk_option_menu_new(GtkWidget *parent, const char *name, char *str_list[], + const char *val, GSGDialogElement * elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable); +extern void xsane_back_gtk_text_entry_new(GtkWidget *parent, const char *name, const char *val, + GSGDialogElement *elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable); +extern void xsane_back_gtk_push_button_callback(GtkWidget * widget, gpointer data); +extern const char *xsane_back_gtk_unit_string(SANE_Unit unit); +void xsane_set_window_icon(GtkWidget *gtk_window, gchar **xpm_d); + +#define xsane_back_gtk_dialog_get_device(dialog) ((dialog)->dev) + +#endif /* gtkglue_h */ diff --git a/frontend/xsane-device-preferences.c b/frontend/xsane-device-preferences.c new file mode 100644 index 0000000..cce2007 --- /dev/null +++ b/frontend/xsane-device-preferences.c @@ -0,0 +1,699 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-device-preferences.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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-rc-io.h" +#include "xsane-front-gtk.h" +#include "xsane-gamma.h" + +/* ---------------------------------------------------------------------------------------------------------------- */ + +#define BITS_PER_LONG (8*sizeof(u_long)) + +#define SET(set, bit) ((set)[(bit)/BITS_PER_LONG] |= (1UL << (bit)%BITS_PER_LONG)) +#define IS_SET(set, bit) (((set)[(bit)/BITS_PER_LONG] & (1UL << (bit)%BITS_PER_LONG)) != 0) + +#define DPOFFSET(field) ((char *) &((Xsane *) 0)->field - (char *) 0) + +/* ---------------------------------------------------------------------------------------------------------------- */ + +static struct +{ + SANE_String name; + void (*codec) (Wire *w, void *p, long offset); + long offset; +} +desc_xsane_device[] = +{ + {"xsane-main-window-x-position", xsane_rc_pref_int, DPOFFSET(shell_posx)}, + {"xsane-main-window-y-position", xsane_rc_pref_int, DPOFFSET(shell_posy)}, + {"xsane-main-window-width", xsane_rc_pref_int, DPOFFSET(shell_width)}, + {"xsane-main-window-height", xsane_rc_pref_int, DPOFFSET(shell_height)}, + {"xsane-standard-options-window-x-position", xsane_rc_pref_int, DPOFFSET(standard_options_shell_posx)}, + {"xsane-standard-options-window-y-position", xsane_rc_pref_int, DPOFFSET(standard_options_shell_posy)}, + {"xsane-advanced-options-window-x-position", xsane_rc_pref_int, DPOFFSET(advanced_options_shell_posx)}, + {"xsane-advanced-options-window-y-position", xsane_rc_pref_int, DPOFFSET(advanced_options_shell_posy)}, + {"xsane-histogram-window-x-position", xsane_rc_pref_int, DPOFFSET(histogram_dialog_posx)}, + {"xsane-histogram-window-y-position", xsane_rc_pref_int, DPOFFSET(histogram_dialog_posy)}, + {"xsane-preview-window-x-position", xsane_rc_pref_int, DPOFFSET(preview_dialog_posx)}, + {"xsane-preview-window-y-position", xsane_rc_pref_int, DPOFFSET(preview_dialog_posy)}, + {"xsane-preview-window-width", xsane_rc_pref_int, DPOFFSET(preview_dialog_width)}, + {"xsane-preview-window-height", xsane_rc_pref_int, DPOFFSET(preview_dialog_height)}, + + {"xsane-gamma", xsane_rc_pref_double, DPOFFSET(gamma)}, + {"xsane-gamma-red", xsane_rc_pref_double, DPOFFSET(gamma_red)}, + {"xsane-gamma-green", xsane_rc_pref_double, DPOFFSET(gamma_green)}, + {"xsane-gamma-blue", xsane_rc_pref_double, DPOFFSET(gamma_blue)}, + + {"xsane-brightness", xsane_rc_pref_double, DPOFFSET(brightness)}, + {"xsane-brightness-red", xsane_rc_pref_double, DPOFFSET(brightness_red)}, + {"xsane-brightness-green", xsane_rc_pref_double, DPOFFSET(brightness_green)}, + {"xsane-brightness-blue", xsane_rc_pref_double, DPOFFSET(brightness_blue)}, + + {"xsane-contrast", xsane_rc_pref_double, DPOFFSET(contrast)}, + {"xsane-contrast-red", xsane_rc_pref_double, DPOFFSET(contrast_red)}, + {"xsane-contrast-green", xsane_rc_pref_double, DPOFFSET(contrast_green)}, + {"xsane-contrast-blue", xsane_rc_pref_double, DPOFFSET(contrast_blue)}, + + {"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)}, +}; + +/* ---------------------------------------------------------------------------------------------------------------- */ + +static void xsane_widget_get_uposition(GtkWidget *gtk_window, gint *x, gint *y) +{ +#ifdef XSANE_BUGGY_WINDOWMANAGER_WINDOW_POSITION + gdk_window_get_root_origin(gtk_window->window, x, y); +#else + gdk_window_get_deskrelative_origin(gtk_window->window, x, y); +#endif +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +static int xsane_device_preferences_load_values(Wire *w, SANE_Handle device) +{ + const SANE_Option_Descriptor *opt; + SANE_Word *word_array; + SANE_String name, str; + u_long *caused_reload; + SANE_Int num_options; + SANE_Status status; + int i, keep_going; + SANE_Word word; + SANE_Int info; + off_t offset; + size_t size; + char *buf; + + lseek(w->io.fd, 1, SEEK_SET); /* rewind file */ + xsane_rc_io_w_flush(w); + + offset = lseek(w->io.fd, 0, SEEK_CUR); /* remeber file position */ + + keep_going = 0; + + sane_control_option(device, 0, SANE_ACTION_GET_VALUE, &num_options, 0); + size = (num_options + BITS_PER_LONG - 1) / BITS_PER_LONG * sizeof(long); + caused_reload = alloca(size); + memset(caused_reload, 0, size); + + while (1) + { + xsane_rc_io_w_space(w, 3); + if (!w->status) + { + xsane_rc_io_w_string(w, &name); + } + + if (w->status == XSANE_EOF) /* eof */ + { + if (keep_going) /* we had a reload otpions? */ + { + lseek(w->io.fd, offset, SEEK_SET); /* rewind file to position of first run */ + xsane_rc_io_w_flush(w); + keep_going = 0; + continue; + } + return 0; + } + else if (w->status) /* error: skip line */ + { + w->status = 0; + xsane_rc_io_w_free(w, (WireCodecFunc) xsane_rc_io_w_string, &name); /* free string memory */ + xsane_rc_io_w_skip_newline(w); /* skip this line */ + continue; + } + + status = SANE_STATUS_GOOD; + info = 0; + for (i = 1; (opt = sane_get_option_descriptor(device, i)); ++i) /* search all options */ + { + if (!opt->name || strcmp(opt->name, name) != 0) /* test if option names are equal */ + { + continue; /* not equal, continue the search */ + } + + if (IS_SET(caused_reload, i)) + { + continue; /* option caused a reload, continue search ??? why? ??? */ + } + + switch (opt->type) + { + case SANE_TYPE_BOOL: + case SANE_TYPE_INT: + case SANE_TYPE_FIXED: + if (opt->size == sizeof(SANE_Word)) + { + xsane_rc_io_w_word(w, &word); + status = sane_control_option(device, i, SANE_ACTION_SET_VALUE, &word, &info); + } + else + { + SANE_Int len; + + xsane_rc_io_w_array(w, &len, (void **) &word_array, (WireCodecFunc) xsane_rc_io_w_word, sizeof(SANE_Word)); + status = sane_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)); + w->direction = WIRE_DECODE; + } + break; + + case SANE_TYPE_STRING: + xsane_rc_io_w_string(w, &str); + buf = malloc(opt->size); + if (!w->status) /* got a string ? */ + { + strncpy(buf, str, opt->size); + buf[opt->size - 1] = '\0'; + xsane_rc_io_w_free(w, (WireCodecFunc) xsane_rc_io_w_string, &str); + status = sane_control_option(device, i, SANE_ACTION_SET_VALUE, buf, &info); + } + break; + + case SANE_TYPE_BUTTON: + case SANE_TYPE_GROUP: + /* nothing to read for button and group */ + break; + } + break; /* option is set: do not continue search */ + } + xsane_rc_io_w_free(w, (WireCodecFunc) xsane_rc_io_w_string, &name); /* free string memory */ + + if (status == SANE_STATUS_GOOD && (info & SANE_INFO_RELOAD_OPTIONS)) + { + SET(caused_reload, i); + keep_going = 1; + } + } + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +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; + size_t str_size = 0; + SANE_String str = 0; + SANE_Word word; + int i; + + for (i = 0; (opt = sane_get_option_descriptor(device, i)); ++i) + { + if ((opt->cap & (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT)) != (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT) || !opt->name) + /* if we can't query AND set the option, don't bother saving it */ + { + continue; + } + + switch (opt->type) + { + case SANE_TYPE_BOOL: + case SANE_TYPE_INT: + case SANE_TYPE_FIXED: + if (opt->size == sizeof(SANE_Word)) + { + if (sane_control_option(device, i, SANE_ACTION_GET_VALUE, &word, 0) != SANE_STATUS_GOOD) + { + continue; + } + xsane_rc_io_w_string(w, (SANE_String *) &opt->name); + xsane_rc_io_w_word(w, &word); + } + else + { + SANE_Int len = opt->size / sizeof(SANE_Word); + + if (opt->size > word_array_size) + { + word_array_size = ((opt->size + 32*sizeof(SANE_Word)) & ~(32*sizeof(SANE_Word) - 1)); + if (word_array) + { + word_array = realloc(word_array, word_array_size); + } + else + { + word_array = malloc(word_array_size); + } + + if (word_array == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return 1; + } + } + + if (sane_control_option(device, i, SANE_ACTION_GET_VALUE, word_array, 0) != SANE_STATUS_GOOD) + { + continue; + } + + 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)); + } + break; + + case SANE_TYPE_STRING: + if (opt->size > str_size) + { + str_size = (opt->size + 1024) & ~1023; + + if (str) + { + str = realloc(str, str_size); + } + else + { + str = malloc(str_size); + } + + if (str == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return 1; + } + } + + if (sane_control_option(device, i, SANE_ACTION_GET_VALUE, str, 0) != SANE_STATUS_GOOD) + { + continue; + } + + xsane_rc_io_w_string(w, (SANE_String *) &opt->name); + xsane_rc_io_w_string(w, &str); + break; + + case SANE_TYPE_BUTTON: + case SANE_TYPE_GROUP: + break; + } + } + + if (word_array) + { + free(word_array); + } + if (str) + { + free(str); + } + + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_device_preferences_load_file(char *filename) +{ + int fd; + char buf[256]; +#if 0 + char *version = 0; +#endif + Wire w; + SANE_String name; + int i; + + /* set geometry and position to standard values */ + xsane.shell_posx = XSANE_SHELL_POS_X; + xsane.shell_posy = XSANE_SHELL_POS_Y; + xsane.shell_width = XSANE_SHELL_WIDTH; + xsane.shell_height = XSANE_SHELL_HEIGHT; + + xsane.standard_options_shell_posx = XSANE_STD_OPTIONS_POS_X; + xsane.standard_options_shell_posy = XSANE_STD_OPTIONS_POS_Y; + + xsane.advanced_options_shell_posx = XSANE_ADV_OPTIONS_POS_X; + xsane.advanced_options_shell_posy = XSANE_ADV_OPTIONS_POS_Y; + + xsane.histogram_dialog_posx = XSANE_HISTOGRAM_POS_X; + xsane.histogram_dialog_posy = XSANE_HISTOGRAM_POS_Y; + + xsane.preview_dialog_posx = XSANE_PREVIEW_POS_X; + xsane.preview_dialog_posy = XSANE_PREVIEW_POS_Y; + xsane.preview_dialog_width = XSANE_PREVIEW_WIDTH; + xsane.preview_dialog_height = XSANE_PREVIEW_HEIGHT; + + 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.enhancement_rgb_default = 1; + xsane.negative = 0; + xsane.show_preview = 1; + + fd = open(filename, O_RDONLY); + if (fd >= 0) + { + /* prepare wire */ + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + xsane_rc_io_w_init(&w); + xsane_rc_io_w_set_dir(&w, WIRE_DECODE); + + xsane_rc_io_w_space(&w, 3); + if (!w.status) + { + xsane_rc_io_w_string(&w, &name); /* get string */ + if (!w.status) + { + if (strcmp(name, "XSANE_DEVICE_RC")) /* no real *.drc file */ + { + w.status = -1; /* no *.drc file => error */ + } + } + } + + if (w.status) + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s\n%s %s", ERR_LOAD_DEVICE_SETTINGS, filename, ERR_NO_DRC_FILE); + xsane_back_gtk_error(buf, TRUE); + close(fd); + return; + } + + xsane_rc_io_w_space(&w, 3); + if (!w.status) + { + xsane_rc_io_w_string(&w, &name); /* get string */ + if (!w.status) + { + if (strcmp(name, xsane.device_set_filename)) + { + snprintf(buf, sizeof(buf), "%s \"%s\"\n" + "%s \"%s\",\n" + "%s \"%s\",\n" + "%s", + TEXT_FILE, filename, + ERR_CREATED_FOR_DEVICE, name, + ERR_USED_FOR_DEVICE, xsane.device_set_filename, + ERR_MAY_CAUSE_PROBLEMS); + if (xsane_back_gtk_decision(ERR_HEADER_WARNING, (gchar **) error_xpm, buf, ERR_BUTTON_OK, BUTTON_CANCEL, TRUE) == FALSE) + { /* cancel */ + close(fd); + return; + } + } + } + } + + if (w.status) + { + /* may be we should pop up a window here */ + close(fd); + return; + } + + +#if 0 +/* add here: read version info */ +#if 0 + while (!feof(file)) + { + fgets(option, sizeof(option), file); /* get option name */ + option[strlen(option)-1] = 0; /* remove cr */ + if (strcmp(option, "\"xsane-version\"") == 0) + { + fgets(option, sizeof(option), file); /* get version */ + option[strlen(option)-1] = 0; /* remove cr */ + len = strlen(option); + if (len) + { + if (option[len-1] == 34) + { + option[len-1] = 0; /* remove " */ + } + } + version = strdup(option+1); + } + else + { + fgets(option, sizeof(option), file); /* skip option */ + } + } +#endif + + + if (version) + { + if (strcmp(version, XSANE_VERSION)) + { + snprintf(buf, sizeof(buf), "File: \"%s\"\n" + "has been saved with xsane-%s,\n" + "this may cause problems!", filename, version); + xsane_back_gtk_warning(buf, TRUE); + } + free(version); + } + else + { + snprintf(buf, sizeof(buf), "File: \"%s\"\n" + "has been saved with xsane before version 0.40,\n" + "this may cause problems!", filename); + xsane_back_gtk_warning(buf, TRUE); + } +#endif + + + + while (1) /* read device dependant xsane options */ + { + xsane_rc_io_w_space(&w, 3); + if (w.status) + { + break; + } + + xsane_rc_io_w_string(&w, &name); + + if (!w.status && name) + { + for (i = 0; i < NELEMS (desc_xsane_device); ++i) + { + if (strcmp(name, desc_xsane_device[i].name) == 0) + { + (*desc_xsane_device[i].codec) (&w, &xsane, desc_xsane_device[i].offset); + break; /* leave for loop */ + } + } + } + w.status = 0; + } + + xsane_device_preferences_load_values(&w, dialog->dev); /* read device preferences */ + close(fd); + + if (dialog->well_known.dpi > 0) + { + const SANE_Option_Descriptor *opt; + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.dpi); + + switch (opt->type) + { + case SANE_TYPE_INT: + { + SANE_Int dpi; + sane_control_option(dialog->dev, dialog->well_known.dpi, SANE_ACTION_GET_VALUE, &dpi, 0); + xsane.resolution = dpi; + } + break; + + case SANE_TYPE_FIXED: + { + SANE_Fixed dpi; + sane_control_option(dialog->dev, dialog->well_known.dpi, SANE_ACTION_GET_VALUE, &dpi, 0); + xsane.resolution = (int) SANE_UNFIX(dpi); + } + break; + + default: + fprintf(stderr, "xsane_pref_load_file: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + return; + } + } + } + + gtk_widget_set_uposition(xsane.shell, xsane.shell_posx, xsane.shell_posy); + gtk_window_set_default_size(GTK_WINDOW(xsane.shell), xsane.shell_width, xsane.shell_height); + gtk_widget_set_uposition(xsane.standard_options_shell, xsane.standard_options_shell_posx, xsane.standard_options_shell_posy); + gtk_widget_set_uposition(xsane.advanced_options_shell, xsane.advanced_options_shell_posx, xsane.advanced_options_shell_posy); + gtk_widget_set_uposition(xsane.histogram_dialog, xsane.histogram_dialog_posx, xsane.histogram_dialog_posy); + gtk_widget_set_uposition(xsane.preview->top, xsane.preview_dialog_posx, xsane.preview_dialog_posy); + gtk_window_set_default_size(GTK_WINDOW(xsane.preview->top), xsane.preview_dialog_width, xsane.preview_dialog_height); + + xsane_refresh_dialog(dialog); + xsane_enhancement_by_gamma(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_device_preferences_restore(void) +{ + char filename[PATH_MAX]; + struct stat st; + + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, 0, xsane.device_set_filename, ".drc", XSANE_PATH_LOCAL_SANE); + + if (stat(filename, &st) >= 0) + { + xsane_device_preferences_load_file(filename); + } + else /* no local sane file, look for system file */ + { + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, 0, xsane.device_set_filename, ".drc", XSANE_PATH_SYSTEM); + xsane_device_preferences_load_file(filename); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_device_preferences_load(void) +{ + char filename[PATH_MAX]; + char windowname[256]; + + xsane_set_sensitivity(FALSE); + + sprintf(windowname, "%s %s %s", prog_name, WINDOW_LOAD_SETTINGS, device_text); + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, 0, xsane.device_set_filename, ".drc", XSANE_PATH_LOCAL_SANE); + xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, FALSE); + xsane_device_preferences_load_file(filename); + xsane_set_sensitivity(TRUE); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#define XSANE_RC_IO_W_STRINGCONST(wire, string) { SANE_String str=string; xsane_rc_io_w_string(wire, &str); } + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_device_preferences_save(GtkWidget *widget, gpointer data) +{ + char filename[PATH_MAX]; + char windowname[256]; + int fd; + Wire w; + int i; + + xsane_set_sensitivity(FALSE); + + sprintf(windowname, "%s %s %s", prog_name, WINDOW_SAVE_SETTINGS, device_text); + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, 0, xsane.device_set_filename, ".drc", XSANE_PATH_LOCAL_SANE); + xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, FALSE); + + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_CREATE_FILE, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + xsane_set_sensitivity(TRUE); + return; + } + + /* prepare wire */ + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + xsane_rc_io_w_init(&w); + xsane_rc_io_w_set_dir(&w, WIRE_ENCODE); + + XSANE_RC_IO_W_STRINGCONST(&w, "XSANE_DEVICE_RC"); + xsane_rc_io_w_string(&w, &xsane.device_set_filename); + + XSANE_RC_IO_W_STRINGCONST(&w, "xsane-version"); + XSANE_RC_IO_W_STRINGCONST(&w, XSANE_VERSION); + + /* make geometry and position values up to date */ + xsane_widget_get_uposition(xsane.shell, &xsane.shell_posx, &xsane.shell_posy); +#if 0 +/* other possibillities: */ + gdk_window_get_deskrelative_origin(xsane.shell->window, &xsane.shell_posx, &xsane.shell_posy); + gdk_window_get_origin(xsane.shell->window, &xsane.shell_posx, &xsane.shell_posy); + gdk_window_get_position(xsane.shell->window, &xsane.shell_posx, &xsane.shell_posy); + gdk_window_get_geometry(xsane.shell->window, ?); +#endif + gdk_window_get_size(xsane.shell->window, &xsane.shell_width, &xsane.shell_height); + gtk_widget_set_uposition(xsane.shell, xsane.shell_posx, xsane.shell_posy); /* geometry used when window closed and opened again */ + gtk_window_set_default_size(GTK_WINDOW(xsane.shell), xsane.shell_width, xsane.shell_height); + + xsane_widget_get_uposition(xsane.standard_options_shell, &xsane.standard_options_shell_posx, &xsane.standard_options_shell_posy); + gtk_widget_set_uposition(xsane.standard_options_shell, xsane.standard_options_shell_posx, xsane.standard_options_shell_posy); + + xsane_widget_get_uposition(xsane.advanced_options_shell, &xsane.advanced_options_shell_posx, &xsane.advanced_options_shell_posy); + gtk_widget_set_uposition(xsane.advanced_options_shell, xsane.advanced_options_shell_posx, xsane.advanced_options_shell_posy); + + xsane_widget_get_uposition(xsane.histogram_dialog, &xsane.histogram_dialog_posx, &xsane.histogram_dialog_posy); + gtk_widget_set_uposition(xsane.histogram_dialog, xsane.histogram_dialog_posx, xsane.histogram_dialog_posy); + + if (xsane.preview) + { + xsane_widget_get_uposition(xsane.preview->top, &xsane.preview_dialog_posx, &xsane.preview_dialog_posy); + gdk_window_get_size(xsane.preview->top->window, &xsane.preview_dialog_width, &xsane.preview_dialog_height); + gtk_widget_set_uposition(xsane.preview->top, xsane.preview_dialog_posx, xsane.preview_dialog_posy); + gtk_window_set_default_size(GTK_WINDOW(xsane.preview->top), xsane.preview_dialog_width, xsane.preview_dialog_height); + } + + xsane_device_preferences_save_values(&w, dialog->dev); + + for (i = 0; i < NELEMS(desc_xsane_device); ++i) /* save device preferences xsane values */ + { + xsane_rc_io_w_string(&w, &desc_xsane_device[i].name); + (*desc_xsane_device[i].codec) (&w, &xsane, desc_xsane_device[i].offset); + } + + xsane_rc_io_w_flush(&w); + close(fd); + + xsane_set_sensitivity(TRUE); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + diff --git a/frontend/xsane-device-preferences.c.old b/frontend/xsane-device-preferences.c.old new file mode 100644 index 0000000..aa4d8b8 --- /dev/null +++ b/frontend/xsane-device-preferences.c.old @@ -0,0 +1,761 @@ + +/* sane - Scanner Access Now Easy. + Copyright (C) 1999 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. */ + +/* ---------------------------------------------------------------------------------------------------------------- */ + +#include "xsane.h" +#include "xsane-rc-io.h" +#include "xsane-front-gtk.h" +#include "xsane-gamma.h" + +/* ---------------------------------------------------------------------------------------------------------------- */ + +#define BITS_PER_LONG (8*sizeof(u_long)) + +#define SET(set, bit) ((set)[(bit)/BITS_PER_LONG] |= (1UL << (bit)%BITS_PER_LONG)) +#define IS_SET(set, bit) (((set)[(bit)/BITS_PER_LONG] & (1UL << (bit)%BITS_PER_LONG)) != 0) + +/* ---------------------------------------------------------------------------------------------------------------- */ + +int xsane_device_preferences_load_values(int fd, SANE_Handle device) +{ + const SANE_Option_Descriptor *opt; + SANE_Word *word_array; + SANE_String name, str; + u_long *caused_reload; + SANE_Int num_options; + SANE_Status status; + int i, keep_going; + SANE_Word word; + SANE_Int info; + off_t offset; + size_t size; + char *buf; + Wire w; + + offset = lseek(fd, 0, SEEK_CUR); + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + xsane_rc_io_w_init(&w); + xsane_rc_io_w_set_dir(&w, WIRE_DECODE); + keep_going = 0; + + sane_control_option(device, 0, SANE_ACTION_GET_VALUE, &num_options, 0); + size = (num_options + BITS_PER_LONG - 1) / BITS_PER_LONG * sizeof(long); + caused_reload = alloca(size); + memset(caused_reload, 0, size); + + while (1) + { + xsane_rc_io_w_space(&w, 3); + + if (!w.status) + { + xsane_rc_io_w_string(&w, &name); + } + + if (w.status) + { + if (keep_going) + { + lseek(fd, offset, SEEK_SET); + xsane_rc_io_w_set_dir(&w, WIRE_DECODE); + keep_going = 0; + continue; + } + return 0; + } + + status = SANE_STATUS_GOOD; + info = 0; + for (i = 1; (opt = sane_get_option_descriptor(device, i)); ++i) + { + if (!opt->name || strcmp(opt->name, name) != 0) + { + continue; + } + + if (IS_SET(caused_reload, i)) + { + continue; + } + + switch (opt->type) + { + case SANE_TYPE_BOOL: + case SANE_TYPE_INT: + case SANE_TYPE_FIXED: + if (opt->size == sizeof(SANE_Word)) + { + xsane_rc_io_w_word(&w, &word); + status = sane_control_option(device, i, SANE_ACTION_SET_VALUE, &word, &info); + } + else + { + SANE_Int len; + + xsane_rc_io_w_array(&w, &len, (void **) &word_array, (WireCodecFunc) xsane_rc_io_w_word, sizeof(SANE_Word)); + status = sane_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)); + w.direction = WIRE_DECODE; + } + break; + + case SANE_TYPE_STRING: + xsane_rc_io_w_string(&w, &str); + buf = malloc(opt->size); + if (!w.status) /* got a string ? */ + { + strncpy(buf, str, opt->size); + buf[opt->size - 1] = '\0'; + xsane_rc_io_w_free(&w, (WireCodecFunc) xsane_rc_io_w_string, &str); + status = sane_control_option(device, i, SANE_ACTION_SET_VALUE, buf, &info); + } + break; + + case SANE_TYPE_BUTTON: + case SANE_TYPE_GROUP: + /* nothing to read for button and group */ + break; + } + break; + } + xsane_rc_io_w_free(&w, (WireCodecFunc) xsane_rc_io_w_string, &name); + + if (status == SANE_STATUS_GOOD && (info & SANE_INFO_RELOAD_OPTIONS)) + { + SET(caused_reload, i); + keep_going = 1; + } + } + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +int xsane_device_preferences_save_values(int fd, SANE_Handle device) +{ + const SANE_Option_Descriptor *opt; + size_t word_array_size = 0; + SANE_Word *word_array = 0; + size_t str_size = 0; + SANE_String str = 0; + SANE_Word word; + Wire w; + int i; + + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + xsane_rc_io_w_init(&w); + xsane_rc_io_w_set_dir(&w, WIRE_ENCODE); + + for (i = 0; (opt = sane_get_option_descriptor(device, i)); ++i) + { + if ((opt->cap & (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT)) != (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT) || !opt->name) + /* if we can't query AND set the option, don't bother saving it */ + { + continue; + } + + switch (opt->type) + { + case SANE_TYPE_BOOL: + case SANE_TYPE_INT: + case SANE_TYPE_FIXED: + if (opt->size == sizeof(SANE_Word)) + { + if (sane_control_option(device, i, SANE_ACTION_GET_VALUE, &word, 0) != SANE_STATUS_GOOD) + { + continue; + } + xsane_rc_io_w_string(&w, (SANE_String *) &opt->name); + xsane_rc_io_w_word(&w, &word); + } + else + { + SANE_Int len = opt->size / sizeof(SANE_Word); + + if (opt->size > word_array_size) + { + word_array_size = ((opt->size + 32*sizeof(SANE_Word)) & ~(32*sizeof(SANE_Word) - 1)); + if (word_array) + { + word_array = realloc(word_array, word_array_size); + } + else + { + word_array = malloc(word_array_size); + } + + if (word_array == 0) + { + /* Malloc failed, so return an error. */ + w.status = ENOMEM; + return 1; + } + } + + if (sane_control_option(device, i, SANE_ACTION_GET_VALUE, word_array, 0) != SANE_STATUS_GOOD) + { + continue; + } + + 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)); + } + break; + + case SANE_TYPE_STRING: + if (opt->size > str_size) + { + str_size = (opt->size + 1024) & ~1023; + + if (str) + { + str = realloc(str, str_size); + } + else + { + str = malloc(str_size); + } + + if (str == 0) + { + /* Malloc failed, so return an error. */ + w.status = ENOMEM; + return 1; + } + } + + if (sane_control_option(device, i, SANE_ACTION_GET_VALUE, str, 0) != SANE_STATUS_GOOD) + { + continue; + } + + xsane_rc_io_w_string(&w, (SANE_String *) &opt->name); + xsane_rc_io_w_string(&w, &str); + break; + + case SANE_TYPE_BUTTON: + case SANE_TYPE_GROUP: + break; + } + } + xsane_rc_io_w_set_dir(&w, WIRE_DECODE); + + if (word_array) + { + free(word_array); + } + if (str) + { + free(str); + } + + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_device_preferences_load_file(char *filename) +{ + int fd; + FILE *file; + char buf[256]; + char option[256]; + char *optionp; + char *version = 0; + int len; + + int main_posx = XSANE_DIALOG_POS_X; + int main_posy = XSANE_DIALOG_POS_Y; + int main_width = XSANE_DIALOG_WIDTH; + int main_height = XSANE_DIALOG_HEIGHT; + + int standard_options_posx = XSANE_DIALOG_POS_X; + int standard_options_posy = XSANE_DIALOG_POS_Y2; + + int advanced_options_posx = XSANE_DIALOG_POS_X2; + int advanced_options_posy = XSANE_DIALOG_POS_Y2; + + int histogram_posx = XSANE_DIALOG_POS_X2; + int histogram_posy = XSANE_DIALOG_POS_Y; + + int preview_posx = 0; + int preview_posy = 0; + int preview_width = 0; + int preview_height = 0; + + file = fopen(filename, "r"); + if (file == 0) /* error ? */ + { + return; + } + + if (!feof(file)) + { + fgets(option, sizeof(option), file); /* get first line */ + option[strlen(option)-1] = 0; /* remove cr */ + + if (strcmp(option, "\"XSANE_DEVICE_RC\"") != 0) /* wrong file format ? */ + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s\n%s %s", ERR_LOAD_DEVICE_SETTINGS, filename, ERR_NO_DRC_FILE); + xsane_back_gtk_error(buf, TRUE); + return; + } + + if (!feof(file)) + { + fgets(option, sizeof(option), file); /* get version */ + option[strlen(option)-1] = 0; /* remove cr */ + len = strlen(option); + if (len) + { + if (option[len-1] == 34) + { + option[len-1] = 0; /* remove " */ + } + } + optionp = option+1; + + if (strcmp(optionp, xsane.device_set_filename)) + { + snprintf(buf, sizeof(buf), "%s \"%s\"\n" + "%s \"%s\",\n" + "%s \"%s\",\n" + "%s", + TEXT_FILE, filename, + ERR_CREATED_FOR_DEVICE, optionp, + ERR_USED_FOR_DEVICE, xsane.device_set_filename, + ERR_MAY_CAUSE_PROBLEMS); + if (xsane_back_gtk_decision(ERR_HEADER_WARNING, buf, ERR_BUTTON_OK, BUTTON_CANCEL, TRUE) == FALSE) + { /* cancel */ + fclose(file); + return; + } + } + } + } + + while (!feof(file)) + { + fgets(option, sizeof(option), file); /* get option name */ + option[strlen(option)-1] = 0; /* remove cr */ + if (strcmp(option, "\"xsane-version\"") == 0) + { + fgets(option, sizeof(option), file); /* get version */ + option[strlen(option)-1] = 0; /* remove cr */ + len = strlen(option); + if (len) + { + if (option[len-1] == 34) + { + option[len-1] = 0; /* remove " */ + } + } + version = strdup(option+1); + } + else if (strcmp(option, "\"xsane-gamma\"") == 0) + { + fscanf(file, "%lf\n", &xsane.gamma); + } + else if (strcmp(option, "\"xsane-gamma-red\"") == 0) + { + fscanf(file, "%lf\n", &xsane.gamma_red); + } + else if (strcmp(option, "\"xsane-gamma-green\"") == 0) + { + fscanf(file, "%lf\n", &xsane.gamma_green); + } + else if (strcmp(option, "\"xsane-gamma-blue\"") == 0) + { + fscanf(file, "%lf\n", &xsane.gamma_blue); + } + else if (strcmp(option, "\"xsane-brightness\"") == 0) + { + fscanf(file, "%lf\n", &xsane.brightness); + } + else if (strcmp(option, "\"xsane-brightness-red\"") == 0) + { + fscanf(file, "%lf\n", &xsane.brightness_red); + } + else if (strcmp(option, "\"xsane-brightness-green\"") == 0) + { + fscanf(file, "%lf\n", &xsane.brightness_green); + } + else if (strcmp(option, "\"xsane-brightness-blue\"") == 0) + { + fscanf(file, "%lf\n", &xsane.brightness_blue); + } + else if (strcmp(option, "\"xsane-contrast\"") == 0) + { + fscanf(file, "%lf\n", &xsane.contrast); + } + else if (strcmp(option, "\"xsane-contrast-red\"") == 0) + { + fscanf(file, "%lf\n", &xsane.contrast_red); + } + else if (strcmp(option, "\"xsane-contrast-green\"") == 0) + { + fscanf(file, "%lf\n", &xsane.contrast_green); + } + else if (strcmp(option, "\"xsane-contrast-blue\"") == 0) + { + fscanf(file, "%lf\n", &xsane.contrast_blue); + } + else if (strcmp(option, "\"xsane-enhancement-rgb-default\"") == 0) + { + fscanf(file, "%d\n", &xsane.enhancement_rgb_default); + } + else if (strcmp(option, "\"xsane-negative\"") == 0) + { + fscanf(file, "%d\n", &xsane.negative); + } + else if (strcmp(option, "\"xsane-show-preview\"") == 0) + { + fscanf(file, "%d\n", &xsane.show_preview); + } + else if (strcmp(option, "\"xsane-main-window-x-position\"") == 0) + { + fscanf(file, "%d\n", &main_posx); + } + else if (strcmp(option, "\"xsane-main-window-y-position\"") == 0) + { + fscanf(file, "%d\n", &main_posy); + } + else if (strcmp(option, "\"xsane-main-window-width\"") == 0) + { + fscanf(file, "%d\n", &main_width); + } + else if (strcmp(option, "\"xsane-main-window-height\"") == 0) + { + fscanf(file, "%d\n", &main_height); + } + else if (strcmp(option, "\"xsane-standard-options-window-x-position\"") == 0) + { + fscanf(file, "%d\n", &standard_options_posx); + } + else if (strcmp(option, "\"xsane-standard-options-window-y-position\"") == 0) + { + fscanf(file, "%d\n", &standard_options_posy); + } + else if (strcmp(option, "\"xsane-advanced-options-window-x-position\"") == 0) + { + fscanf(file, "%d\n", &advanced_options_posx); + } + else if (strcmp(option, "\"xsane-advanced-options-window-y-position\"") == 0) + { + fscanf(file, "%d\n", &advanced_options_posy); + } + else if (strcmp(option, "\"xsane-histogram-window-x-position\"") == 0) + { + fscanf(file, "%d\n", &histogram_posx); + } + else if (strcmp(option, "\"xsane-histogram-window-y-position\"") == 0) + { + fscanf(file, "%d\n", &histogram_posy); + } + else if (strcmp(option, "\"xsane-preview-window-x-position\"") == 0) + { + fscanf(file, "%d\n", &preview_posx); + } + else if (strcmp(option, "\"xsane-preview-window-y-position\"") == 0) + { + fscanf(file, "%d\n", &preview_posy); + } + else if (strcmp(option, "\"xsane-preview-window-width\"") == 0) + { + fscanf(file, "%d\n", &preview_width); + } + else if (strcmp(option, "\"xsane-preview-window-height\"") == 0) + { + fscanf(file, "%d\n", &preview_height); + } + else + { + fgets(option, sizeof(option), file); /* skip option */ + } + } + fclose(file); + +#if 0 + if (version) + { + if (strcmp(version, XSANE_VERSION)) + { + snprintf(buf, sizeof(buf), "File: \"%s\"\n" + "has been saved with xsane-%s,\n" + "this may cause problems!", filename, version); + xsane_back_gtk_warning(buf, TRUE); + } + free(version); + } + else + { + snprintf(buf, sizeof(buf), "File: \"%s\"\n" + "has been saved with xsane before version 0.40,\n" + "this may cause problems!", filename); + xsane_back_gtk_warning(buf, TRUE); + } +#endif + + + gtk_widget_set_uposition(xsane.shell, main_posx, main_posy); + gtk_widget_set_uposition(xsane.standard_options_shell, standard_options_posx, standard_options_posy); + gtk_widget_set_uposition(xsane.advanced_options_shell, advanced_options_posx, advanced_options_posy); + gtk_widget_set_uposition(xsane.histogram_dialog, histogram_posx, histogram_posy); + + if (xsane.preview) + { + gtk_widget_set_uposition(xsane.preview->top, preview_posx, preview_posy); + } + + gtk_window_set_default_size(GTK_WINDOW(xsane.shell), main_width, main_height); + + if (xsane.preview) + { + gtk_window_set_default_size(GTK_WINDOW(xsane.preview->top), preview_width, preview_height); + } + + + fd = open(filename, O_RDONLY); + if (fd < 0) + { + return; + } + xsane_device_preferences_load_values(fd, dialog->dev); + close(fd); + + if (dialog->well_known.dpi > 0) + { + const SANE_Option_Descriptor *opt; + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.dpi); + + switch (opt->type) + { + case SANE_TYPE_INT: + { + SANE_Int dpi; + sane_control_option(dialog->dev, dialog->well_known.dpi, SANE_ACTION_GET_VALUE, &dpi, 0); + xsane.resolution = dpi; + } + break; + + case SANE_TYPE_FIXED: + { + SANE_Fixed dpi; + sane_control_option(dialog->dev, dialog->well_known.dpi, SANE_ACTION_GET_VALUE, &dpi, 0); + xsane.resolution = (int) SANE_UNFIX(dpi); + } + break; + + default: + fprintf(stderr, "xsane_pref_load_file: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + return; + } + } + + xsane_refresh_dialog(dialog); + xsane_enhancement_by_gamma(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_device_preferences_restore(void) +{ + char filename[PATH_MAX]; + + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, 0, xsane.device_set_filename, ".drc"); + xsane_device_preferences_load_file(filename); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_device_preferences_load(void) +{ + char filename[PATH_MAX]; + char windowname[256]; + + xsane_set_sensitivity(FALSE); + + sprintf(windowname, "%s %s %s", prog_name, WINDOW_LOAD_SETTINGS, device_text); + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, 0, xsane.device_set_filename, ".drc"); + xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename); + xsane_device_preferences_load_file(filename); + xsane_set_sensitivity(TRUE); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_device_preferences_save(GtkWidget *widget, gpointer data) +{ + char filename[PATH_MAX]; + char windowname[256]; + int fd; + FILE *file; + int posx, posy, width, height; + + xsane_set_sensitivity(FALSE); + + sprintf(windowname, "%s %s %s", prog_name, WINDOW_SAVE_SETTINGS, device_text); + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, 0, xsane.device_set_filename, ".drc"); + xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename); + + file = fopen(filename, "w"); + if (file == 0) + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_CREATE_FILE, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + xsane_set_sensitivity(TRUE); + return; + } + + fprintf(file, "\"XSANE_DEVICE_RC\"\n"); + fprintf(file, "\"%s\"\n", xsane.device_set_filename); + fclose(file); + + fd = open(filename, O_WRONLY | O_APPEND , 0666); + if (fd < 0) + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_CREATE_FILE, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + xsane_set_sensitivity(TRUE); + return; + } + xsane_device_preferences_save_values(fd, dialog->dev); + close(fd); + + + file = fopen(filename, "a"); + if (file == 0) + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_CREATE_FILE, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + xsane_set_sensitivity(TRUE); + return; + } + + fprintf(file, "\"xsane-version\"\n"); + fprintf(file, "\"" XSANE_VERSION "\"\n"); + fprintf(file, "\"xsane-gamma\"\n"); + fprintf(file, "%f\n", xsane.gamma); + fprintf(file, "\"xsane-gamma-red\"\n"); + fprintf(file, "%f\n", xsane.gamma_red); + fprintf(file, "\"xsane-gamma-green\"\n"); + fprintf(file, "%f\n", xsane.gamma_green); + fprintf(file, "\"xsane-gamma-blue\"\n"); + fprintf(file, "%f\n", xsane.gamma_blue); + + fprintf(file, "\"xsane-brightness\"\n"); + fprintf(file, "%f\n", xsane.brightness); + fprintf(file, "\"xsane-brightness-red\"\n"); + fprintf(file, "%f\n", xsane.brightness_red); + fprintf(file, "\"xsane-brightness-green\"\n"); + fprintf(file, "%f\n", xsane.brightness_green); + fprintf(file, "\"xsane-brightness-blue\"\n"); + fprintf(file, "%f\n", xsane.brightness_blue); + + fprintf(file, "\"xsane-contrast\"\n"); + fprintf(file, "%f\n", xsane.contrast); + fprintf(file, "\"xsane-contrast-red\"\n"); + fprintf(file, "%f\n", xsane.contrast_red); + fprintf(file, "\"xsane-contrast-green\"\n"); + fprintf(file, "%f\n", xsane.contrast_green); + fprintf(file, "\"xsane-contrast-blue\"\n"); + fprintf(file, "%f\n", xsane.contrast_blue); + + fprintf(file, "\"xsane-enhancement-rgb-default\"\n"); + fprintf(file, "%d\n", xsane.enhancement_rgb_default); + + fprintf(file, "\"xsane-negative\"\n"); + fprintf(file, "%d\n", xsane.negative); + + gdk_window_get_root_origin(xsane.shell->window, &posx, &posy); + gdk_window_get_size(xsane.shell->window, &width, &height); + fprintf(file, "\"xsane-main-window-x-position\"\n"); + fprintf(file, "%d\n", posx); + fprintf(file, "\"xsane-main-window-y-position\"\n"); + fprintf(file, "%d\n", posy); + fprintf(file, "\"xsane-main-window-width\"\n"); + fprintf(file, "%d\n", width); + fprintf(file, "\"xsane-main-window-height\"\n"); + fprintf(file, "%d\n", height); + gtk_widget_set_uposition(xsane.shell, posx, posy); /* set default geometry used when window is closed and opened again */ + gtk_window_set_default_size(GTK_WINDOW(xsane.shell), width, height); + + gdk_window_get_root_origin(xsane.standard_options_shell->window, &posx, &posy); + fprintf(file, "\"xsane-standard-options-window-x-position\"\n"); + fprintf(file, "%d\n", posx); + fprintf(file, "\"xsane-standard-options-window-y-position\"\n"); + fprintf(file, "%d\n", posy); + gtk_widget_set_uposition(xsane.standard_options_shell, posx, posy); + + gdk_window_get_root_origin(xsane.advanced_options_shell->window, &posx, &posy); + fprintf(file, "\"xsane-advanced-options-window-x-position\"\n"); + fprintf(file, "%d\n", posx); + fprintf(file, "\"xsane-advanced-options-window-y-position\"\n"); + fprintf(file, "%d\n", posy); + gtk_widget_set_uposition(xsane.advanced_options_shell, posx, posy); + + gdk_window_get_root_origin(xsane.histogram_dialog->window, &posx, &posy); + fprintf(file, "\"xsane-histogram-window-x-position\"\n"); + fprintf(file, "%d\n", posx); + fprintf(file, "\"xsane-histogram-window-y-position\"\n"); + fprintf(file, "%d\n", posy); + gtk_widget_set_uposition(xsane.histogram_dialog, posx, posy); + + fprintf(file, "\"xsane-show-preview\"\n"); + fprintf(file, "%d\n", xsane.show_preview); + + if (xsane.preview) + { + gdk_window_get_root_origin(xsane.preview->top->window, &posx, &posy); + gdk_window_get_size(xsane.preview->top->window, &width, &height); + fprintf(file, "\"xsane-preview-window-x-position\"\n"); + fprintf(file, "%d\n", posx); + fprintf(file, "\"xsane-preview-window-y-position\"\n"); + fprintf(file, "%d\n", posy); + fprintf(file, "\"xsane-preview-window-width\"\n"); + fprintf(file, "%d\n", width); + fprintf(file, "\"xsane-preview-window-height\"\n"); + fprintf(file, "%d\n", height); + gtk_widget_set_uposition(xsane.preview->top, posx, posy); + gtk_window_set_default_size(GTK_WINDOW(xsane.preview->top), width, height); + } + + fclose(file); + + xsane_set_sensitivity(TRUE); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + diff --git a/frontend/xsane-device-preferences.h b/frontend/xsane-device-preferences.h new file mode 100644 index 0000000..a372f2e --- /dev/null +++ b/frontend/xsane-device-preferences.h @@ -0,0 +1,42 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-device-preferences.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifndef xsane_device_preferences_h +#define xsane_device_preferences_h + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#include <sane/sane.h> +#include "xsane.h" + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +extern void xsane_device_preferences_save(GtkWidget *widget, gpointer data); +extern void xsane_device_preferences_restore(void); +extern void xsane_device_preferences_load(void); +extern void xsane_device_preferences_load_file(char *filename); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#endif diff --git a/frontend/xsane-front-gtk.c b/frontend/xsane-front-gtk.c new file mode 100644 index 0000000..fca864e --- /dev/null +++ b/frontend/xsane-front-gtk.c @@ -0,0 +1,798 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-front-gtk.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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-preferences.h" +#include "xsane-preview.h" +#include "xsane-save.h" +#include "xsane-text.h" +#include "xsane-gamma.h" +#include "xsane-setup.h" + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ +#include <png.h> +#include <zlib.h> +#endif +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* forward declarations: */ + +void xsane_get_bounds(const SANE_Option_Descriptor *opt, double *minp, double *maxp); +int xsane_set_resolution(int well_known_option, int resolution); +void xsane_set_all_resolutions(void); +void xsane_define_maximum_output_size(); +void xsane_close_dialog_callback(GtkWidget *widget, gpointer data); +void xsane_authorization_button_callback(GtkWidget *widget, gpointer data); +gint xsane_authorization_callback(SANE_String_Const resource, + SANE_Char username[SANE_MAX_USERNAME_LEN], + SANE_Char password[SANE_MAX_PASSWORD_LEN]); +void xsane_progress_cancel(GtkWidget *widget, gpointer data); +XsaneProgress_t *xsane_progress_new(char *title, char *text, GtkSignalFunc callback, gpointer callback_data); +void xsane_progress_free(XsaneProgress_t *p); +void xsane_progress_update(XsaneProgress_t *p, gfloat newval); +void xsane_toggle_button_new_with_pixmap(GtkWidget *parent, const char *xpm_d[], const char *desc, + int *state, void *xsane_toggle_button_callback); +GtkWidget *xsane_button_new_with_pixmap(GtkWidget *parent, const char *xpm_d[], const char *desc, + void *xsane_button_callback, gpointer data); +void xsane_option_menu_new(GtkWidget *parent, char *str_list[], const char *val, int option_number, const char *desc, + void *option_menu_callback, SANE_Int settable, const gchar *widget_name); +void xsane_option_menu_new_with_pixmap(GtkBox *parent, const char *xpm_d[], const char *desc, + char *str_list[], const char *val, + GtkObject **data, int option, + void *option_menu_callback, SANE_Int settable, const gchar *widget_name); +void xsane_scale_new(GtkBox *parent, char *labeltext, const char *desc, + float min, float max, float quant, float step, float page_step, + int digits, double *val, GtkObject **data, void *xsane_scale_callback, SANE_Int settable); +void xsane_scale_new_with_pixmap(GtkBox *parent, const char *xpm_d[], const char *desc, + float min, float max, float quant, float step, float page_step, int digits, + double *val, GtkObject **data, int option, void *xsane_scale_callback, SANE_Int settable); +void xsane_separator_new(GtkWidget *xsane_parent, int dist); +GtkWidget *xsane_info_table_text_new(GtkWidget *table, gchar *text, int row, int colomn); +GtkWidget *xsane_info_text_new(GtkWidget *parent, gchar *text); +void xsane_refresh_dialog(void *nothing); +void xsane_set_sensitivity(SANE_Int sensitivity); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_get_bounds(const SANE_Option_Descriptor *opt, double *minp, double *maxp) +{ + double min, max; + int i; + + min = -INF; + max = INF; + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + min = opt->constraint.range->min; + max = opt->constraint.range->max; + break; + + case SANE_CONSTRAINT_WORD_LIST: + min = INF; + max = -INF; + + for (i = 1; i <= opt->constraint.word_list[0]; ++i) + { + if (opt->constraint.word_list[i] < min) + { + min = opt->constraint.word_list[i]; + } + if (opt->constraint.word_list[i] > max) + { + max = opt->constraint.word_list[i]; + } + } + break; + + default: + break; + } + + if (opt->type == SANE_TYPE_FIXED) + { + if (min > -INF && min < INF) + { + min = SANE_UNFIX (min); + } + if (max > -INF && max < INF) + { + max = SANE_UNFIX (max); + } + } + *minp = min; + *maxp = max; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +int xsane_set_resolution(int well_known_option, int resolution) +{ + const SANE_Option_Descriptor *opt; + SANE_Word dpi; + SANE_Word bestdpi; + SANE_Word diff; + SANE_Word val; + int items; + int i; + + opt = sane_get_option_descriptor(dialog->dev, well_known_option); + + if (!opt) + { + return -1; /* option does not exits */ + } + + if (opt->constraint_type == SANE_CONSTRAINT_RANGE) + { + switch (opt->type) + { + case SANE_TYPE_INT: + dpi = resolution; + break; + + case SANE_TYPE_FIXED: + dpi = SANE_FIX(resolution); + break; + + default: + fprintf(stderr, "set_resolution: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + return 1; /* error */ + } + } + else if (opt->constraint_type == SANE_CONSTRAINT_WORD_LIST) + { + switch (opt->type) + { + case SANE_TYPE_INT: + dpi = resolution; + break; + + case SANE_TYPE_FIXED: + dpi = SANE_FIX(resolution); + break; + + default: + fprintf(stderr, "set_resolution: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + return 1; /* error */ + } + + items = opt->constraint.word_list[0]; + bestdpi = opt->constraint.word_list[1]; + diff = abs(bestdpi - dpi); + + for (i=1; i<=items; i++) + { + val = opt->constraint.word_list[i]; + if (abs(val - dpi) < diff) + { + diff = abs(val - dpi); + bestdpi = val; + } + } + + if (bestdpi == -1) + { + fprintf(stderr, "set_resolution: %s\n", ERR_FAILED_SET_RESOLUTION); + return -1; + } + dpi = bestdpi; + } + else + { + fprintf(stderr, "set_resolution: %s %d\n", ERR_UNKNOWN_CONSTRAINT_TYPE, opt->constraint_type); + return 1; /* error */ + } + + sane_control_option(dialog->dev, well_known_option, SANE_ACTION_SET_VALUE, &dpi, 0); + return 0; /* everything is ok */ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_set_all_resolutions(void) +{ + xsane_set_resolution(dialog->well_known.dpi_y, xsane.resolution_y); /* set y resolution if possible */ + if (xsane_set_resolution(dialog->well_known.dpi_x, xsane.resolution_x)) /* set x resolution if possible */ + { + xsane_set_resolution(dialog->well_known.dpi, xsane.resolution); /* set common resolution if necessary */ + xsane.resolution_x = xsane.resolution; + xsane.resolution_y = xsane.resolution; + } + + xsane.zoom = xsane.resolution / preferences.printer[preferences.printernr]->resolution; + xsane.zoom_x = xsane.resolution_x / preferences.printer[preferences.printernr]->resolution; + xsane.zoom_y = xsane.resolution_y / preferences.printer[preferences.printernr]->resolution; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_define_maximum_output_size() +{ + const SANE_Option_Descriptor *opt; + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.coord[0]); + + if ( (opt) && (opt->unit== SANE_UNIT_MM) ) + { + if (xsane.xsane_mode == XSANE_COPY) + { + if (preferences.psrotate) /* rotate: landscape */ + { + preview_set_maximum_output_size(xsane.preview, + preferences.printer[preferences.printernr]->height / xsane.zoom_y, + preferences.printer[preferences.printernr]->width / xsane.zoom_x); + } + else /* do not rotate: portrait */ + { + preview_set_maximum_output_size(xsane.preview, + preferences.printer[preferences.printernr]->width / xsane.zoom_x, + preferences.printer[preferences.printernr]->height / xsane.zoom_y); + } + } + else if (xsane.xsane_mode == XSANE_FAX) + { + preview_set_maximum_output_size(xsane.preview, preferences.fax_width, preferences.fax_height); + } + else + { + preview_set_maximum_output_size(xsane.preview, INF, INF); + } + } + else + { + preview_set_maximum_output_size(xsane.preview, INF, INF); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_close_dialog_callback(GtkWidget *widget, gpointer data) +{ + GtkWidget *dialog = data; + + gtk_widget_destroy(dialog); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +int authorization_flag; + +void xsane_authorization_button_callback(GtkWidget *widget, gpointer data) +{ + authorization_flag = (long) data; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +gint xsane_authorization_callback(SANE_String_Const resource, + SANE_Char username[SANE_MAX_USERNAME_LEN], + SANE_Char password[SANE_MAX_PASSWORD_LEN]) +{ + GtkWidget *authorize_dialog, *vbox, *hbox, *button, *label; + GtkWidget *username_widget, *password_widget; + char buf[256]; + char *input; + int len; + + authorize_dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_position(GTK_WINDOW(authorize_dialog), GTK_WIN_POS_CENTER); + gtk_window_set_policy(GTK_WINDOW(authorize_dialog), FALSE, FALSE, FALSE); + gtk_signal_connect(GTK_OBJECT(authorize_dialog), "delete_event", + GTK_SIGNAL_FUNC(xsane_authorization_button_callback), (void *) -1); /* -1 = cancel */ + snprintf(buf, sizeof(buf), "%s %s", prog_name, WINDOW_AUTHORIZE); + gtk_window_set_title(GTK_WINDOW(authorize_dialog), buf); + xsane_set_window_icon(authorize_dialog, 0); + + vbox = gtk_vbox_new(/* not homogeneous */ FALSE, 10); /* y-space between all box items */ + gtk_container_add(GTK_CONTAINER(authorize_dialog), vbox); + gtk_widget_show(vbox); + + snprintf(buf, sizeof(buf), "\n\n%s %s\n", TEXT_AUTHORIZATION_REQ, resource); + label = gtk_label_new(buf); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); /* y-space around authorization text */ + gtk_widget_show(label); + + /* ask for username */ + hbox = gtk_hbox_new(FALSE, 10); /* x-space between label and input filed */ + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* y-space around inner items */ + + label = gtk_label_new(TEXT_USERNAME); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10); /* x-space around label */ + gtk_widget_show(label); + + username_widget = gtk_entry_new_with_max_length(SANE_MAX_USERNAME_LEN-1); + gtk_widget_set_usize(username_widget, 250, 0); + gtk_entry_set_text(GTK_ENTRY(username_widget), ""); + gtk_box_pack_end(GTK_BOX(hbox), username_widget, FALSE, FALSE, 10); /* x-space around input filed */ + gtk_widget_show(username_widget); + gtk_widget_show(hbox); + + + /* ask for password */ + hbox = gtk_hbox_new(FALSE, 10); /* x-space between label and input filed */ + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* y-space around inner items */ + + label = gtk_label_new(TEXT_PASSWORD); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10); /* x-space around label */ + gtk_widget_show(label); + + password_widget = gtk_entry_new_with_max_length(SANE_MAX_PASSWORD_LEN-1); + gtk_entry_set_visibility(GTK_ENTRY(password_widget), FALSE); /* make entered text invisible */ + gtk_widget_set_usize(password_widget, 250, 0); + gtk_entry_set_text(GTK_ENTRY(password_widget), ""); + gtk_box_pack_end(GTK_BOX(hbox), password_widget, FALSE, FALSE, 10); /* x-space around input filed */ + gtk_widget_show(password_widget); + gtk_widget_show(hbox); + + /* buttons */ + hbox = gtk_hbox_new(TRUE, 10); /* x-space between buttons */ + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 10); /* y-space around buttons */ + + button = gtk_button_new_with_label(BUTTON_OK); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_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 OK-button */ + gtk_widget_grab_default(button); + gtk_widget_show(button); + + button = gtk_button_new_with_label(BUTTON_CANCEL); + gtk_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); + + + username[0]=0; + password[0]=0; + + authorization_flag = 0; + + /* wait for ok or cancel */ + while (authorization_flag == 0) + { + gtk_main_iteration(); + } + + if (authorization_flag == 1) /* 1=ok, -1=cancel */ + { + input = gtk_entry_get_text(GTK_ENTRY(username_widget)); + len = strlen(input); + memcpy(username, input, len); + username[len] = 0; + + input = gtk_entry_get_text(GTK_ENTRY(password_widget)); + len = strlen(input); + memcpy(password, input, len); + password[len] = 0; + } + gtk_widget_destroy(authorize_dialog); + return TRUE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_progress_cancel(GtkWidget *widget, gpointer data) +{ + XsaneProgress_t *p = (XsaneProgress_t *) data; + + (*p->callback) (); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +XsaneProgress_t *xsane_progress_new(char *title, char *text, GtkSignalFunc callback, gpointer callback_data) +{ + GtkWidget *button, *label; + GtkBox *vbox, *hbox; + XsaneProgress_t *p; + static const int progress_x = 5; + static const int progress_y = 5; + + p = (XsaneProgress_t *) malloc(sizeof(XsaneProgress_t)); + p->callback = callback; + + p->shell = gtk_dialog_new(); + gtk_widget_set_uposition(p->shell, progress_x, progress_y); + gtk_window_set_title(GTK_WINDOW (p->shell), title); + + xsane_set_window_icon(p->shell, 0); + + vbox = GTK_BOX(GTK_DIALOG(p->shell)->vbox); + hbox = GTK_BOX(GTK_DIALOG(p->shell)->action_area); + + gtk_container_set_border_width(GTK_CONTAINER (vbox), 7); + + label = gtk_label_new(text); + gtk_misc_set_alignment(GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start(vbox, label, FALSE, TRUE, 0); + + p->pbar = gtk_progress_bar_new(); + gtk_widget_set_usize(p->pbar, 200, 20); + gtk_box_pack_start(vbox, p->pbar, TRUE, TRUE, 0); + + button = gtk_toggle_button_new_with_label(BUTTON_CANCEL); + gtk_signal_connect(GTK_OBJECT (button), "clicked", (GtkSignalFunc) xsane_progress_cancel, p); + gtk_box_pack_start(hbox, button, TRUE, TRUE, 0); + + gtk_widget_show(label); + gtk_widget_show(p->pbar); + gtk_widget_show(button); + gtk_widget_show(GTK_WIDGET (p->shell)); + return p; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_progress_free(XsaneProgress_t *p) +{ + if (p) + { + gtk_widget_destroy(p->shell); + free (p); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_progress_update(XsaneProgress_t *p, gfloat newval) +{ + if (p) + { + gtk_progress_bar_update(GTK_PROGRESS_BAR(p->pbar), newval); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_toggle_button_new_with_pixmap(GtkWidget *parent, const char *xpm_d[], const char *desc, + int *state, void *xsane_toggle_button_callback) +{ + GtkWidget *button; + GtkWidget *pixmapwidget; + GdkBitmap *mask; + GdkPixmap *pixmap; + + button = gtk_toggle_button_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, button, desc); + + pixmap = gdk_pixmap_create_from_xpm_d(xsane.histogram_dialog->window, &mask, xsane.bg_trans, (gchar **) xpm_d); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_container_add(GTK_CONTAINER(button), pixmapwidget); + gtk_widget_show(pixmapwidget); + gdk_pixmap_unref(pixmap); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *state); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_toggle_button_callback, (GtkObject *)state); + gtk_box_pack_start(GTK_BOX(parent), button, FALSE, FALSE, 0); + gtk_widget_show(button); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +GtkWidget *xsane_button_new_with_pixmap(GtkWidget *parent, const char *xpm_d[], const char *desc, + void *xsane_button_callback, gpointer data) +{ + GtkWidget *button; + GtkWidget *pixmapwidget; + GdkBitmap *mask; + GdkPixmap *pixmap; + + button = gtk_button_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, button, desc); + + pixmap = gdk_pixmap_create_from_xpm_d(xsane.histogram_dialog->window, &mask, xsane.bg_trans, (gchar **) xpm_d); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_container_add(GTK_CONTAINER(button), pixmapwidget); + gtk_widget_show(pixmapwidget); + gdk_pixmap_unref(pixmap); + + if (xsane_button_callback) + { + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_button_callback, data); + } + gtk_box_pack_start(GTK_BOX(parent), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + return(button); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_option_menu_lookup(GSGMenuItem menu_items[], const char *string) +{ + int i; + + for (i = 0; strcmp(menu_items[i].label, string) != 0; ++i); + return i; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_option_menu_callback(GtkWidget *widget, gpointer data) +{ + GSGMenuItem *menu_item = data; + GSGDialogElement *elem = menu_item->elem; + const SANE_Option_Descriptor *opt; + GSGDialog *dialog = elem->dialog; + int opt_num; + double dval; + SANE_Word val; + void *valp = &val; + + opt_num = elem - dialog->element; + opt = sane_get_option_descriptor(dialog->dev, opt_num); + switch (opt->type) + { + case SANE_TYPE_INT: + sscanf(menu_item->label, "%d", &val); + break; + + case SANE_TYPE_FIXED: + sscanf(menu_item->label, "%lg", &dval); + val = SANE_FIX(dval); + break; + + case SANE_TYPE_STRING: + valp = menu_item->label; + break; + + default: + fprintf(stderr, "xsane_option_menu_callback: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + break; + } + xsane_back_gtk_set_option(dialog, opt_num, valp, SANE_ACTION_SET_VALUE); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_option_menu_new(GtkWidget *parent, char *str_list[], const char *val, int option_number, const char *desc, + void *option_menu_callback, SANE_Int settable, const gchar *widget_name) +{ + GtkWidget *option_menu, *menu, *item; + GSGMenuItem *menu_items; + GSGDialogElement *elem; + int i, num_items; + + elem = dialog->element + option_number; + + for (num_items = 0; str_list[num_items]; ++num_items); + menu_items = malloc(num_items * sizeof(menu_items[0])); + + menu = gtk_menu_new(); + if (widget_name) + { + gtk_widget_set_name(menu, widget_name); + } + + for (i = 0; i < num_items; ++i) + { + item = gtk_menu_item_new_with_label(_BGT(str_list[i])); + gtk_container_add(GTK_CONTAINER(menu), item); + + if (option_menu_callback) + { + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) option_menu_callback, menu_items + i); + } + else + { + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_option_menu_callback, menu_items + i); + } + + gtk_widget_show(item); + + menu_items[i].label = str_list[i]; + menu_items[i].elem = elem; + menu_items[i].index = i; + } + + option_menu = gtk_option_menu_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, option_menu, desc); + gtk_box_pack_end(GTK_BOX(parent), option_menu, FALSE, FALSE, 2); + gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), xsane_option_menu_lookup(menu_items, val)); + + gtk_widget_show(option_menu); + + gtk_widget_set_sensitive(option_menu, settable); + + elem->widget = option_menu; + elem->menu_size = num_items; + elem->menu = menu_items; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_option_menu_new_with_pixmap(GtkBox *parent, const char *xpm_d[], const char *desc, + char *str_list[], const char *val, + GtkObject **data, int option, + void *option_menu_callback, SANE_Int settable, const gchar *widget_name) +{ + GtkWidget *hbox; + GtkWidget *pixmapwidget; + GdkBitmap *mask; + GdkPixmap *pixmap; + + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(parent, hbox, FALSE, FALSE, 0); + + pixmap = gdk_pixmap_create_from_xpm_d(xsane.histogram_dialog->window, &mask, xsane.bg_trans, (gchar **) xpm_d); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); + gtk_widget_show(pixmapwidget); + + xsane_option_menu_new(hbox, str_list, val, option, desc, option_menu_callback, settable, widget_name); + gtk_widget_show(hbox); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_scale_new(GtkBox *parent, char *labeltext, const char *desc, + float min, float max, float quant, float step, float page_step, + int digits, double *val, GtkObject **data, void *xsane_scale_callback, SANE_Int settable) +{ + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *scale; + + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(parent, hbox, FALSE, FALSE, 0); + + label = gtk_label_new(labeltext); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + + *data = gtk_adjustment_new(*val, min, max, quant, step, page_step); + scale = gtk_hscale_new(GTK_ADJUSTMENT(*data)); + xsane_back_gtk_set_tooltip(dialog->tooltips, scale, desc); + gtk_widget_set_usize(scale, 201, 0); /* minimum scale with = 201 pixels */ + gtk_range_set_update_policy(GTK_RANGE(scale), preferences.gtk_update_policy); + /* GTK_UPDATE_CONTINUOUS, GTK_UPDATE_DISCONTINUOUS, GTK_UPDATE_DELAYED */ + gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP); + gtk_scale_set_digits(GTK_SCALE(scale), digits); + gtk_box_pack_end(GTK_BOX(hbox), scale, FALSE, TRUE, 5); /* make scale not sizeable */ + + if (xsane_scale_callback) + { + gtk_signal_connect(*data, "value_changed", (GtkSignalFunc) xsane_scale_callback, val); + } + + gtk_widget_show(label); + gtk_widget_show(scale); + gtk_widget_show(hbox); + + gtk_widget_set_sensitive(scale, settable); + +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_scale_new_with_pixmap(GtkBox *parent, const char *xpm_d[], const char *desc, + float min, float max, float quant, float step, float page_step, int digits, + double *val, GtkObject **data, int option, void *xsane_scale_callback, SANE_Int settable) +{ + GtkWidget *hbox; + GtkWidget *scale; + GtkWidget *pixmapwidget; + GdkBitmap *mask; + GdkPixmap *pixmap; + + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(parent, hbox, FALSE, FALSE, 0); + + pixmap = gdk_pixmap_create_from_xpm_d(xsane.histogram_dialog->window, &mask, xsane.bg_trans, (gchar **) xpm_d); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); + + *data = gtk_adjustment_new(*val, min, max, quant, step, page_step); + scale = gtk_hscale_new(GTK_ADJUSTMENT(*data)); + xsane_back_gtk_set_tooltip(dialog->tooltips, scale, desc); + gtk_widget_set_usize(scale, 201, 0); /* minimum scale with = 201 pxiels */ + gtk_range_set_update_policy(GTK_RANGE(scale), preferences.gtk_update_policy); + /* GTK_UPDATE_CONTINUOUS, GTK_UPDATE_DISCONTINUOUS, GTK_UPDATE_DELAYED */ + gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP); + gtk_scale_set_digits(GTK_SCALE(scale), digits); + gtk_box_pack_end(GTK_BOX(hbox), scale, TRUE, TRUE, 5); /* make scale sizeable */ + + if (xsane_scale_callback) + { + gtk_signal_connect(*data, "value_changed", (GtkSignalFunc) xsane_scale_callback, val); + } + + gtk_widget_show(pixmapwidget); + gtk_widget_show(scale); + gtk_widget_show(hbox); + + gtk_widget_set_sensitive(scale, settable); + + gdk_pixmap_unref(pixmap); + + if ( (dialog) && (option) ) + { + GSGDialogElement *elem; + + elem=dialog->element + option; + elem->data = *data; + elem->widget = scale; + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_separator_new(GtkWidget *xsane_parent, int dist) +{ + GtkWidget *xsane_separator; + + xsane_separator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(xsane_parent), xsane_separator, FALSE, FALSE, dist); + gtk_widget_show(xsane_separator); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +GtkWidget *xsane_info_table_text_new(GtkWidget *table, gchar *text, int row, int colomn) +{ + GtkWidget *hbox, *label; + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_table_attach_defaults(GTK_TABLE(table), hbox, row, row+1, colomn, colomn+1); + gtk_widget_show(hbox); + + label = gtk_label_new(text); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10); + gtk_widget_show(label); + + return label; +} +/* ---------------------------------------------------------------------------------------------------------------------- */ +#if 0 +GtkWidget *xsane_info_text_new(GtkWidget *parent, gchar *text) +{ + GtkWidget *hbox, *label; + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(parent), hbox, TRUE, TRUE, 5); + gtk_widget_show(hbox); + + label = gtk_label_new(text); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10); + gtk_widget_show(label); + + return label; +} +#endif +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_refresh_dialog(void *nothing) +{ + xsane_back_gtk_refresh_dialog(dialog); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-front-gtk.h b/frontend/xsane-front-gtk.h new file mode 100644 index 0000000..600fa28 --- /dev/null +++ b/frontend/xsane-front-gtk.h @@ -0,0 +1,73 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-front-gtk.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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 <sane/sane.h> +#include "xsane.h" + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifndef xsane_front_gtk_h +#define xsane_front_gtk_h + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +extern void xsane_get_bounds(const SANE_Option_Descriptor *opt, double *minp, double *maxp); +extern int xsane_set_resolution(int well_known_option, int resolution); +extern void xsane_set_all_resolutions(void); +extern void xsane_define_maximum_output_size(); +extern void xsane_close_dialog_callback(GtkWidget *widget, gpointer data); +extern void xsane_authorization_button_callback(GtkWidget *widget, gpointer data); +extern gint xsane_authorization_callback(SANE_String_Const resource, + SANE_Char username[SANE_MAX_USERNAME_LEN], + SANE_Char password[SANE_MAX_PASSWORD_LEN]); +extern void xsane_progress_cancel(GtkWidget *widget, gpointer data); +extern XsaneProgress_t *xsane_progress_new(char *title, char *text, GtkSignalFunc callback, gpointer callback_data); +extern void xsane_progress_free(XsaneProgress_t *p); +extern void xsane_progress_update(XsaneProgress_t *p, gfloat newval); +extern void xsane_toggle_button_new_with_pixmap(GtkWidget *parent, const char *xpm_d[], const char *desc, + int *state, void *xsane_toggle_button_callback); +extern GtkWidget *xsane_button_new_with_pixmap(GtkWidget *parent, const char *xpm_d[], const char *desc, + void *xsane_button_callback, gpointer data); +extern void xsane_pixmap_new(GtkWidget *parent, char *title, int width, int height, XsanePixmap *hist); +extern void xsane_option_menu_new(GtkWidget *parent, char *str_list[], const char *val, int option_number, const char *desc, + void *option_menu_callback, SANE_Int settable, const gchar *widget_name); +extern void xsane_option_menu_new_with_pixmap(GtkBox *parent, const char *xpm_d[], const char *desc, + char *str_list[], const char *val, + GtkObject **data, int option, + void *option_menu_callback, SANE_Int settable, const gchar *widget_name); +extern void xsane_scale_new(GtkBox *parent, char *labeltext, const char *desc, + float min, float max, float quant, float step, float xxx, + int digits, double *val, GtkObject **data, void *xsane_scale_callback, SANE_Int settable); +extern void xsane_scale_new_with_pixmap(GtkBox *parent, const char *xpm_d[], const char *desc, + float min, float max, float quant, float step, float xxx, int digits, + double *val, GtkObject **data, int option, void *xsane_scale_callback, SANE_Int settable); +extern void xsane_separator_new(GtkWidget *xsane_parent, int dist); +extern GtkWidget *xsane_info_table_text_new(GtkWidget *table, gchar *text, int row, int colomn); +extern GtkWidget *xsane_info_text_new(GtkWidget *parent, gchar *text); +extern void xsane_refresh_dialog(void *nothing); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#endif + diff --git a/frontend/xsane-gamma.c b/frontend/xsane-gamma.c new file mode 100644 index 0000000..90573f5 --- /dev/null +++ b/frontend/xsane-gamma.c @@ -0,0 +1,1541 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-gamma.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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-front-gtk.h" +#include "xsane-back-gtk.h" +#include "xsane-preferences.h" +#include "xsane-preview.h" +#include "xsane-save.h" + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ +#include <png.h> +#include <zlib.h> +#endif +#endif + + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* forward declarations: */ + +static void xsane_bound_double(double *value, double min, double max); +void xsane_clear_histogram(XsanePixmap *hist); +static void xsane_draw_histogram_with_points(XsanePixmap *hist, int invert, + SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue, + int show_red, int show_green, int show_blue, int show_inten, double scale); +static void xsane_draw_histogram_with_lines(XsanePixmap *hist, int invert, + SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue, + int show_red, int show_green, int show_blue, int show_inten, double scale); +void xsane_draw_slider_level(XsaneSlider *slider); +static void xsane_set_slider(XsaneSlider *slider, double min, double mid, double max); +void xsane_update_slider(XsaneSlider *slider); +void xsane_update_sliders(void); +static gint xsane_slider_callback(GtkWidget *widget, GdkEvent *event, XsaneSlider *slider); +void xsane_create_slider(XsaneSlider *slider); +void xsane_create_histogram(GtkWidget *parent, const char *title, int width, int height, XsanePixmap *hist); +static void xsane_calculate_auto_enhancement(int negative, + SANE_Int *count_raw, SANE_Int *count_raw_red, SANE_Int *count_raw_green, SANE_Int *count_raw_blue); +void xsane_calculate_histogram(void); +void xsane_update_histogram(void); +void xsane_histogram_toggle_button_callback(GtkWidget *widget, gpointer data); +void xsane_create_gamma_curve(SANE_Int *gammadata, int negative, double gamma, + double brightness, double contrast, int numbers, int maxout); +void xsane_update_gamma(void); +static void xsane_enhancement_update(void); +static void xsane_gamma_to_histogram(double *min, double *mid, double *max, + double contrast, double brightness, double gamma); +void xsane_enhancement_by_gamma(void); +void xsane_enhancement_restore_default(void); +void xsane_enhancement_restore(void); +void xsane_enhancement_store(void); +static void xsane_histogram_to_gamma(XsaneSlider *slider, double *contrast, double *brightness, double *gamma); +void xsane_enhancement_by_histogram(void); +static gint xsane_histogram_win_delete(GtkWidget *widget, gpointer data); +void xsane_create_histogram_dialog(const char *devicetext); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_bound_double(double *value, double min, double max) +{ + if (*value < min) + { + *value = min; + } + + if (*value > max) + { + *value = max; + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_clear_histogram(XsanePixmap *hist) +{ + GdkRectangle rect; + + if(hist->pixmap) + { + rect.x=0; + rect.y=0; + rect.width = HIST_WIDTH; + rect.height = HIST_HEIGHT; + + gdk_draw_rectangle(hist->pixmap, xsane.gc_backg, TRUE, 0, 0, HIST_WIDTH, HIST_HEIGHT); + gtk_widget_draw(hist->pixmapwid, &rect); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_draw_histogram_with_points(XsanePixmap *hist, int invert, + SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue, + int show_red, int show_green, int show_blue, int show_inten, double scale) +{ + GdkRectangle rect; + int i; + int inten, red, green, blue; + int colval; + +#define XD 1 +#define YD 2 + + if(hist->pixmap) + { + rect.x=0; + rect.y=0; + rect.width = HIST_WIDTH; + rect.height = HIST_HEIGHT; + + gdk_draw_rectangle(hist->pixmap, xsane.gc_backg, TRUE, 0, 0, HIST_WIDTH, HIST_HEIGHT); + + red = 0; + green = 0; + blue = 0; + + for (i=0; i < HIST_WIDTH; i++) + { + if (invert) + { + colval = 255-i; + } + else + { + colval = i; + } + + inten = show_inten * count[colval] * scale; + + if (xsane.xsane_color) + { + red = show_red * count_red[colval] * scale; + green = show_green * count_green[colval] * scale; + blue = show_blue * count_blue[colval] * scale; + } + + if (inten > HIST_HEIGHT) + inten = HIST_HEIGHT; + + if (red > HIST_HEIGHT) + red = HIST_HEIGHT; + + if (green > HIST_HEIGHT) + green = HIST_HEIGHT; + + if (blue > HIST_HEIGHT) + blue = HIST_HEIGHT; + + + gdk_draw_rectangle(hist->pixmap, xsane.gc_red, TRUE, i, HIST_HEIGHT - red, XD, YD); + gdk_draw_rectangle(hist->pixmap, xsane.gc_green, TRUE, i, HIST_HEIGHT - green, XD, YD); + gdk_draw_rectangle(hist->pixmap, xsane.gc_blue, TRUE, i, HIST_HEIGHT - blue, XD, YD); + gdk_draw_rectangle(hist->pixmap, xsane.gc_black, TRUE, i, HIST_HEIGHT - inten, XD, YD); + } + + gtk_widget_draw(hist->pixmapwid, &rect); + } +} +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_draw_histogram_with_lines(XsanePixmap *hist, int invert, + SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue, + int show_red, int show_green, int show_blue, int show_inten, double scale) +{ + GdkRectangle rect; + int i, j, k; + int inten, red, green, blue; + int inten0=0, red0=0, green0=0, blue0=0; + int val[4]; + int val2[4]; + int color[4]; + int val_swap; + int color_swap; + int colval; + + if (hist->pixmap) + { + rect.x=0; + rect.y=0; + rect.width = HIST_WIDTH; + rect.height = HIST_HEIGHT; + + gdk_draw_rectangle(hist->pixmap, xsane.gc_backg, TRUE, 0, 0, HIST_WIDTH, HIST_HEIGHT); + + red = 0; + green = 0; + blue = 0; + + for (i=0; i < HIST_WIDTH; i++) + { + if (invert) + { + colval = 255-i; + } + else + { + colval = i; + } + + inten = show_inten * count[colval] * scale; + + if (xsane.xsane_color) + { + red = show_red * count_red[colval] * scale; + green = show_green * count_green[colval] * scale; + blue = show_blue * count_blue[colval] * scale; + } + + if (inten > HIST_HEIGHT) + inten = HIST_HEIGHT; + + if (red > HIST_HEIGHT) + red = HIST_HEIGHT; + + if (green > HIST_HEIGHT) + green = HIST_HEIGHT; + + if (blue > HIST_HEIGHT) + blue = HIST_HEIGHT; + + val[0] = red; color[0] = 0; + val[1] = green; color[1] = 1; + val[2] = blue; color[2] = 2; + val[3] = inten; color[3] = 3; + + for (j=0; j<3; j++) + { + for (k=j+1; k<4; k++) + { + if (val[j] < val[k]) + { + val_swap = val[j]; + color_swap = color[j]; + val[j] = val[k]; + color[j] = color[k]; + val[k] = val_swap; + color[k] = color_swap; + } + } + } + val2[0]=val[1]+1; + val2[1]=val[2]+1; + val2[2]=val[3]+1; + val2[3]=0; + + for (j=0; j<4; j++) + { + switch(color[j]) + { + case 0: red0 = val2[j]; + break; + case 1: green0 = val2[j]; + break; + case 2: blue0 = val2[j]; + break; + case 3: inten0 = val2[j]; + break; + } + } + + + gdk_draw_line(hist->pixmap, xsane.gc_red, i, HIST_HEIGHT - red, i, HIST_HEIGHT - red0); + gdk_draw_line(hist->pixmap, xsane.gc_green, i, HIST_HEIGHT - green, i, HIST_HEIGHT - green0); + gdk_draw_line(hist->pixmap, xsane.gc_blue, i, HIST_HEIGHT - blue, i, HIST_HEIGHT - blue0); + gdk_draw_line(hist->pixmap, xsane.gc_black, i, HIST_HEIGHT - inten, i, HIST_HEIGHT - inten0); + } + + gtk_widget_draw(hist->pixmapwid, &rect); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_establish_slider(XsaneSlider *slider) +{ + int x, y, pos, len; + guchar buf[XSANE_SLIDER_WIDTH*3]; + GdkRectangle rect; + + buf[0] = buf[1] = buf[2] = 0; + buf[3+0] = buf[3+1] = buf[3+2]= 0; + + for (x=0; x<256; x++) + { + buf[3*x+0+6] = x * slider->r; + buf[3*x+1+6] = x * slider->g; + buf[3*x+2+6] = x * slider->b; + } + + buf[258*3+0] = 255 * slider->r; + buf[258*3+1] = 255 * slider->g; + buf[258*3+2] = 255 * slider->b; + + buf[259*3+0] = 255 * slider->r; + buf[259*3+1] = 255 * slider->g; + buf[259*3+2] = 255 * slider->b; + + for (y=0; y<XSANE_SLIDER_HEIGHT; y++) + { + pos = slider->position[0]-y/2; + len = y; + if (pos<-2) + { + len = len + pos + 2; + pos = -2; + } + pos = pos * 3 + 6; + + for (x=0; x<=len; x++) + { + if ((x == 0) || (x == len) || (y == XSANE_SLIDER_HEIGHT-1)) + { + buf[pos++] = 255; + buf[pos++] = 255; + buf[pos++] = 255; + } + else + { + buf[pos++] = 0; + buf[pos++] = 0; + buf[pos++] = 0; + } + } + + + pos = slider->position[1]-y/2; + len = y; + pos = pos * 3 + 6; + + for (x=0; x<=len; x++) + { + if ((x == 0) || (x == len) || (y == XSANE_SLIDER_HEIGHT-1)) + { + buf[pos++] = 255; + buf[pos++] = 255; + buf[pos++] = 255; + } + else + { + buf[pos++] = 128; + buf[pos++] = 128; + buf[pos++] = 128; + } + } + + + pos = slider->position[2]-y/2; + len = y; + if (pos+len>257) + { + len = 257 - pos; + } + pos = pos * 3 + 6; + + for (x=0; x<=len; x++) + { + if ((x == 0) || (x == len) || (y == XSANE_SLIDER_HEIGHT-1)) + { + buf[pos++] = 0; + buf[pos++] = 0; + buf[pos++] = 0; + } + else + { + buf[pos++] = 255; + buf[pos++] = 255; + buf[pos++] = 255; + } + } + + gtk_preview_draw_row(GTK_PREVIEW(slider->preview),buf, 0, y, XSANE_SLIDER_WIDTH); + } + + rect.x=0; + rect.y=0; + rect.width = XSANE_SLIDER_WIDTH; + rect.height = XSANE_SLIDER_HEIGHT; + + gtk_widget_draw(slider->preview, &rect); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_draw_slider_level(XsaneSlider *slider) +{ + int i; + guchar buf[XSANE_SLIDER_WIDTH*3]; + GdkRectangle rect; + + buf[0] = buf[1] = buf[2] = 0; + buf[3+0] = buf[3+1] = buf[3+2]= 0; + + for (i=0; i<256; i++) + { + buf[3*i+0+6] = i * slider->r; + buf[3*i+1+6] = i * slider->g; + buf[3*i+2+6] = i * slider->b; + } + + buf[258*3+0] = 255 * slider->r; + buf[258*3+1] = 255 * slider->g; + buf[258*3+2] = 255 * slider->b; + + buf[259*3+0] = 255 * slider->r; + buf[259*3+1] = 255 * slider->g; + buf[259*3+2] = 255 * slider->b; + + for (i=0; i<XSANE_SLIDER_HEIGHT; i++) + { + gtk_preview_draw_row(GTK_PREVIEW(slider->preview),buf, 0, i, XSANE_SLIDER_WIDTH); + } + + rect.x=0; + rect.y=0; + rect.width = XSANE_SLIDER_WIDTH; + rect.height = XSANE_SLIDER_HEIGHT; + + gtk_widget_draw(slider->preview, &rect); +} +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_set_slider(XsaneSlider *slider, double min, double mid, double max) +{ + slider->value[0] = min; + slider->value[1] = mid; + slider->value[2] = max; + + slider->position[0] = min * 2.55; + slider->position[1] = mid * 2.55; + slider->position[2] = max * 2.55; + + xsane_establish_slider(slider); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_update_slider(XsaneSlider *slider) +{ + slider->position[0] = 2.55 * slider->value[0]; + slider->position[1] = 2.55 * slider->value[1]; + slider->position[2] = 2.55 * slider->value[2]; + + xsane_establish_slider(slider); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_update_sliders() +{ + xsane_update_slider(&xsane.slider_gray); + + if ( (xsane.xsane_color) && (!xsane.enhancement_rgb_default) ) + { + xsane_update_slider(&xsane.slider_red); + xsane_update_slider(&xsane.slider_green); + xsane_update_slider(&xsane.slider_blue); + + xsane.slider_gray.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */ + xsane.slider_red.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */ + xsane.slider_green.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */ + xsane.slider_blue.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */ + } + else + { + xsane_draw_slider_level(&xsane.slider_red); /* remove slider */ + xsane_draw_slider_level(&xsane.slider_green); /* remove slider */ + xsane_draw_slider_level(&xsane.slider_blue); /* remove slider */ + + xsane.slider_red.active = XSANE_SLIDER_INACTIVE; /* mark slider inactive */ + 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) + { + xsane_draw_slider_level(&xsane.slider_gray); /* remove slider */ + xsane.slider_gray.active = XSANE_SLIDER_INACTIVE; /* mark slider inactive */ + } + else + { + xsane.slider_gray.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */ + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static gint xsane_slider_callback(GtkWidget *widget, GdkEvent *event, XsaneSlider *slider) +{ + GdkEventButton *button_event; + GdkEventMotion *motion_event; + int distance; + int i = 0; + static int update = FALSE; + static int event_count = 0; + static int x; + + if (slider->active == XSANE_SLIDER_INACTIVE) + { + return 0; + } + + event_count++; + + switch(event->type) + { + case GDK_BUTTON_PRESS: + gtk_grab_add(widget); + button_event = (GdkEventButton *) event; + + distance = G_MAXINT; + for (i=0; i<3; i++) + { + if (fabs(button_event->x - slider->position[i]) < distance) + { + slider->active = i + 1; + distance = fabs(button_event->x - slider->position[i]); + } + } + if (distance<10) + { + x = button_event->x; + update = TRUE; + } + else + { + slider->active = XSANE_SLIDER_ACTIVE; + } + break; + + case GDK_BUTTON_RELEASE: + gtk_grab_remove(widget); + xsane_enhancement_by_histogram(); /* slider->active must be unchanged !!! */ + slider->active = XSANE_SLIDER_ACTIVE; /* ok, now we can reset it */ + break; + + case GDK_MOTION_NOTIFY: + motion_event = (GdkEventMotion *) event; + gdk_window_get_pointer(widget->window, &x, 0, 0); + update = TRUE; + break; + + default: + break; + } + + if (update) + { + update = FALSE; + switch(slider->active) + { + case 1: + slider->value[0] = (x-XSANE_SLIDER_OFFSET) / 2.55; + xsane_bound_double(&slider->value[0], 0.0, slider->value[1] - 1); + break; + + case 2: + slider->value[1] = (x-XSANE_SLIDER_OFFSET) / 2.55; + xsane_bound_double(&slider->value[1], slider->value[0] + 1, slider->value[2] - 1); + break; + + case 3: + slider->value[2] = (x-XSANE_SLIDER_OFFSET) / 2.55; + xsane_bound_double(&slider->value[2], slider->value[1] + 1, 100.0); + break; + + default: + break; + } + xsane_set_slider(slider, slider->value[0], slider->value[1], slider->value[2]); + + if ((preferences.gtk_update_policy == GTK_UPDATE_CONTINUOUS) && (event_count == 1)) + { + xsane_enhancement_by_histogram(); + } + else if ((preferences.gtk_update_policy == GTK_UPDATE_DELAYED) && (event_count == 1)) + { + xsane_enhancement_by_histogram(); + } + } + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + event_count--; + + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_create_slider(XsaneSlider *slider) +{ + slider->preview = gtk_preview_new(GTK_PREVIEW_COLOR); + gtk_preview_size(GTK_PREVIEW(slider->preview), XSANE_SLIDER_WIDTH, XSANE_SLIDER_HEIGHT); + gtk_widget_set_events(slider->preview, XSANE_SLIDER_EVENTS); + gtk_signal_connect(GTK_OBJECT(slider->preview), "event", GTK_SIGNAL_FUNC(xsane_slider_callback), slider); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_create_histogram(GtkWidget *parent, const char *title, int width, int height, XsanePixmap *hist) +{ + GdkBitmap *mask=NULL; + + hist->frame = gtk_frame_new(title); + hist->pixmap = gdk_pixmap_new(xsane.histogram_dialog->window, width, height, -1); + hist->pixmapwid = gtk_pixmap_new(hist->pixmap, mask); + gtk_container_add(GTK_CONTAINER(hist->frame), hist->pixmapwid); + gdk_draw_rectangle(hist->pixmap, xsane.gc_backg, TRUE, 0, 0, width, height); + + gtk_box_pack_start(GTK_BOX(parent), hist->frame, FALSE, FALSE, 2); + gtk_widget_show(hist->pixmapwid); + gtk_widget_show(hist->frame); + } + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_calculate_auto_enhancement(int negative, + SANE_Int *count_raw, SANE_Int *count_raw_red, SANE_Int *count_raw_green, SANE_Int *count_raw_blue) +{ /* calculate white, medium and black values for auto enhancement */ + int limit, limit_mid; + int points, points_mix, points_red, points_green, points_blue; + int min, mid, max; + int min_red, mid_red, max_red; + int min_green, mid_green, max_green; + int min_blue, mid_blue, max_blue; + int val; + int i; + + if (xsane.preview) + { + points = 0; + points_mix = 0; + points_red = 0; + points_green = 0; + points_blue = 0; + + for (i=0; i<256; i++) + { + points += count_raw[i]; + points_mix += 10 * log(1 + count_raw[i] + count_raw_red[i] + count_raw_green[i] + count_raw_blue[i]); + points_red += 10 * log(1 + count_raw_red[i]); + points_green += 10 * log(1 + count_raw_green[i]); + points_blue += 10 * log(1 + count_raw_blue[i]); + } + + limit = 1 + points / 5000; + + /* ----- gray ----- */ + + min = -1; + val = 0; + while ( (val/4 < limit) && (min < 254) ) + { + min++; + val += count_raw[min] + count_raw_red[min] + count_raw_green[min] + count_raw_blue[min]; + } + + max = HIST_WIDTH; + val = 0; + while ( (val/4 < limit) && (max > min + 1) ) + { + max--; + val += count_raw[max] + count_raw_red[max] + count_raw_green[max] + count_raw_blue[max]; + } + + limit_mid = points_mix / 2.0; + + mid = 0; + val = 0; + while ( (val < limit_mid) && (mid < max - 2) ) + { + mid++; + val += 10 * log(1 + count_raw[mid] + count_raw_red[mid] + count_raw_green[mid] + count_raw_blue[mid]); + } + + /* ----- red ----- */ + + min_red = -1; + val = 0; + while ( (val < limit) && (min_red < 254) ) + { + min_red++; + val += count_raw_red[min_red]; + } + + max_red = HIST_WIDTH; + val = 0; + while ( (val < limit) && (max_red > min_red + 1) ) + { + max_red--; + val += count_raw_red[max_red]; + } + + limit_mid = points_red / 2.0; + + mid_red = 0; + val = 0; + while ( (val < limit_mid) && (mid_red < max_red - 2) ) + { + mid_red++; + val += 10 * log(1 + count_raw_red[mid_red]); + } + + /* ----- green ----- */ + + min_green = -1; + val = 0; + while ( (val < limit) && (min_green < 254) ) + { + min_green++; + val += count_raw_green[min_green]; + } + + max_green = HIST_WIDTH; + val = 0; + while ( (val < limit) && (max_green > min_green + 1) ) + { + max_green--; + val += count_raw_green[max_green]; + } + + limit_mid = points_green / 2.0; + + mid_green = 0; + val = 0; + while ( (val < limit_mid) && (mid_green < max_green - 2) ) + { + mid_green++; + val += 10 * log(1 + count_raw_green[mid_green]); + } + + /* ----- blue ----- */ + + min_blue = -1; + val = 0; + while ( (val < limit) && (min_blue < 254) ) + { + min_blue++; + val += count_raw_blue[min_blue]; + } + + max_blue = HIST_WIDTH; + val = 0; + while ( (val < limit) && (max_blue > min_blue + 1) ) + { + max_blue--; + val += count_raw_blue[max_blue]; + } + + limit_mid = points_blue / 2.0; + + mid_blue = 0; + val = 0; + while ( (val < limit_mid) && (mid_blue < max_blue - 2) ) + { + mid_blue++; + val += 10 * log(1 + count_raw_blue[mid_blue]); + } + + if (negative) + { + xsane.auto_white = (255-min)/2.55; + xsane.auto_gray = (255-mid)/2.55; + xsane.auto_black = (255-max)/2.55; + + xsane.auto_white_red = (255-min_red)/2.55; + xsane.auto_gray_red = (255-mid_red)/2.55; + xsane.auto_black_red = (255-max_red)/2.55; + + xsane.auto_white_green = (255-min_green)/2.55; + xsane.auto_gray_green = (255-mid_green)/2.55; + xsane.auto_black_green = (255-max_green)/2.55; + + xsane.auto_white_blue = (255-min_blue)/2.55; + xsane.auto_gray_blue = (255-mid_blue)/2.55; + xsane.auto_black_blue = (255-max_blue)/2.55; + } + else /* positive */ + { + xsane.auto_white = max/2.55; + xsane.auto_gray = mid/2.55; + xsane.auto_black = min/2.55; + + xsane.auto_white_red = max_red/2.55; + xsane.auto_gray_red = mid_red/2.55; + xsane.auto_black_red = min_red/2.55; + + xsane.auto_white_green = max_green/2.55; + xsane.auto_gray_green = mid_green/2.55; + xsane.auto_black_green = min_green/2.55; + + xsane.auto_white_blue = max_blue/2.55; + xsane.auto_gray_blue = mid_blue/2.55; + xsane.auto_black_blue = min_blue/2.55; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_calculate_histogram(void) +{ + SANE_Int *count_raw; + SANE_Int *count_raw_red; + SANE_Int *count_raw_green; + SANE_Int *count_raw_blue; + SANE_Int *count_enh; + SANE_Int *count_enh_red; + SANE_Int *count_enh_green; + SANE_Int *count_enh_blue; + int i; + int maxval_raw; + int maxval_enh; + int maxval; + double scale; + + /* at first reset auto enhancement values */ + + xsane.auto_black = 0.0; + xsane.auto_gray = 50.0; + xsane.auto_white = 100.0; + + xsane.auto_black_red = 0.0; + xsane.auto_gray_red = 50.0; + xsane.auto_white_red = 100.0; + + xsane.auto_black_green = 0.0; + xsane.auto_gray_green = 50.0; + xsane.auto_white_green = 100.0; + + xsane.auto_black_blue = 0.0; + xsane.auto_gray_blue = 50.0; + xsane.auto_white_blue = 100.0; + + if (xsane.preview) /* preview window exists? */ + { + count_raw = calloc(256, sizeof(SANE_Int)); + count_raw_red = calloc(256, sizeof(SANE_Int)); + count_raw_green = calloc(256, sizeof(SANE_Int)); + count_raw_blue = calloc(256, sizeof(SANE_Int)); + count_enh = calloc(256, sizeof(SANE_Int)); + count_enh_red = calloc(256, sizeof(SANE_Int)); + count_enh_green = calloc(256, sizeof(SANE_Int)); + count_enh_blue = calloc(256, sizeof(SANE_Int)); + + preview_calculate_histogram(xsane.preview, count_raw, count_raw_red, count_raw_green, count_raw_blue, + count_enh, count_enh_red, count_enh_green, count_enh_blue); + + if (xsane.param.depth > 1) + { + xsane_calculate_auto_enhancement(xsane.negative, count_raw, count_raw_red, count_raw_green, count_raw_blue); + } + + if (xsane.histogram_log) /* logarithmical display */ + { + for (i=0; i<=255; i++) + { + count_raw[i] = (int) (50*log(1.0 + count_raw[i])); + count_raw_red[i] = (int) (50*log(1.0 + count_raw_red[i])); + count_raw_green[i] = (int) (50*log(1.0 + count_raw_green[i])); + count_raw_blue[i] = (int) (50*log(1.0 + count_raw_blue[i])); + + count_enh[i] = (int) (50*log(1.0 + count_enh[i])); + count_enh_red[i] = (int) (50*log(1.0 + count_enh_red[i])); + count_enh_green[i] = (int) (50*log(1.0 + count_enh_green[i])); + count_enh_blue[i] = (int) (50*log(1.0 + count_enh_blue[i])); + } + } + + maxval_raw = 0; + maxval_enh = 0; + + /* first and last 10 values are not used for calculating maximum value */ + for (i = 10 ; i < HIST_WIDTH - 10; i++) + { + if (count_raw[i] > maxval_raw) { maxval_raw = count_raw[i]; } + if (count_raw_red[i] > maxval_raw) { maxval_raw = count_raw_red[i]; } + if (count_raw_green[i] > maxval_raw) { maxval_raw = count_raw_green[i]; } + if (count_raw_blue[i] > maxval_raw) { maxval_raw = count_raw_blue[i]; } + if (count_enh[i] > maxval_enh) { maxval_enh = count_enh[i]; } + if (count_enh_red[i] > maxval_enh) { maxval_enh = count_enh_red[i]; } + if (count_enh_green[i] > maxval_enh) { maxval_enh = count_enh_green[i]; } + if (count_enh_blue[i] > maxval_enh) { maxval_enh = count_enh_blue[i]; } + } + maxval = ((maxval_enh > maxval_raw) ? maxval_enh : maxval_raw); + scale = 100.0/maxval; + + if (xsane.histogram_lines) + { + xsane_draw_histogram_with_lines(&xsane.histogram_raw, xsane.negative, + count_raw, count_raw_red, count_raw_green, count_raw_blue, + xsane.histogram_red, xsane.histogram_green, xsane.histogram_blue, xsane.histogram_int, scale); + + xsane_draw_histogram_with_lines(&xsane.histogram_enh, 0 /* negative is done by gamma table */, + count_enh, count_enh_red, count_enh_green, count_enh_blue, + xsane.histogram_red, xsane.histogram_green, xsane.histogram_blue, xsane.histogram_int, scale); + } + else + { + xsane_draw_histogram_with_points(&xsane.histogram_raw, xsane.negative, + count_raw, count_raw_red, count_raw_green, count_raw_blue, + xsane.histogram_red, xsane.histogram_green, xsane.histogram_blue, xsane.histogram_int, scale); + + xsane_draw_histogram_with_points(&xsane.histogram_enh, 0 /*negative is done by gamma table */, + count_enh, count_enh_red, count_enh_green, count_enh_blue, + xsane.histogram_red, xsane.histogram_green, xsane.histogram_blue, xsane.histogram_int, scale); + } + + free(count_enh_blue); + free(count_enh_green); + free(count_enh_red); + free(count_enh); + free(count_raw_blue); + free(count_raw_green); + free(count_raw_red); + free(count_raw); + } + else + { + xsane_clear_histogram(&xsane.histogram_raw); + xsane_clear_histogram(&xsane.histogram_enh); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_update_histogram() +{ + if (preferences.show_histogram) + { + xsane_calculate_histogram(); + gtk_widget_show(xsane.histogram_dialog); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_histogram_toggle_button_callback(GtkWidget *widget, gpointer data) +{ + int *valuep = data; + + *valuep = (GTK_TOGGLE_BUTTON(widget)->active != 0); + xsane_update_histogram(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_create_gamma_curve(SANE_Int *gammadata, int negative, double gamma, + double brightness, double contrast, int numbers, int maxout) +{ + int i; + double midin; + double val; + double m; + double b; + int maxin = numbers-1; + + if (contrast < -100.0) + { + contrast = -100.0; + } + + midin = (int)(numbers / 2.0); + + m = 1.0 + contrast/100.0; + b = (1.0 + brightness/100.0) * midin; + + if (negative) + { + for (i=0; i <= maxin; i++) + { + val = ((double) (maxin - i)) - midin; + val = val * m + b; + xsane_bound_double(&val, 0.0, maxin); + + gammadata[i] = 0.5 + maxout * pow( val/maxin, (1.0/gamma) ); + } + } + else /* positive */ + { + for (i=0; i <= maxin; i++) + { + val = ((double) i) - midin; + val = val * m + b; + xsane_bound_double(&val, 0.0, maxin); + + gammadata[i] = 0.5 + maxout * pow( val/maxin, (1.0/gamma) ); + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_update_gamma(void) +{ + if (xsane.preview) + { + if (!xsane.preview_gamma_data_red) + { + xsane.preview_gamma_data_red = malloc(256 * sizeof(SANE_Int)); + xsane.preview_gamma_data_green = malloc(256 * sizeof(SANE_Int)); + xsane.preview_gamma_data_blue = malloc(256 * sizeof(SANE_Int)); + + xsane.histogram_gamma_data_red = malloc(256 * sizeof(SANE_Int)); + xsane.histogram_gamma_data_green = malloc(256 * sizeof(SANE_Int)); + xsane.histogram_gamma_data_blue = malloc(256 * sizeof(SANE_Int)); + } + + xsane_create_gamma_curve(xsane.preview_gamma_data_red, xsane.negative, + xsane.gamma * xsane.gamma_red * preferences.preview_gamma * preferences.preview_gamma_red, + xsane.brightness + xsane.brightness_red, + xsane.contrast + xsane.contrast_red, 256, 255); + + xsane_create_gamma_curve(xsane.preview_gamma_data_green, xsane.negative, + xsane.gamma * xsane.gamma_green * preferences.preview_gamma * preferences.preview_gamma_green, + xsane.brightness + xsane.brightness_green, + xsane.contrast + xsane.contrast_green, 256, 255); + + xsane_create_gamma_curve(xsane.preview_gamma_data_blue, xsane.negative, + xsane.gamma * xsane.gamma_blue * preferences.preview_gamma * preferences.preview_gamma_blue, + xsane.brightness + xsane.brightness_blue, + xsane.contrast + xsane.contrast_blue , 256, 255); + + xsane_create_gamma_curve(xsane.histogram_gamma_data_red, xsane.negative, + xsane.gamma * xsane.gamma_red, + xsane.brightness + xsane.brightness_red, + xsane.contrast + xsane.contrast_red, 256, 255); + + xsane_create_gamma_curve(xsane.histogram_gamma_data_green, xsane.negative, + xsane.gamma * xsane.gamma_green, + xsane.brightness + xsane.brightness_green, + xsane.contrast + xsane.contrast_green, 256, 255); + + xsane_create_gamma_curve(xsane.histogram_gamma_data_blue, xsane.negative, + xsane.gamma * xsane.gamma_blue, + xsane.brightness + xsane.brightness_blue, + xsane.contrast + xsane.contrast_blue , 256, 255); + + preview_gamma_correction(xsane.preview, + xsane.preview_gamma_data_red, xsane.preview_gamma_data_green, xsane.preview_gamma_data_blue, + xsane.histogram_gamma_data_red, xsane.histogram_gamma_data_green, xsane.histogram_gamma_data_blue); + + } + xsane_update_histogram(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_enhancement_update(void) +{ + guint sig_changed=0; + + if (xsane.param.depth == 1) /* lineart? no gamma */ + { + return; + } + + sig_changed = gtk_signal_lookup("changed", GTK_OBJECT_TYPE(xsane.gamma_widget)); + + GTK_ADJUSTMENT(xsane.gamma_widget)->value = xsane.gamma; + GTK_ADJUSTMENT(xsane.brightness_widget)->value = xsane.brightness; + GTK_ADJUSTMENT(xsane.contrast_widget)->value = xsane.contrast; + + if ( (xsane.xsane_color) && (!xsane.enhancement_rgb_default) ) + { + GTK_ADJUSTMENT(xsane.gamma_red_widget)->value = xsane.gamma_red; + GTK_ADJUSTMENT(xsane.gamma_green_widget)->value = xsane.gamma_green; + GTK_ADJUSTMENT(xsane.gamma_blue_widget)->value = xsane.gamma_blue; + + GTK_ADJUSTMENT(xsane.brightness_red_widget)->value = xsane.brightness_red; + GTK_ADJUSTMENT(xsane.brightness_green_widget)->value = xsane.brightness_green; + GTK_ADJUSTMENT(xsane.brightness_blue_widget)->value = xsane.brightness_blue; + + GTK_ADJUSTMENT(xsane.contrast_red_widget)->value = xsane.contrast_red; + GTK_ADJUSTMENT(xsane.contrast_green_widget)->value = xsane.contrast_green; + GTK_ADJUSTMENT(xsane.contrast_blue_widget)->value = xsane.contrast_blue; + + gtk_signal_emit(xsane.gamma_red_widget, sig_changed); + gtk_signal_emit(xsane.gamma_green_widget, sig_changed); + gtk_signal_emit(xsane.gamma_blue_widget, sig_changed); + + gtk_signal_emit(xsane.brightness_red_widget, sig_changed); + gtk_signal_emit(xsane.brightness_green_widget, sig_changed); + gtk_signal_emit(xsane.brightness_blue_widget, sig_changed); + + gtk_signal_emit(xsane.contrast_red_widget, sig_changed); + gtk_signal_emit(xsane.contrast_green_widget, sig_changed); + gtk_signal_emit(xsane.contrast_blue_widget, sig_changed); + + } + + gtk_signal_emit(xsane.gamma_widget, sig_changed); + gtk_signal_emit(xsane.brightness_widget, sig_changed); + gtk_signal_emit(xsane.contrast_widget, sig_changed); + + xsane_update_sliders(); /* update histogram slider */ + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_gamma_to_histogram(double *min, double *mid, double *max, + double contrast, double brightness, double gamma) +{ + double m; + double b; + + m = 1.0 + contrast/100.0; + b = (1.0 + brightness/100.0) * 50.0; + + if (m > 0) + { + *min = 50.0 - b/m; + *mid = (100.0 * pow(0.5, gamma)-b) / m + 50.0; + *max = (100.0-b)/m + 50.0; + } + else + { + *min = 0.0; + *mid = 50.0; + *max = 100.0; + } + + xsane_bound_double(min, 0.0, 99.0); + xsane_bound_double(max, 1.0, 100.0); + xsane_bound_double(mid, *min+1, *max-1); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_enhancement_by_gamma(void) +{ + double min, mid, max; + double contrast, brightness, gamma; + + xsane_gamma_to_histogram(&min, &mid, &max, xsane.contrast, xsane.brightness, xsane.gamma); + + xsane.slider_gray.value[0] = min; + xsane.slider_gray.value[1] = mid; + xsane.slider_gray.value[2] = max; + + + /* red */ + contrast = xsane.contrast + xsane.contrast_red; + brightness = xsane.brightness + xsane.brightness_red; + gamma = xsane.gamma * xsane.gamma_red; + + if (contrast < -100.0) + { + contrast = -100.0; + } + + xsane_gamma_to_histogram(&min, &mid, &max, contrast, brightness, gamma); + + xsane.slider_red.value[0] = min; + xsane.slider_red.value[1] = mid; + xsane.slider_red.value[2] = max; + + + /* green */ + contrast = xsane.contrast + xsane.contrast_green; + brightness = xsane.brightness + xsane.brightness_green; + gamma = xsane.gamma * xsane.gamma_green; + + if (contrast < -100.0) + { + contrast = -100.0; + } + + xsane_gamma_to_histogram(&min, &mid, &max, contrast, brightness, gamma); + + xsane.slider_green.value[0] = min; + xsane.slider_green.value[1] = mid; + xsane.slider_green.value[2] = max; + + + /* blue */ + contrast = xsane.contrast + xsane.contrast_blue; + brightness = xsane.brightness + xsane.brightness_blue; + gamma = xsane.gamma * xsane.gamma_blue; + + if (contrast < -100.0) + { + contrast = -100.0; + } + + xsane_gamma_to_histogram(&min, &mid, &max, + xsane.contrast + xsane.contrast_blue, + xsane.brightness + xsane.brightness_blue, + xsane.gamma * xsane.gamma_blue); + + xsane.slider_blue.value[0] = min; + xsane.slider_blue.value[1] = mid; + xsane.slider_blue.value[2] = max; + + + xsane_enhancement_update(); + xsane_update_gamma(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_enhancement_restore_default() +{ + 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_enhancement_by_gamma(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_enhancement_restore() +{ + xsane.gamma = preferences.xsane_gamma; + xsane.gamma_red = preferences.xsane_gamma_red; + xsane.gamma_green = preferences.xsane_gamma_green; + xsane.gamma_blue = preferences.xsane_gamma_blue; + + xsane.brightness = preferences.xsane_brightness; + xsane.brightness_red = preferences.xsane_brightness_red; + xsane.brightness_green = preferences.xsane_brightness_green; + xsane.brightness_blue = preferences.xsane_brightness_blue; + + xsane.contrast = preferences.xsane_contrast; + xsane.contrast_red = preferences.xsane_contrast_red; + xsane.contrast_green = preferences.xsane_contrast_green; + xsane.contrast_blue = preferences.xsane_contrast_blue; + + xsane.enhancement_rgb_default = preferences.xsane_rgb_default; + xsane.negative = preferences.xsane_negative; + + xsane_refresh_dialog(dialog); + xsane_enhancement_by_gamma(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_enhancement_store() +{ + preferences.xsane_gamma = xsane.gamma; + preferences.xsane_gamma_red = xsane.gamma_red; + preferences.xsane_gamma_green = xsane.gamma_green; + preferences.xsane_gamma_blue = xsane.gamma_blue; + + preferences.xsane_brightness = xsane.brightness; + preferences.xsane_brightness_red = xsane.brightness_red; + preferences.xsane_brightness_green = xsane.brightness_green; + preferences.xsane_brightness_blue = xsane.brightness_blue; + + preferences.xsane_contrast = xsane.contrast; + preferences.xsane_contrast_red = xsane.contrast_red; + preferences.xsane_contrast_green = xsane.contrast_green; + preferences.xsane_contrast_blue = xsane.contrast_blue; + + preferences.xsane_rgb_default = xsane.enhancement_rgb_default; + preferences.xsane_negative = xsane.negative; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_histogram_to_gamma(XsaneSlider *slider, double *contrast, double *brightness, double *gamma) +{ + double mid; + double range; + + *contrast = (10000.0 / (slider->value[2] - slider->value[0]) - 100.0); + *brightness = - (slider->value[0] - 50.0) * (*contrast + 100.0)/50.0 - 100.0; + + mid = slider->value[1] - slider->value[0]; + range = slider->value[2] - slider->value[0]; + + *gamma = log(mid/range) / log(0.5); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_enhancement_by_histogram(void) +{ + double gray_brightness; + double gray_contrast; + double gray_gamma; + double brightness; + double contrast; + double gamma; + + xsane_histogram_to_gamma(&xsane.slider_gray, &gray_contrast, &gray_brightness, &gray_gamma); + + xsane.gamma = gray_gamma; + xsane.brightness = gray_brightness; + xsane.contrast = gray_contrast; + + if ( (xsane.xsane_color) && (!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 */ + { + xsane_histogram_to_gamma(&xsane.slider_red, &contrast, &brightness, &gamma); + + xsane.gamma_red = gamma / gray_gamma; + xsane.brightness_red = brightness - gray_brightness; + xsane.contrast_red = contrast - gray_contrast; + + xsane_histogram_to_gamma(&xsane.slider_green, &contrast, &brightness, &gamma); + + xsane.gamma_green = gamma / gray_gamma; + xsane.brightness_green = brightness - gray_brightness; + xsane.contrast_green = contrast - gray_contrast; + + xsane_histogram_to_gamma(&xsane.slider_blue, &contrast, &brightness, &gamma); + + xsane.gamma_blue = gamma / gray_gamma; + xsane.brightness_blue = brightness - gray_brightness; + xsane.contrast_blue = contrast - gray_contrast; + + xsane_enhancement_update(); + xsane_update_gamma(); + } + else /* gray slider was moved in rgb-mode */ + { + xsane_enhancement_by_gamma(); + } + } + else /* rgb sliders not active */ + { + xsane_enhancement_update(); + xsane_update_gamma(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static gint xsane_histogram_win_delete(GtkWidget *widget, gpointer data) +{ + gtk_widget_hide(widget); + preferences.show_histogram = FALSE; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_histogram_widget), preferences.show_histogram); + return TRUE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_create_histogram_dialog(const char *devicetext) +{ + char windowname[255]; + GtkWidget *xsane_color_hbox; + GtkWidget *xsane_histogram_vbox; + GdkColor color_black; + GdkColor color_red; + GdkColor color_green; + GdkColor color_blue; + GdkColor color_backg; + GdkColormap *colormap; + GtkStyle *style; + + xsane.histogram_dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_policy(GTK_WINDOW(xsane.histogram_dialog), FALSE, FALSE, FALSE); + gtk_widget_set_uposition(xsane.histogram_dialog, XSANE_HISTOGRAM_POS_X, XSANE_HISTOGRAM_POS_Y); + gtk_signal_connect(GTK_OBJECT(xsane.histogram_dialog), "delete_event", GTK_SIGNAL_FUNC(xsane_histogram_win_delete), 0); + sprintf(windowname, "%s %s", WINDOW_HISTOGRAM, devicetext); + gtk_window_set_title(GTK_WINDOW(xsane.histogram_dialog), windowname); + xsane_set_window_icon(xsane.histogram_dialog, 0); + + xsane_histogram_vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(xsane_histogram_vbox), 5); + gtk_container_add(GTK_CONTAINER(xsane.histogram_dialog), xsane_histogram_vbox); + gtk_widget_show(xsane_histogram_vbox); + + + /* set gc for histogram drawing */ + gtk_widget_realize(xsane.histogram_dialog); /* realize dialog to get colors and style */ + + style = gtk_widget_get_style(xsane.histogram_dialog); +/* + style = gtk_rc_get_style(xsane.histogram_dialog); + style = gtk_widget_get_default_style(); +*/ + + xsane.gc_trans = style->bg_gc[GTK_STATE_NORMAL]; + xsane.bg_trans = &style->bg[GTK_STATE_NORMAL]; + + colormap = gdk_window_get_colormap(xsane.histogram_dialog->window); + + xsane.gc_black = gdk_gc_new(xsane.histogram_dialog->window); + color_black.red = 0; + color_black.green = 0; + color_black.blue = 0; + gdk_color_alloc(colormap, &color_black); + gdk_gc_set_foreground(xsane.gc_black, &color_black); + + xsane.gc_red = gdk_gc_new(xsane.histogram_dialog->window); + color_red.red = 40000; + color_red.green = 10000; + color_red.blue = 10000; + gdk_color_alloc(colormap, &color_red); + gdk_gc_set_foreground(xsane.gc_red, &color_red); + + xsane.gc_green = gdk_gc_new(xsane.histogram_dialog->window); + color_green.red = 10000; + color_green.green = 40000; + color_green.blue = 10000; + gdk_color_alloc(colormap, &color_green); + gdk_gc_set_foreground(xsane.gc_green, &color_green); + + xsane.gc_blue = gdk_gc_new(xsane.histogram_dialog->window); + color_blue.red = 10000; + color_blue.green = 10000; + color_blue.blue = 40000; + gdk_color_alloc(colormap, &color_blue); + gdk_gc_set_foreground(xsane.gc_blue, &color_blue); + + xsane.gc_backg = gdk_gc_new(xsane.histogram_dialog->window); + color_backg.red = 50000; + color_backg.green = 50000; + color_backg.blue = 50000; + gdk_color_alloc(colormap, &color_backg); + gdk_gc_set_foreground(xsane.gc_backg, &color_backg); + + + /* add histogram images and sliders */ + + xsane_create_histogram(xsane_histogram_vbox, FRAME_RAW_IMAGE, 256, 100, &(xsane.histogram_raw)); + + xsane_separator_new(xsane_histogram_vbox, 0); + + xsane.slider_gray.r = 1; + xsane.slider_gray.g = 1; + xsane.slider_gray.b = 1; + xsane.slider_gray.active = XSANE_SLIDER_ACTIVE; + xsane_create_slider(&xsane.slider_gray); + gtk_box_pack_start(GTK_BOX(xsane_histogram_vbox), xsane.slider_gray.preview, FALSE, FALSE, 0); + gtk_widget_show(xsane.slider_gray.preview); + gtk_widget_realize(xsane.slider_gray.preview); + + xsane_separator_new(xsane_histogram_vbox, 0); + + xsane.slider_red.r = 1; + xsane.slider_red.g = 0; + xsane.slider_red.b = 0; + xsane.slider_red.active = XSANE_SLIDER_ACTIVE; + xsane_create_slider(&xsane.slider_red); + gtk_box_pack_start(GTK_BOX(xsane_histogram_vbox), xsane.slider_red.preview, FALSE, FALSE, 0); + gtk_widget_show(xsane.slider_red.preview); + gtk_widget_realize(xsane.slider_red.preview); + + xsane_separator_new(xsane_histogram_vbox, 0); + + xsane.slider_green.r = 0; + xsane.slider_green.g = 1; + xsane.slider_green.b = 0; + xsane.slider_green.active = XSANE_SLIDER_ACTIVE; + xsane_create_slider(&xsane.slider_green); + gtk_box_pack_start(GTK_BOX(xsane_histogram_vbox), xsane.slider_green.preview, FALSE, FALSE, 0); + gtk_widget_show(xsane.slider_green.preview); + gtk_widget_realize(xsane.slider_green.preview); + + xsane_separator_new(xsane_histogram_vbox, 0); + + xsane.slider_blue.r = 0; + xsane.slider_blue.g = 0; + xsane.slider_blue.b = 1; + xsane.slider_blue.active = XSANE_SLIDER_ACTIVE; + xsane_create_slider(&xsane.slider_blue); + gtk_box_pack_start(GTK_BOX(xsane_histogram_vbox), xsane.slider_blue.preview, FALSE, FALSE, 0); + gtk_widget_show(xsane.slider_blue.preview); + gtk_widget_realize(xsane.slider_blue.preview); + + xsane_draw_slider_level(&xsane.slider_gray); + xsane_draw_slider_level(&xsane.slider_red); + xsane_draw_slider_level(&xsane.slider_green); + xsane_draw_slider_level(&xsane.slider_blue); + + xsane_separator_new(xsane_histogram_vbox, 0); + + xsane_create_histogram(xsane_histogram_vbox, FRAME_ENHANCED_IMAGE, 256, 100, &(xsane.histogram_enh)); + + xsane_color_hbox = gtk_hbox_new(TRUE, 5); + gtk_container_set_border_width(GTK_CONTAINER(xsane_color_hbox), 5); + gtk_container_add(GTK_CONTAINER(xsane_histogram_vbox), xsane_color_hbox); + gtk_widget_show(xsane_color_hbox); + + xsane_toggle_button_new_with_pixmap(xsane_color_hbox, intensity_xpm, DESC_HIST_INTENSITY, + &xsane.histogram_int, xsane_histogram_toggle_button_callback); + xsane_toggle_button_new_with_pixmap(xsane_color_hbox, red_xpm, DESC_HIST_RED, + &xsane.histogram_red, xsane_histogram_toggle_button_callback); + xsane_toggle_button_new_with_pixmap(xsane_color_hbox, green_xpm, DESC_HIST_GREEN, + &xsane.histogram_green, xsane_histogram_toggle_button_callback); + xsane_toggle_button_new_with_pixmap(xsane_color_hbox, blue_xpm, DESC_HIST_BLUE, + &xsane.histogram_blue, xsane_histogram_toggle_button_callback); + xsane_toggle_button_new_with_pixmap(xsane_color_hbox, pixel_xpm, DESC_HIST_PIXEL, + &xsane.histogram_lines, xsane_histogram_toggle_button_callback); + xsane_toggle_button_new_with_pixmap(xsane_color_hbox, log_xpm, DESC_HIST_LOG, + &xsane.histogram_log, xsane_histogram_toggle_button_callback); + + gtk_widget_show(xsane_color_hbox); + +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + diff --git a/frontend/xsane-gamma.h b/frontend/xsane-gamma.h new file mode 100644 index 0000000..ed70175 --- /dev/null +++ b/frontend/xsane-gamma.h @@ -0,0 +1,48 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-gamma.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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 <sane/sane.h> + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +extern void xsane_clear_histogram(XsanePixmap *hist); +extern void xsane_draw_slider_level(XsaneSlider *slider); +extern void xsane_update_slider(XsaneSlider *slider); +extern void xsane_update_sliders(void); +extern void xsane_create_slider(XsaneSlider *slider); +extern void xsane_create_histogram(GtkWidget *parent, const char *title, int width, int height, XsanePixmap *hist); +extern void xsane_calculate_histogram(void); +extern void xsane_update_histogram(void); +extern void xsane_histogram_toggle_button_callback(GtkWidget *widget, gpointer data); +extern void xsane_create_gamma_curve(SANE_Int *gammadata, int negative, double gamma, + double brightness, double contrast, int numbers, int maxout); +extern void xsane_update_gamma(void); +extern void xsane_enhancement_by_gamma(void); +extern void xsane_enhancement_restore_default(void); +extern void xsane_enhancement_restore(void); +extern void xsane_enhancement_store(void); +extern void xsane_enhancement_by_histogram(void); +extern void xsane_create_histogram_dialog(const char *devicetext); + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-icons.c b/frontend/xsane-icons.c new file mode 100644 index 0000000..3165ab6 --- /dev/null +++ b/frontend/xsane-icons.c @@ -0,0 +1,1751 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-icons.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* --------------------------------------------------- */ + +const char *xsane_window_icon_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 14 16 6 1", +/* color */ +" none", +"b c #2020e0", +"w c #eeeeee", +"x c #fff098", +"y c #f0e890", +"z c #e8d880", +/* pixel */ +" xxyyyyy ", +" xyyyyyyyyyyz ", +"xyyyyzzyyyyyyz", +"xyxz zyyz", +"xxy yyz", +" yyyy yy ", +" zyyyyz yyy ", +" zzzz yxz", +" zbbbbz yyz", +" x zbbwwbbz yy", +"xy zbbwwbbz yy", +"xyy zbbbbz xyy", +"xyyy zzzz xyyz", +"xyyyyyyyyyyyz ", +" zyyyyyyyyz ", +" zzzzzzz " +}; + +/* --------------------------------------------------- */ + +const char *error_xpm[] = +{ +"40 40 6 1", +" c None", +". c #FE0809", +"+ c #FDFDFC", +"@ c #E5D5D6", +"# c #E1A09F", +"$ c #FE8081", +" #@@++++@@# ", +" #@++++++++++++@# ", +" #+++@#$......$$@+++# ", +" #+++#..............#+++# ", +" #++#..................@++# ", +" @++$....................$++@ ", +" @+@........................++@ ", +" #+@$.........................@+# ", +" #++...........................$++# ", +" ++$.....@+...............++....$++ ", +" #+#.....+++@.............+++@....#+# ", +" ++.....$+++++...........@++++$....++ ", +" #+#......#++++@.........+++++#.....#+# ", +" @+........#+++++.......@++++$.......+@ ", +" +@.........$++++@.....+++++#........++ ", +"#+$..........#+++++...@++++$.........$+#", +"@+$...........$+++++$@++++#..........$+@", +"@+.............#+++++++++$............+@", +"++..............$+++++++#.............++", +"++...............#+++++#..............++", +"++...............++++++@..............++", +"++..............@++++++++.............++", +"@+.............+++++@++++@............+@", +"@+$...........@++++#.#+++++..........$+@", +"#+$..........+++++$...$++++@.........$+#", +" +@.........@++++#.....#+++++........@+ ", +" @+........+++++$.......$++++@.......+@ ", +" #+#......@++++#.........#+++++.....#+# ", +" ++.....#++++#...........$++++$....++ ", +" @+#.....$++$.............#++$....#+# ", +" ++$.....#$...............$#....$++ ", +" #++............................++# ", +" #++..........................++# ", +" @++........................++@ ", +" @++$....................$++@ ", +" #++#..................#++# ", +" #+++#..............#+++# ", +" #+++@$$......$$++++# ", +" #+++++++++++++@# ", +" #@@++++@@# " +}; + +/* --------------------------------------------------- */ + +const char *warning_xpm[] = +{ +"40 40 4 1", +" c None", +". c #FFFFFF", +"+ c #FFFA00", +"@ c #000000", +" ", +" .. ", +" .. ", +" .++. ", +" .++. ", +" .++++. ", +" .++++. ", +" .++++++. ", +" .++++++. ", +" .++++++++. ", +" .++++++++. ", +" .++++++++++. ", +" .++++@@++++. ", +" .++++@@@@++++. ", +" .+++@@@@@@+++. ", +" .++++@@@@@@++++. ", +" .+++@@@@@@@@+++. ", +" .++++@@@@@@@@++++. ", +" .++++@@@@@@@@++++. ", +" .++++++@@@@@@++++++. ", +" .++++++@@@@@@++++++. ", +" .+++++++@@@@@@+++++++. ", +" .+++++++@@@@@@+++++++. ", +" .+++++++++@@@@+++++++++. ", +" .+++++++++@@@@+++++++++. ", +" .++++++++++@@@@++++++++++. ", +" .+++++++++++@@+++++++++++. ", +" .++++++++++++++++++++++++++. ", +" .++++++++++++++++++++++++++. ", +" .++++++++++++++++++++++++++++. ", +" .+++++++++++++@@+++++++++++++. ", +" .+++++++++++++@@@@+++++++++++++. ", +" .+++++++++++++@@@@+++++++++++++. ", +" .+++++++++++++++@@+++++++++++++++. ", +" .++++++++++++++++++++++++++++++++. ", +" .++++++++++++++++++++++++++++++++++. ", +" .++++++++++++++++++++++++++++++++++. ", +" ..++++++++++++++++++++++++++++++++++.. ", +" ...................................... ", +"........................................" +}; + +/* --------------------------------------------------- */ + +const char *file_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +"* c #000000", +". c #707070", +"- c #e0e0e0", +" none", +/* pixels */ +" ", +" ................ ", +" .*............*. ", +" .*............*. ", +" ................ ", +" ................ ", +" ................ ", +" ................ ", +" ................ ", +" ................ ", +" ................ ", +" ................ ", +" ....--------.... ", +" ....-...----.... ", +" ....-...----.... ", +" ....-...----.... ", +" ....-...----.... ", +" ............... ", +" ", +" " +}; + +/* --------------------------------------------------- */ + +const char *fax_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +"* c #000000", +". c #ffffff", +"- c #e0e0e0", +" none", +/* pixels */ +" ", +" ", +" ", +" .*********** ", +" ..*.........* ", +" ...*..**.*.*.* ", +" ****.........* ", +" *............* ", +" *...*...***..* ", +" *............* ", +" *.*.*.**.**..* ", +" *............* ", +" *..*....*..*.* ", +" *............* ", +" *.**..*....*.* ", +" *............* ", +" ************** ", +" ", +" ", +" " +}; + +/* --------------------------------------------------- */ + +const char *faxreceiver_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +"* c #000000", +"- c #e0e0e0", +" none", +/* pixels */ +" ", +" ********* ", +" *****-----* ", +" ****--------* ", +" ****-----***-* ", +" ****----*----* ", +" ***-------**--* ", +" ***------------* ", +" **--------------* ", +" **------------*** ", +" **-----------* ", +" **----------* ", +" *-------*---* ", +" *--------*** ", +" *----------* ", +" *----------* ", +" *----------* ", +" *---------* ", +" *------*** ", +" *----* ", +}; + +/* --------------------------------------------------- */ + +const char *colormode_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 20 20 7 1", +/* colors */ +". c #000000", +"# c #0000ff", +"a c #00ff00", +"b c #7f7f7f", +"d c #ff0000", +"e c #ffffff", +" none", +/* pixels */ +" ", +" eeeee ", +" eeeee...... ", +" eeeee......ddddddd ", +" eeeee......ddddddd ", +" eeeee......ddddddd ", +" eeeee......ddddddd ", +" eeeeebbbbbbddddddd ", +" eeeeebbbbbbddddddd ", +" .....bbbbbbaaaaaaa ", +" .....bbbbbbaaaaaaa ", +" .....bbbbbbaaaaaaa ", +" .....eeeeeeaaaaaaa ", +" .....eeeeeeaaaaaaa ", +" .....eeeeee####### ", +" .....eeeeee####### ", +" .....eeeeee####### ", +" eeeeee####### ", +" ####### ", +" " +}; + +/* --------------------------------------------------- */ + +const char *Gamma_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 2 1", +/* colors */ +". c #000000", +" none", +/* pixels */ +" ", +" ", +" ............. ", +" ... .. ", +" .. .. ", +" .. . ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .... ", +" ........ ", +" " +}; + +/* --------------------------------------------------- */ + +const char *Gamma_red_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 2 1", +/* colors */ +". c #ff0000", +" none", +/* pixels */ +" ", +" ", +" ", +" ............. ", +" ... .. ", +" .. .. ", +" .. . ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .... ", +" ........ ", +}; + +/* --------------------------------------------------- */ + +const char *Gamma_green_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 2 1", +/* colors */ +". c #00ff00", +" none", +/* pixels */ +" ", +" ", +" ", +" ............. ", +" ... .. ", +" .. .. ", +" .. . ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .... ", +" ........ ", +}; + +/* --------------------------------------------------- */ + +const char *Gamma_blue_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 2 1", +/* colors */ +". c #0000ff", +" none", +/* pixels */ +" ", +" ", +" ", +" ............. ", +" ... .. ", +" .. .. ", +" .. . ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .... ", +" ........ ", +}; + +/* --------------------------------------------------- */ + +const char *brightness_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +/* pixels */ +" ", +" ", +" ", +" . ", +" . ", +" . ", +" . ... . ", +" . .aaa. . ", +" .aaaaa. ", +" .aaaaaaa. ", +" .aaaaaaaaa. ", +" ....aaaaaaaaa.... ", +" .aaaaaaaaa. ", +" .aaaaaaa. ", +" .aaaaa. ", +" . .aaa. . ", +" . ... . ", +" . ", +" . ", +" . ", +}; + +/* --------------------------------------------------- */ + +const char *brightness_red_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ff0000", +/* pixels */ +" ", +" ", +" ", +" . ", +" . ", +" . ", +" . ... . ", +" . .aaa. . ", +" .aaaaa. ", +" .aaaaaaa. ", +" .aaaaaaaaa. ", +" ....aaaaaaaaa.... ", +" .aaaaaaaaa. ", +" .aaaaaaa. ", +" .aaaaa. ", +" . .aaa. . ", +" . ... . ", +" . ", +" . ", +" . ", +}; + +/* --------------------------------------------------- */ + +const char *brightness_green_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #00ff00", +/* pixels */ +" ", +" ", +" ", +" . ", +" . ", +" . ", +" . ... . ", +" . .aaa. . ", +" .aaaaa. ", +" .aaaaaaa. ", +" .aaaaaaaaa. ", +" ....aaaaaaaaa.... ", +" .aaaaaaaaa. ", +" .aaaaaaa. ", +" .aaaaa. ", +" . .aaa. . ", +" . ... . ", +" . ", +" . ", +" . ", +}; + +const char *brightness_blue_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #0000ff", +/* pixels */ +" ", +" ", +" ", +" . ", +" . ", +" . ", +" . ... . ", +" . .aaa. . ", +" .aaaaa. ", +" .aaaaaaa. ", +" .aaaaaaaaa. ", +" ....aaaaaaaaa.... ", +" .aaaaaaaaa. ", +" .aaaaaaa. ", +" .aaaaa. ", +" . .aaa. . ", +" . ... . ", +" . ", +" . ", +" . ", +}; + +/* --------------------------------------------------- */ + +const char *contrast_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +/* pixels */ +" ", +" ", +" ", +" ..... ", +" .....aa.. ", +" ......aaaa.. ", +" .......aaaaa. ", +" ........aaaaaa. ", +" ........aaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" ........aaaaaa. ", +" ........aaaaaa. ", +" .......aaaaa. ", +" ......aaaa.. ", +" .....aa.. ", +" ..... ", +}; + +/* --------------------------------------------------- */ + +const char *contrast_red_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ff0000", +/* pixels */ +" ", +" ", +" ", +" ..... ", +" .....aa.. ", +" ......aaaa.. ", +" .......aaaaa. ", +" ........aaaaaa. ", +" ........aaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" ........aaaaaa. ", +" ........aaaaaa. ", +" .......aaaaa. ", +" ......aaaa.. ", +" .....aa.. ", +" ..... ", +}; + +/* --------------------------------------------------- */ + +const char *contrast_green_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #00ff00", +/* pixels */ +" ", +" ", +" ", +" ..... ", +" .....aa.. ", +" ......aaaa.. ", +" .......aaaaa. ", +" ........aaaaaa. ", +" ........aaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" ........aaaaaa. ", +" ........aaaaaa. ", +" .......aaaaa. ", +" ......aaaa.. ", +" .....aa.. ", +" ..... ", +}; + +/* --------------------------------------------------- */ + +const char *contrast_blue_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #0000ff", +/* pixels */ +" ", +" ", +" ", +" ..... ", +" .....aa.. ", +" ......aaaa.. ", +" .......aaaaa. ", +" ........aaaaaa. ", +" ........aaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" .........aaaaaaa. ", +" ........aaaaaa. ", +" ........aaaaaa. ", +" .......aaaaa. ", +" ......aaaa.. ", +" .....aa.. ", +" ..... ", +}; + +/* --------------------------------------------------- */ + +const char *rgb_default_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 6 1", +/* colors */ +" none", +"w c #ffffff", +"k c #000000", +"r c #ff0000", +"g c #00ff00", +"b c #0000ff", +/* pixels */ +" ", +" rr gg kk bb ", +" rr gg kk bb ", +" rr gg kk bb ", +" rr gg kk bb ", +" rr gg kk bb ", +" rr gg kk bb ", +" r g k b ", +" r g k b ", +" r g k b ", +" rg k b ", +" rg k b ", +" rgkkb ", +" kk ", +" kk ", +" kk ", +" kk ", +" kk ", +" kk ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *negative_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 16 1", +/* colors */ +" none", +"W c #b0b0b0", +"r c #a01010", +"g c #20a010", +"b c #0020a0", +"c c #10a0a0", +"m c #a000a0", +"y c #a0a000", +"W c #ffffff", +"R c #ff0000", +"G c #00ff00", +"B c #0000ff", +"C c #00ffff", +"M c #ff00ff", +"Y c #ffff00", +"k c #000000", +/* pixels */ +" ", +" YYYYYYYYYYYYYYYYYk ", +" kkYYYYYYYYYkkCCbkB ", +" kkkYYYYYYkkkkCCkBB ", +" YYYYYYYYYYCCCCkRRB ", +" YYYYYkkYYYYCCkRWWW ", +" YYYYYYYYYYYYkRRBWW ", +" YYkkYYYYYYkkWBBBBB ", +" YkkYYYYYYkkWWWBBBB ", +" YYYYYYYYYkBBBBBBBB ", +" MMMMMMMMkGGGGGGGGG ", +" MMMMMMMkGGGGGGGGGG ", +" MMMGMMkGGGGGGGgGGG ", +" MMMCMkGGGGGGGGGgGG ", +" MBMMkgGGRGGGGGGGGG ", +" MMMkGGgGGGGGGGGgGG ", +" MMkGGGGGgGGGGgGGGG ", +" MkGGGGGGGgGGGGGGgG ", +" kGGGGGGGGGGGGGGGGG ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *enhance_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 16 1", +/* colors */ +" none", +"w c #b0b0b0", +"r c #a01010", +"g c #20a010", +"b c #0020a0", +"c c #10a0a0", +"m c #a000a0", +"y c #a0a000", +"W c #ffffff", +"R c #ff0000", +"G c #00ff00", +"B c #0000ff", +"C c #00ffff", +"M c #ff00ff", +"Y c #ffff00", +"k c #000000", +/* pixels */ +" ", +" bbbbbbbbbbbbbbbbbk ", +" wwbbbbbbbbbwwrrbkB ", +" wwwbbbbbbwwwwrrkBB ", +" bbbbbbbbbbrrrrkRRB ", +" bbbbbwwbbbbrrkRWWW ", +" bbbbbbbbbbbbkRRBWW ", +" bbwwbbbbbbwkBBBBBB ", +" bwwbbbbbbbkBWBBBBB ", +" bbbbbbbbbkBBBBBBBB ", +" ggggggggkGGGGGGGGG ", +" gggmgggkGGGGGGGGGG ", +" gggrggkGGGGGGGgGGG ", +" gggggkGGGGGGGGGgGG ", +" gyggkgGGRGGGGGGGGG ", +" gggkGGgGGGGGGGGgGG ", +" ggkGGGGGgGGGGgGGGG ", +" gkGGGGGGGgGGGGGGgG ", +" kGGGGGGGGGGGGGGGGG ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *store_enhancement_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 5 1", +/* colors */ +"* c #000000", +". c #606060", +"- c #e0e0e0", +"w c #ffffff", +" none", +/* pixels */ +" ", +" * * ", +" ** ** ", +" *** *** ", +" **** **** ", +" ** ** ** ** ", +" ** ** ** ** ", +" ** ***** ** ", +" ** *** ** ", +" ** * ** ", +" ** ** ", +" ** ** ", +" ** ** ", +" ** ** ", +" ** ** ", +" ** ** ", +" ** ** ", +" ** ** ", +" **** **** ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *restore_enhancement_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 5 1", +/* colors */ +"* c #000000", +". c #606060", +"- c #e0e0e0", +"w c #ffffff", +" none", +/* pixels */ +" ", +" ************** ", +" **************** ", +" ** ** ", +" ** ** ", +" ** ** ", +" ** ** ", +" ** ** ", +" ** ** ", +" *************** ", +" ************* ", +" ** *** ", +" ** ** ", +" ** ** ", +" ** *** ", +" ** ** ", +" ** *** ", +" ** ** ", +" **** **** ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *default_enhancement_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +"* c #000000", +". c #606060", +"- c #e0e0e0", +" none", +/* pixels */ +" ", +" * ", +" * ", +" * ", +" * ", +" * ", +" * * * ", +" ** * ** ", +" ** * ** ", +" ******* * ******** ", +" ** * ** ", +" ** * ** ", +" * * * ", +" * ", +" * ", +" * ", +" * ", +" * ", +" * ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *pipette_white_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +/* pixels */ +" ", +" ", +" .... ", +" ...... ", +" ...... ", +" ......... ", +" ...... ", +" .aaa.. ", +" .aaaa.. ", +" .aaaa. . ", +" .aaaa. . ", +" .aaaa. ", +" .aaaa. ", +" .aaaa. ", +" .aaaa. ", +" .aaaa. ", +" .aaaa. ", +" .aaaa. ", +" .aaa. ", +" ... ", +}; + +/* --------------------------------------------------- */ + +const char *pipette_gray_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +"X c #808080", +/* pixels */ +" ", +" ", +" .... ", +" ...... ", +" ...... ", +" ......... ", +" ...... ", +" .aaa.. ", +" .aaaa.. ", +" .aaaa. . ", +" .XXXX. . ", +" .XXXX. ", +" .XXXX. ", +" .XXXX. ", +" .XXXX. ", +" .XXXX. ", +" .XXXX. ", +" .XXXX. ", +" .XXX. ", +" ... ", +}; + + +const char *pipette_black_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +/* pixels */ +" ", +" ", +" .... ", +" ...... ", +" ...... ", +" ......... ", +" ...... ", +" .aaa.. ", +" .aaaa.. ", +" .aaaa. . ", +" ...... . ", +" ...... ", +" ...... ", +" ...... ", +" ...... ", +" ...... ", +" ...... ", +" ...... ", +" ..... ", +" ... ", +}; + +/* --------------------------------------------------- */ + +const char *zoom_in_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +" none", +". c #000000", +"+ c #c0c0c0", +"a c #ffffff", +/* pixels */ +" ", +" ", +" ..... ", +" .+aaaa. ", +" .++aaaaa. ", +" .+++aaaaaa. ", +" .aaaaaaaaa. ", +" .aaaaaaaaa. ", +" .aaaaaaaaa. ", +" .aaaaaaa. ", +" .aaaaa. ", +" ....... ", +" ... ", +" . ... ", +" . ... ", +" ..... ... ", +" . ... ", +" . .. ", +" ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *zoom_not_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +" none", +". c #000000", +"+ c #c0c0c0", +"a c #ffffff", +/* pixels */ +" ", +" ", +" .. ..... .. ", +" ...+aaaa. .. ", +" ..+aaaaa. .. ", +" .+..aaaaaa. .. ", +" .aa..aaaaa... ", +" .aaa..aaaa.. ", +" .aaaa..aa.. ", +" .aaaa.... ", +" .aaaa.. ", +" ....... ", +" .. ... ", +" .. ... ", +" .. ... ", +" .. ... ", +" .. ... ", +" .. .. ", +" ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *zoom_undo_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +" none", +". c #000000", +"+ c #c0c0c0", +"a c #ffffff", +/* pixels */ +" ", +" ", +" ..... ", +" .+aaaa. ", +" .++aaaaa. ", +" .+++aaaaaa. ", +" .aaaaaaaaa. ", +" .aaaaaaaaa. ", +" .aaaaaaaaa. ", +" .aaaaaaa. ", +" .aaaaa. ", +" ....... ", +" ... ", +" ", +" . . . . .. .. ", +" . . .. . . . . . ", +" . . .... . . . . ", +" . . . .. . . . . ", +" .. . . .. .. ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *zoom_out_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +" none", +". c #000000", +"+ c #c0c0c0", +"a c #ffffff", +/* pixels */ +" ", +" ", +" ..... ", +" .+aaaa. ", +" .++aaaaa. ", +" .+++aaaaaa. ", +" .aaaaaaaaa. ", +" .aaaaaaaaa. ", +" .aaaaaaaaa. ", +" .aaaaaaa. ", +" .aaaaa. ", +" ....... ", +" ... ", +" ... ", +" ... ", +" ..... ... ", +" ... ", +" .. ", +" ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *full_preview_area_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +" none", +". c #000000", +"+ c #c0c0c0", +"a c #ffffff", +/* pixels */ +" ", +" ................. ", +" . . ", +" . . . ", +" . ... . ", +" . . . . . ", +" . . . ", +" . . . ", +" . . . . . ", +" . . . . . ", +" . ............. . ", +" . . . . . ", +" . . . . . ", +" . . . ", +" . . . ", +" . . . . . ", +" . ... . ", +" . . . ", +" ................. ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *printer_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +". c #000000", +"# c #7f7f7f", +" none", +"b c #ffffff", +/* pixels */ +" ", +" ", +" ", +" ", +" ......... ", +" .bbbbbbb.. ", +" .bbbbbbb.b. ", +" .bbbbbbb.... ", +" .bbbbbbbbbb. ", +" .bbbbbbbbbb. ", +" .bbbbbbbbbb. ", +" .bbbbbbbbbb. ", +" .bbbbbbbbbb... ", +" ............. .. ", +" ..###########.. . ", +" . . . ", +" . . . ", +" .bbbbbbbbbbbbb. . ", +" .#############.. ", +" .............. ", +}; + +/* --------------------------------------------------- */ + +const char *zoom_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +/* pixels */ +" ", +" ", +" .............. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaa....aaaaa. ", +" .aaaa...aaaaa. ", +" .aaa....aaaaa. ", +" .aa...a.aaaaa. ", +" .aaa.aaaaaaaa. ", +" .......aaaaaaaaaa. ", +" .aaaaa.aaaaaaaaaa. ", +" .aaaaa............ ", +" .aaaaa. ", +" .aaaaa. ", +" .aaaaa. ", +" ....... ", +}; + +/* --------------------------------------------------- */ + +const char *zoom_x_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +"# c #4040ff", +/* pixels */ +" ", +" ", +" .............. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaa....aaaaa. ", +" .aaaa...aaaaa. ", +" .aaa....aaaaa. ", +" .aa...a.aaaaa. ", +" .aaa ", +" .......a ## ## ", +" .aaaaa.a ## ## ", +" .aaaaa.. #### ", +" .aaaaa. ## ", +" .aaaaa. #### ", +" .aaaaa. ## ## ", +" ....... ## ## ", +}; + +/* --------------------------------------------------- */ + +const char *zoom_y_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 4 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +"# c #4040ff", +/* pixels */ +" ", +" ", +" .............. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaaaaaaaaaaa. ", +" .aaa....aaaaa. ", +" .aaaa...aaaaa. ", +" .aaa....aaaaa. ", +" .aa...a.aaaaa. ", +" .aaa ", +" .......a ## ## ", +" .aaaaa.a ## ## ", +" .aaaaa.. #### ", +" .aaaaa. ## ", +" .aaaaa. ## ", +" .aaaaa. ## ", +" ....... ## ", +}; + +/* --------------------------------------------------- */ + +const char *resolution_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 2 1", +/* colors */ +". c #000000", +" none", +/* pixels */ +" ", +" ", +" ", +" ... .. ", +" ..... .... . ", +" ....... ...... ... ", +" ....... .... . ", +" ....... .. ", +" ..... ", +" ... .. . ", +" .... ... ", +" .. .... . ", +" .... .. ", +" ...... ", +" .... .. . ", +" .. .... ", +" .. . ", +" .. ", +" .... .. . ", +" .. .. ", +}; + +/* --------------------------------------------------- */ + +const char *resolution_x_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +"# c #4040ff", +" none", +/* pixels */ +" ", +" ", +" ", +" ... .. ", +" ..... .... . ", +" ....... ...... ... ", +" ....... .... . ", +" ....... .. ", +" ..... ", +" ... .. . ", +" .... ... ", +" .. .... . ", +" .... ", +" ...... ## ## ", +" .... ## ## ", +" .. #### ", +" ## ", +" .. #### ", +" .... ## ## ", +" .. ## ## ", +}; + +/* --------------------------------------------------- */ + +const char *resolution_y_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +"# c #4040ff", +" none", +/* pixels */ +" ", +" ", +" ", +" ... .. ", +" ..... .... . ", +" ....... ...... ... ", +" ....... .... . ", +" ....... .. ", +" ..... ", +" ... .. . ", +" .... ... ", +" .. .... . ", +" .... ", +" ...... ## ## ", +" .... ## ## ", +" .. #### ", +" ## ", +" .. ## ", +" .... ## ", +" .. ## ", +}; + +/* --------------------------------------------------- */ + +const char *scanner_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" .. ", +" .... ", +" .... ", +" .... ", +" .... ", +" ... ", +" .... ", +" ................ ", +" .aaaa.a.a.a.a.aa. ", +" .aaaaa.a.a.a.a.aa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" ................. ", +" .................. ", +}; + +/* --------------------------------------------------- */ + +const char *intensity_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ffffff", +/* pixels */ +" ", +" .................. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaa........aaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaaaaa..aaaaaaa. ", +" .aaaa........aaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .................. ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *red_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #ff2020", +/* pixels */ +" ", +" .................. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aa..........aaaa. ", +" .aa...........aaa. ", +" .aa..aaaaaaaa..aa. ", +" .aa..aaaaaaaa..aa. ", +" .aa..aaaaaaaa..aa. ", +" .aa...........aaa. ", +" .aa..........aaaa. ", +" .aa..aaaa..aaaaaa. ", +" .aa..aaaaa..aaaaa. ", +" .aa..aaaaaa..aaaa. ", +" .aa..aaaaaaa..aaa. ", +" .aa..aaaaaaa..aaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .................. ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *green_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #20ff20", +/* pixels */ +" ", +" .................. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaa.......aaaa. ", +" .aaa...........aa. ", +" .aaa..aaaaaaa..aa. ", +" .aaa..aaaaaaaaaaa. ", +" .aaa..aaaaaaaaaaa. ", +" .aaa..aaa.....aaa. ", +" .aaa..aaa......aa. ", +" .aaa..aaaaaaa..aa. ", +" .aaa..aaaaaaa..aa. ", +" .aaa..aaaaaaa..aa. ", +" .aaaa.........aaa. ", +" .aaaaa.......aaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .................. ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *blue_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +". c #000000", +" none", +"a c #3030ff", +/* pixels */ +" ", +" .................. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aa...........aaa. ", +" .aa............aa. ", +" .aa..aaaaaaaa..aa. ", +" .aa..aaaaaaaa..aa. ", +" .aa..aaaaaaaa..aa. ", +" .aa...........aaa. ", +" .aa...........aaa. ", +" .aa..aaaaaaaa..aa. ", +" .aa..aaaaaaaa..aa. ", +" .aa..aaaaaaaa..aa. ", +" .aa............aa. ", +" .aa...........aaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .aaaaaaaaaaaaaaaa. ", +" .................. ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *pixel_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 3 1", +/* colors */ +"a c #000000", +" none", +". c #ffffff", +/* pixels */ +" ", +" ", +" ", +" a . ", +" a a . ", +" a . ", +" a a a . ", +" a . ", +" a . ", +" . ", +" . ", +" . a ", +" . aaaa ", +" . aaaa a ", +" . a aaaaaa ", +" . a aaaaaaaaa ", +" . aaaaaaaaaaaa ", +" ", +" ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *log_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 2 1", +/* colors */ +". c #000000", +" none", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" . .. ... ", +" . . . . . ", +" . . . . ", +" . . . . ", +" . . . . ", +" . . . . ... ", +" . . . . . ", +" . . . . . ", +" . . . . . ", +" . . . . . ", +" .... .. ... ", +" ", +" ", +" ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *move_up_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 2 1", +/* colors */ +". c #000000", +" none", +/* pixels */ +" ", +" ", +" ", +" . ", +" ... ", +" ... ", +" . . . ", +" . . . ", +" . . . ", +" . . . ", +" . ", +" . ", +" . ", +" . ", +" . ", +" . ", +" . ", +" ", +" ", +" ", +}; + +/* --------------------------------------------------- */ + +const char *move_down_xpm[] = +{ +/* width height num_colors chars_per_pixel */ +" 20 20 2 1", +/* colors */ +". c #000000", +" none", +/* pixels */ +" ", +" ", +" ", +" . ", +" . ", +" . ", +" . ", +" . ", +" . ", +" . ", +" . . . ", +" . . . ", +" . . . ", +" . . . ", +" ... ", +" ... ", +" . ", +" ", +" ", +" ", +}; + +/* --------------------------------------------------- */ + +const unsigned char cursor_pipette_white[] = +{ + 0x00, 0x70, 0x00, 0xf8, 0x80, 0xff, 0x00, 0xfe, 0x00, 0x7d, 0x80, 0x38, + 0x40, 0x18, 0x20, 0x14, 0x10, 0x12, 0x08, 0x01, 0x84, 0x00, 0x44, 0x00, + 0x32, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00 +}; + +/* --------------------------------------------------- */ + +const unsigned char cursor_pipette_black[] = +{ + 0x00, 0x70, 0x00, 0xf8, 0x80, 0xff, 0x00, 0xfe, 0x00, 0x7d, 0x80, 0x38, + 0x40, 0x18, 0xe0, 0x17, 0xf0, 0x13, 0xf8, 0x01, 0xfc, 0x00, 0x7c, 0x00, + 0x3e, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x00 +}; + +/* --------------------------------------------------- */ + +const unsigned char cursor_pipette_gray[] = +{ + 0x00, 0x70, 0x00, 0xf8, 0x80, 0xff, 0x00, 0xfe, 0x00, 0x7d, 0x80, 0x38, + 0x40, 0x18, 0x20, 0x14, 0x10, 0x12, 0xf8, 0x01, 0xfc, 0x00, 0x7c, 0x00, + 0x3e, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x00 +}; + +/* --------------------------------------------------- */ + +const unsigned char cursor_pipette_mask[] = +{ + 0x00, 0x70, 0x00, 0xf8, 0x80, 0xff, 0x00, 0xfe, 0x00, 0x7f, 0x80, 0x3f, + 0xc0, 0x1f, 0xe0, 0x17, 0xf0, 0x13, 0xf8, 0x01, 0xfc, 0x00, 0x7c, 0x00, + 0x3e, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x00 +}; + +/* --------------------------------------------------- */ + diff --git a/frontend/xsane-icons.h b/frontend/xsane-icons.h new file mode 100644 index 0000000..538f9ea --- /dev/null +++ b/frontend/xsane-icons.h @@ -0,0 +1,87 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-icons.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ------------------------------------------------------------------------- */ + +#ifndef XSANE_ICONS_H +#define XSANE_ICONS_H + +#define CURSOR_PIPETTE_WIDTH 16 +#define CURSOR_PIPETTE_HEIGHT 16 +#define CURSOR_PIPETTE_HOT_X 1 +#define CURSOR_PIPETTE_HOT_Y 14 + +extern const char *xsane_window_icon_xpm[]; +extern const char *error_xpm[]; +extern const char *warning_xpm[]; +extern const char *file_xpm[]; +extern const char *fax_xpm[]; +extern const char *faxreceiver_xpm[]; +extern const char *colormode_xpm[]; +extern const char *Gamma_xpm[]; +extern const char *Gamma_red_xpm[]; +extern const char *Gamma_green_xpm[]; +extern const char *Gamma_blue_xpm[]; +extern const char *brightness_xpm[]; +extern const char *brightness_red_xpm[]; +extern const char *brightness_green_xpm[]; +extern const char *brightness_blue_xpm[]; +extern const char *contrast_xpm[]; +extern const char *contrast_red_xpm[]; +extern const char *contrast_green_xpm[]; +extern const char *contrast_blue_xpm[]; +extern const char *rgb_default_xpm[]; +extern const char *negative_xpm[]; +extern const char *enhance_xpm[]; +extern const char *store_enhancement_xpm[]; +extern const char *restore_enhancement_xpm[]; +extern const char *default_enhancement_xpm[]; +extern const char *pipette_white_xpm[]; +extern const char *pipette_gray_xpm[]; +extern const char *pipette_black_xpm[]; +extern const char *zoom_not_xpm[]; +extern const char *zoom_out_xpm[]; +extern const char *zoom_in_xpm[]; +extern const char *zoom_undo_xpm[]; +extern const char *full_preview_area_xpm[]; +extern const char *printer_xpm[]; +extern const char *zoom_xpm[]; +extern const char *zoom_x_xpm[]; +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 *scanner_xpm[]; +extern const char *intensity_xpm[]; +extern const char *red_xpm[]; +extern const char *green_xpm[]; +extern const char *blue_xpm[]; +extern const char *pixel_xpm[]; +extern const char *log_xpm[]; +extern const char *move_up_xpm[]; +extern const char *move_down_xpm[]; +extern const char cursor_pipette_white[]; +extern const char cursor_pipette_gray[]; +extern const char cursor_pipette_black[]; +extern const char cursor_pipette_mask[]; + +#endif diff --git a/frontend/xsane-logo.xpm b/frontend/xsane-logo.xpm new file mode 100644 index 0000000..cfe0a03 --- /dev/null +++ b/frontend/xsane-logo.xpm @@ -0,0 +1,372 @@ +/* XPM */ +static char *xsane_64c[] = { +/* width height ncolors chars_per_pixel */ +"256 300 65 1", +/* colors */ +" c #CBDDFC", +". c #363777", +"X c #D2E6FC", +"o c #27241C", +"O c #B0A47E", +"+ c #1F1C14", +"@ c #D9EFFC", +"# c #E2D9B5", +"$ c #788DFC", +"% c #3848FC", +"& c #978C6B", +"* c #0A0B54", +"= c #C8BC94", +"- c #D6CCA5", +"; c #C0B48C", +": c #2028FB", +"> c #687CFC", +", c #242777", +"< c #5468FC", +"1 c #8097FC", +"2 c #4E4836", +"3 c #A2B9FC", +"4 c #858279", +"5 c #98ACFC", +"6 c #E9F7FC", +"7 c #3D47B3", +"8 c #B0C7FC", +"9 c #AAA27F", +"0 c #F1ECD5", +"q c #13179A", +"w c #BED7FC", +"e c #595785", +"r c #8FA6FC", +"t c #5F5842", +"y c #2F36B5", +"u c #CFC49C", +"i c #302C21", +"p c #BBCDFC", +"a c #4558FC", +"s c #867C5E", +"d c #8C9EFC", +"f c #DAD2AD", +"g c #020204", +"h c #B8AC85", +"j c #FBFBF5", +"k c #2B2EA0", +"l c #1E25B1", +"z c #AEBEFC", +"x c #7D7458", +"c c #C6C2B0", +"v c #EBE4C7", +"b none", +"n c #171CF9", +"m c #71684F", +"M c #15140F", +"N c #5E74FC", +"B c #3D3829", +"V c #131863", +"C c #6F84FC", +"Z c #474A8C", +"A c #0D0C0A", +"S c #8E8464", +"D c #2B37FB", +"F c #62669C", +"G c #A49976", +/* pixels */ +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbS&#u##-#f###v##ummbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&&G=f#f#f---ff#f-#-##--#v#v#v-u=-==uh9hu=mbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbsS&;u-u-#f#v#vfff-###--f####---###-#fvv#ff#fu=-;OO;u;h;;===9&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbGO-##-=-#f;==#-uff#vv####vv#fff#=vvvf#-f-f-####vff#--u==-uhOhu=;u=uf-u==;&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbGOcvvvfff#--###uuff--uff-#fvv##f#v##-u-f#-##v#--u-###vfu-f-u-#-==uuu==uu;uu---===-=u;&Sbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;;-vvf-##vv##f--f-#--##-#u--uf#f--fv#####-==-ffv##-##u=-###f-uu;uu-u=u-uu;==hu-===u---uu=;OGh;;;Gbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=-##v#f##f##v###fv#ff-f#fu-##-u=u-#fu-f-#f-##fuu----#-u--uu-fu-u=#u=uu=u=hu--u;h=u-u==uu-u=f-u;h===;u;h;;&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbf-vvf##v#fvvv##v#f#v#-v#f#f=##-f###u;=uuuu=u==-##-u-ufu--=u--u=-u=u-u;-u=uuhuu==u--uOh========u-#-u-=-=uu;===;h=hGSbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb9-=-vvv##0######v####ff#-#f#vv--=-##f-=uu-=uuhO=-uhhu--uu-===u==-u=uu=;u=u=--#;=9=f--u;;;u;=uhO;-u;hu#--=-u=uu==u=h==h9hhhGbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=u#fv-=##vvv#vfvvvvv-##---u--f--#--=-----==h;uu;hO;;-hG=;-u-u=;u=f--h==;hhO;;=;=-=uh=uu=u=;hh=uhh9;;-h9;=-u#uu;-=ff-==;;hhGhhhhhhbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;fffv#--f####-v-v-f#v####v-uu;u==-u-f#ff-;u=-=h;O;h;==hhO==;;huhu;;=-===--=h;O;h;===ufu-uO==u;hhO;O;;=hOO===;hu;u==u--u--#uh=h;Oh;hh;=;hbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=v---#v#fv##fu#0##f##ff#-f#-uu;;==;---ff-u-=-uuu=uh9h;u;h=;;;G;-==h==;=u;uu=;=Ohh;h=uu---u-=uuuu;=h99;=;h=;;;9;-u=;-u=u-uu-u=uhh;;h=uu=-=;=hh9bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=v#vv###fv#-vff#v###--cfuu--====-h=9;-=uu-fu==uff=h==;hhO;;h=hh;u=-=;=h==;=uh;;;=h;Ghu==u--===u-f=h=u;;;9==h;;;;u=-u;=O==h=u;;;=u;;9;-u=u--=;hh==O9mbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc00#v##0#vv#vfu-#--f#--=h-f;;c9;h;O;;h=u==;-u=hh-uu;=;;u;=u;=;9h=h;=uu;h9;uhO;GhOhOh;h=u==;uuuhO-uu;=;hu;;uh=;9O;h;;=u;;G;u;O;9;O;hh=;=u=u;-uuh9uu=hh99OGbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#6v0#-f00##vv#f--=--c-f--Ou-;u=;OOOG;;h=u===;;h=u-=u;OOuu;;=u=;Oh9=;;;=;=9;uh==;hO9Gh;O===;=;=O==-==;O9=u;;=u=;hhO;=h;u;u9;u;==;OO99O=h=uuuuu=h=uf==;O&h;OG9hSbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbhvvv#v0v-f#vvv#vf#-u--uu-f-uu==h;=h;O99OO==h;uu;h==;;=u=hO;=uuuu=u;h;u;;uu-=u==hh;O;9G9Oh;=h===;h==;h=u=OO;;=uu===;h===;uu-====hh;h;O99hO;=;;uu=;=u===u=h9hh;;hO9OSbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-#f#f##vvv##--#0#fu=u--u==u;=f-=h;;O;u=hOhu;h=;h;hOhhOh;==h;Oh;fu=;h=uu==;u;=--;hO=O;u;;Oh=;h=h;;hOhh9h;==;;hh;--u;h=u==;;u;=-f=hh=O;==hO9==h;;;h;O;;9;;=u;;hOh==;9GGOGmbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbfvv###vvf#-vf=-#-f#-u=-u;u;u=cu-=h;;99;u;h;=;;h;;;=hhh=;hhOu;9h===-==h==;=hu;;uuuh;;OOhuhhh=;hh;;;=hhh;=hOh=;9O==;u==h=u;=h==;uuuh;=OOhu;hh=hh;;;=;;hh;=;hh==hO=u;u;h9OhGG&Sbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-0v#fvv0###uffu-f-f-uuuu===huu=-uhu;hhhhh;;h&huu;;=h9;h=;=h9h;h;=u=u=;==;=;Ouu=-uh=;hOhhO;;h&O=-;;=h9;h=;;;OO;h;=u=uu=u==;=h=u=u-hu=O9hhO;h;GOu-;;;;9hh==;;Oh;;;=-=u=;=;h9O&G9G&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-v06#vvv#vf--f=9;u;--=;===uh;huuuu;=-;h;;Ghh9GGOh;uuh;=;;;hhh=O&9hOuu;;====h;hu-uu;;-=hh;9h;9GGOh;=u;;;;;;hO;;h&G;h=u=h;u==h;huuuu;h-=hh=9h;9GG9O==-;;=;;;;O;;;&G;hu-uh;==;hO9OOOGGxbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;f-0v00vv##-uu-;9;uGh=u=u;=;=;;-=u==hh==;=hOh;OOOGG==uu;;h;;OO=O&9=GO=u=uh;=u;;u=;==O;==;uhOO;OOOGG===u;=h;;OO;h&O;G9=u;u;;==;;=====O;==;uhOO=OOO9&;=;u=;h;;9O;;&9;99;u=u=;==;;h;hOG&&&Sbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=##fvvv0v#-##ff---9h;=-hOuuuu=G-#=huOhh;u=uu;hOGhhh9h;h-=hO;u;=;=u99h=uh9=-uu;Guf=;=hO;huu===hO9hhh9h;;u=hOhu;u;=u99h=uhO=uuu=G=#=;=;9;Ouu===;O9Ohh9h=;u=hhhu;u;=uOGh=u;O=-u-u&=f=OhhSG&GG&tbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbvf##v#fv###f##f###f;=;-u=h9uu-cu=uf=hh=h=O;h;=;=;9hOhhO;hh=;==u-#f-;;;uu=O9=uuu=uu-uhh=h;O;h;=;=;OhOhOhh;h;===uu#ff;;huu=hG=u=u=u=-uhh=h;hh;h=h;;OOOhhOh;h=;==uu#-#=;huuuh9;-uu=uu--hOh9G&&SS&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbc0v0#0--v#uv#ufu--##-;h;uu-;---uuu=u=u-uu;h=;h9O==;;O;OG=;Ouu;====ff-;h;=uf;u-uuuu=u==-=u;h==hOO==;;O;h&=;Ouu;u=u=-#f;hhuu-=uu-u=-uuu=-=-;h=;hh9===;O;h&;;O=u;====-ff;h;=u-==--uuuuu==-=uh999&&xSsbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbb;vvv0vv0#=-v-#-u=u-uu=;u;=u=-uuu;u-==uu-u-u-uh9;hO;h=h;=;Ghu=uu=;uuuu=;===u=-=uu;=-=uuu--fu-=h9;hO;h;;;;=9Ou=uu=;=u-=u;==;u=uuuu;u-;u=u---uuu;G;hO=h;;;;=OO==uuu;=u-=u;==;u=uuuu;=f;-=u---u==OS&&sSstbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbv00ff#vv--f----u-u====u=;=;==u;;=;uu==u--f--=hh;h==9GO=;OO;;====u=u=====h;;;=u=hu;uu=;ufu#-f=hh;h;=OGO==OO;;====u=u;====;;;==u=hu;uu=;u-u#-#=;h;;;=OGO==h9;=====u=u=====;h;;=u=hu;=-=;u-uf-#;h9hGG9smmsbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbvv0ff-v#--uu-=-u--==;;u==;;===u=;;==-=;-=ff-=uu=;h=9GG;;hhh;=;uuu-==;;uu;;;;u=u==h==-==-=-f-=u-=;h=OGGh=Ohh;=;=uu-==;;uu=;;;=;uu=h==-==u=-f-==uu;h;OGGh=hOhh=;=uu-==;;uu=;=;u==u=h==-==u=-#-u=-=hOO&xss&mtbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbb;60v#v0#u=uf==u=---u;==ff=h;;=Ou--;=;=;;=uuuuu==uu;;9;=;GGO=hh=;u-uu;=;ufu;;;=9uuu==O;;=;=-uuu==u==;Oh=;G9O=hh=;u-uu;=;u-u;;;=Ouu-=;;=;=;u-uuu=====;hh=;GGO=;O=;=--u;===fu;h;;Ouuu==;;;u;=-uuu==uu=h9GOGsxmsmbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbb;vv60v###fu;=u=h==-u=u=u-u;;O;;;;uu-=h;h;=uu-;;;=;h==;Oh;;;Oh=;h==--====-u;;O;;;;-u-OsOhhuuu-;;;=;h==;hh;hhOh=;h==--u===-u=;O;;=;uu-u;;h;=uu-=;;==h=u;OO;;;OO==h;=u-u;==-uu;O;;=;u-f=;;hh=uu-=;;;=O;u;OG9&&Sxxs2bbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbcvvv0v#v#--=;;h==;h;=f-===u;OO;u;-u==u=hh=uuu=;;hO;h=hh;=h;hhhO;=hh;;-u===u;O9;u=uu=hs9hh;uuu==hhO;h=;h;=;=OhOO;=;hh;-u===u;O9h=;uu==u=;O==u=u=;hO;h;=h;=;;hhh9h=;hh=uuu==u;hGh===u==u==O;=u=u;;;9;h;=9h;h9&&Smsxtbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbc00vvv#-##f=;Oh;==O;=;==;uu=Oh;=;uu;;===;;u;u;;u;;;h;=hO;==hO&G9OOG9O9h;=uu=Oh;=;=u=hGxh;;u;==;u;;;h;=hOh==hO9h;=;hh;;=;=uu=hO;===u=;===;;u;u=hu;;;hh=hO;==;O9O;==hh;;==;uu=hO===;-=;=u=;;u===hu=h;hh=hOh=;h&&SSSSmtbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbb=0v00#vv-f-fu;9O;h;;;;hh=u-======u=;=u=;=u=h=u=;u=;=;O==h;=u=OmtmmmtmmtxG;u===;===uhuhxG;u=h=u=hu=;=;O=;;;=u=;G9h;hhh;h;;uf=;u;u;uuh==u;;u=;;u=;u=;=;O;;;h=u=;G9h;h;h;;h;=f==u;u;=u;===;;==;;u=;=u;=;O;;;h===h&&&Ssxmmbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbb;6jj0##v0#fu=;;;;;;OG;==9Ouu=u;u=h==;=u=;==;;=;=;uuu;hO=-uu=;h;OG9G&&GhOSmmh==;u=h==;;;m9==;;=;=;uu-;;9;-uu=;;;=h;;O9;==O9=uuu;u=;;=;;u=;==;h=;=;uu-;=G=-uu=h;;=h;;OGh==O9=uu=;==h==;;uu;===h=;=;uu-;=G;-uu=;hh;G9&smmxmbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbb;000j0vfvff-u=;Oh==OOG;;=OG;;u=u==h==-uu;==hhhh;;=;u-==O=====;hOh==OO9h;=9smmh=-==hu=-u;mO=hhhO;==;=-==h====u;;Oh;=OOGhhuOG;;u=u==hu=--uh==;hhO;;;;=uu=h;u==u;;Oh;uOO9OhuhGh;u=-=uh=;u-u;==;h;O;;;;=uu=;huu;u=;OOh;&&xmmxtbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbb0600600vf=uu-hOhh;h;=;OOh;;;;O-huh;uu=u=u-h;hO;hh===u-u-uh==u;OhOhO;=;OOh;;9&mhhuh;=u==Gs=;;;O;hh===u-uuuh==u;OOO;Oh=;OOO;;hhO=h=;;=u===u-=h;O;;h===u--u-O==u=OOO;O;;=hOO;;;hh=;=;h=uu==uu=h;O;hh===u--u-O====9OOh9OGGSmmmtbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbv0jjjjvvv=fuu=;=O9h;=hh=;;h9;u=;;u;;=-;u==;hOhh;h=uu--uu-;u=uu==O9O;=hh=;;hG;=s&O===;-;OS9h;OOh;h==uu-uuu;====;;OGO;=hh;;hhG;uu;h=;;;u;==;h;OOhhh=uuufuuu=u==u;=h99;=;O=;;;G;u=;hu==;u==u=;;hOh;h==uufuu-===u===hGGh;h&Gsxmttbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbb0j00000#--#ff;huu=hOh=;h;hh===-=;;Ou;h==hh;;uh;&;-===--u;=u-f;h==;;hO=;h;hh=u=u9mm&;;;;9s&h;=OhGh====--=;==-f;h==;;hO=;h;h;;u=u=;=h=;h;=;;;;=hhGhu===--u=u=-f=h=u;;hO;=h;h;;u=uu;=O;;;;u;h;;=hhGOu==u--u===-f=;;==;hOhh9G&smtttbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbj000j0v==#-u;=;;=;u;;=OOh;h;;u=;O9=uOh;GhhhOO;h;=;=;-u=OOfuu;=;huh==;=h9h;O;;u=;&tx9G99tG9h9O;h;===;uu=hO--u;=;h=;;=O=;GO;hhhuu;h&;uhO=GhOhOO;h;==;;uu=O9uu-==;h=;;=h=;GO=hh;=u;;G;u;O;GhOhhO;h;===;uuuh9uuu=;;;=;;=h=;&&&x2B2t2bbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbb00j00#f##fuu;Ohuu;;=u=hhhO=;h==;=G==h==hhO9G;;O=u====;h=u-==;OO=u;;=u=;hh9==h=u;=G9Gmm&x&99Gh;O;==;;;;O==-;;h9G==hO;=;h9OGh;Oh=h=&;=h;;hOO9GO;hh==;=;=O==-==;OG=u;;;-==hhOh=h;u;u9hu;;;;hh99O=h;==;=;=O==-==;h9===h;-=;OOSmmxmmttBbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbb-v0j0vf#fu;uu;Oh;==u=u==;h;u;;u-u====hh=O;GG9Oh==h===;h===huu=OO;==u====hh;=;;=uu;==;&tm&hGGGOO;=O;=;;O;;;O;;;GGOh;;;;h;hOh;hh;;=h;;hOOO9OGGGOO;=h;==;O===h===h9;==uu===;h===;uu-;u==;;hhhOGGOO;u;;=u;;;==;=u=h9;;uuu===;&x&&&&smt2Bbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbv0vvv#--;;h===;;Oh=fu=hh=u===;u;=--;hh;hhu=hOh=;h;h;hhOhOOO;==h;hh=f-=;h====;h=;=--;h9GtG=;hOO;hO;OOO9G9GGG9hhG9G&O;hOG&GO99GGOGO;;9GGOG9;h9GG;hOhh;hhOhhGhh==h;hO;--=;h====;;=;=--;hO=O;==;OO=;h;;;hhOhhGhh;=h;hO;u-==hOx9;hGGsxmt2bbbbbbbbbbbbbbb", +"bbbbbbbbbbbbv000vvfu=uuh;hu;9h==uu==;=uh=hu==u-=O;;9O;=hh;;h;h;;;=hhh==hhO=;9h===u=;h==h=hu=;uu=O;;&t9=OOO;O9GO9OOG&&GG&&SG&sS&&GGG&S&&S&s&GSG99S&GSSGOGGGh9GOOOhhhOO;;;Oh;;OO===u==h=u;=hu=;uu-hh=OOh=;;h=;hh;;;=hhh;=;hh==OO==;-==h9s9;Oh9Ssmt2ibbbbbbbbbbbbbb", +"bbbbbbbbbbbbjv00#ffuf==h9;;h;=u=u====;=;huu;-=hu;hOhOh;;h&;uu;==OO;h=;=hOh;h;=========;=O=u;-=h=h99&tSO99sGOhGGGSsSS&SSsmxsmxxsxxxmxxmxmmxxxssmsxxmxxxSSSxS9hG9O9GOOhh;OOO;h;;u=u=====;=h=u=u-h==hOhhO;hhG9=u=;=;Oh;;=;;OO;h;;u=uu;=hx&;h;;OGGmt2Bobbbbbbbbbbbbb", +"bbbbbbbbbbb#0jjv##-uuhhh=O&O;huu;;====h;hu-uuh=-;h;;9hhGGGOh;=uh;;;;;hhh;hSOhO=u;h==;=hhh=u==OhuhG9&tSGssxsSS&&xxxmmmttttt22t2ttt22t22222ttttttmtttmtmmtmtmsS&9&GGGOOOGhhh&Ghh===;;===h;h=uuu=;-=Oh;9h;OGG9h;=u;;;;h;;O;;;&Ghh=u=h;hGx9;O=u=9&xmtBibbbbbbbbbbbbb", +"bbbbbbbbbbb-0000v#uu;hh=O&O;GO=u;=h=;u;;u====hh==;=h9h;OO99G==uu;=h;hOh;O&9=&O=u;uh;;=h;==hhhG99OGGx2xSxmmmtmmmmttt222B2BiBBiBBBBBBBBBBBBB2B2BB22222B2t2ttt2xxsSS&S&G&&OOSGhGG;u;=;;==;;=u===hh;u;=;OO=O9O9&;=;u=;h;;OO;;&9hOO;===Gxx9;;;=;hO&xmtBiobbbbbbbbbbbb", +"bbbbbbbbbbb00vj#f=uu=;=u=GO;;uhhu-uu;G--=huOhh;u=uu;hOGhhh9h;h-;hO;u;=;;=G9;;uhO=u=u;&=uh9hG&&&G&&S2tmtttt22222BBiBBiiiio++oooo+oooio+iiioii+iiBBBBBBBBB2222ttmmmmx&S&&Gh&&O;;;O;-=u=G=f=;=;9;h=uu==;O9OhhOO=;uuhhhu;=h=uOGh===O;h4Oh&=#=;;;&Gsxm2Bibbbbbbbbbbbb", +"bbbbbbbbbb#v#0###---ufff-;;;uu;O9u=u===uf=Oh=h=O;O;;;;;9hOhhO=h;;;===uff-;;;u=;9G=;;;hhh;9SS&sxmxt2B222BBiiioiooo++++o+++++++++++++++MMM+MMMMoooioiBiBiiiBB2B222ttmxsSG9OGGGh;;9G;u=u;uu-uh;;;h;;hhuh;;OOOOhhO;h;;==uufff=;huu=h&xhuu=u=--hhh9Sst2iiMbbbbbbbbbbb", +"bbbbbbbbbb-f0v#0#u-==u##u;h;uu-;u--uuuuu=u-u=;h==hOh==;;O;GG=;Ouuh=;==f#-hhO==uh;=;hOOGGSSSxxttt2B++iBio+o+MM+MMMMMMMMMbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbMiBoBB2222ttmms&&ssSOh=h;u-==u=u==-=u;h;=hhG===hh;h&;=O=u;==u=-f#;hh=u-9shuu=u=u==u==O&Sm2io+bbbbbbbbbbb", +"bbbbbbbbbb6vfv0v#f==ufuu=;u;=u=uuuu;u-==uu-u-uuuh9=Oh;h=;;=;Ghu======-==;;;;;;hhOO9&&Gsxxmmtt2BBioMM+MMMMAMAAAAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbB2222tttmxxsSSG9hh=;;=f=u=u---uuu;G;;O;h;;;;=O9==uu=;=u-=u;=u;uhx9uu==f=u;u-uu=hGx2Bo+bbbbbbbbbbb", +"bbbbbbbbb-##0vv#f-uu=====;;;;=uu;;uhuu=;---#-f=hhhh==OGO==OO;;;===u===;;=hOOGOOO&xSxxmt222BBii+MMMAAAAgAAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbB22tttmmmss&O9G;O;===u-u#-#=;O;h;uhGO;=;Oh====uu=u=====;h=hOshh===u===-ufu-h&xmBioMbbbbbbbbbb", +"bbbbbbbbb#v#0v##f--u=;;u==;h=====;;u=-==u=ff-;uu=;h=GGG;;Ohh;;;uuuu=;hh;hOGGG&ssxmt222Biioo+MAAAAAgAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb22tttmssS&GGhhu=;==-f-=u-u;;;h&GhuhOh;;==u=-==;;u==;;hhsO==;==-u===-#-=hhSm2i+Abbbbbbbbbb", +"bbbbbbbbbv0#vv###fu;u=--=h=;=O--u;=;;=;=uuuuu==uu=hO;=h9Gh=OO=;=-u=h;h;;O&SsstxttBBio++MMAAgAggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2tmtxs&S&GOO=h=-u-u==uu=;Ohu;GG9;;O=;=--u;=;=fu;h;OmG--;;;;hu;=u=u==hh&x2i+Mbbbbbbbbbb", +"bbbbbbbbb#v0#####-===u-u;;O;;;;-u-=h=O;=-u-;;;=;h==;Oh;hhOh=;h==u=;hOOOGSstm22BBio+MMAgAgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbtmxs&&S&GG;=u-=;;==h;u;hO;;hOh;=h;=--u===-uu;hhOm9=--u;;;h=uu-=;hhOSxtB+Mbbbbbbbbbb", +"bbbbbbbb=v##0v-=u=fuu;=;99G===uu==u=hh=uu===;hO;h=h;;=h;hOO9;=hOhh;OGSSst22BBio+MAAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbtxxSSSSOhu=u=;hO;;;=O;=;;hhhOh=;hh=uuu==u=OGhhmhu==u=;O;=-=u;;OGG&smBoMAbbbbbbbbb", +"bbbbbbbbhfvvvvuuu===;;OxmG;=====;===;;=;u=;u;;;h;=hO;==hOGO;=;9OOGG&sxmtBio+MAAgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbtxsSS9Oh=;u=;;hh=;O;==;OOOh==hh;;====u=hOhO&m;=;====;u;==hu=h;9&StBoMAbbbbbbbbb", +"bbbbbbbb;ffv#fu==h;hOsx9h====u;===;===;===hu=;;;O;=h;=u=hGO;OhGG&sxmmtBio+MAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbxs&&9;;;uu==;O;;;h=uu;GOh;hhh;;h;=f===GsmtmO==u;;==;;u=h==;hh&Sm2oMAbbbbbbbbb", +"bbbbbbbb#vvv#-;-=hsxsOh=;u=h=;;=u=;=u;;===;uuu=hOu-uu=;hh;hhh&S&Sx2BBi+MAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbtSSGO;;--#=u9=-uu=;h;=h;;OOh==hG=u=hGs9&mG;;u=;==;;;==;=uu;h&SstB+Abbbbbbbbb", +"bbbbbbbb#vvv-=Oh9xmsh;==u==;==-uuh==hhhh;=;;u-=;O====u;hOh;hGSsxmtB++AAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbs&h;=uu#-=h;uu;u=hOh;uh9GOhuhGh;Oxs9;Gm9u--;;=;h;O;;;;=u=hGSsti+Abbbbbbbbb", +"bbbbbbbb#####uxmm&O=h;h-Ouh;uuu==u-h;h9;hh===u--uuh==uhOhOhGGGxtBo+AggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbSh;----#f--O==u=OhOhO;;;hOO;;;9s9O;;Gx;u==uuuh;Ohh;=;;=-uhhmtB+ggbbbbbbbb", +"bbbbbbbbf=uu-9mGO;OO;u=;;u;==u;u==;hOh;hh=u=-fuu-;u=u=;;OGGGGxt2iMggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbu##vv#--u==u===hOOh=;h=h;;Gh=;;h-h4Gc==u=;;hOh;h;=uu-u=;9stBoAgbbbbbbbb", +"bbbbbbbbf&sssxx;;;=uuu=;;O=;;==;h=;uO;G;-=uu--===u--;h;=;OG&&m2iMgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbG#vvv#--=-#=;;=;hhO;=h;;h;u;-c;=Ohh;h-;h;;=;h9O=u=uu-u;hG&xB+ggbbbbbbbb", +"bbbbbbbbf#ccchO==h;=u=;hG=-Oh;GhhhOhhh;===;u-=OOfu-;=;h=h;O&stiMgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#vvvuh---==;;==;uh==GO=h;;=u=;G;u;9;GhOhhOhhh===;=uuhGhhGm2+Agbbbbbbbb", +"bbbbbbbbv00v#-uh=;h=u;=Gu=h==hhO9G;;h=u;;==;h=u-==;Oh==;h;h&x2iAgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbvv-v#v-u;hO=u;;;u=;hhOh=h;u;u9hu;;=;hh9O9=hhuu;=;=O;=u;9StioAgbbbbbbbb", +"bbbbbbbbvv0vv-uu-;=u-u;===hh;hhGGOOO==h===;h===hu==9O;===;O&m2+Agbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;vvv##uuu=hO;==uu=u=;h;=;;=u-;===;;O;h99GOO;=;;=u=;h==hh9&mBoggbbbbbbbb", +"bbbbbbbb00vff##uu=;u==fuhhh;hhu;h9h=;h=h;hhOhOhO==;hhOh=-;Ost2+gbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbvv###;==uuh=hO;--=;h;=u==hu==--=h9=hh;=hOO;=h;;;hhOhhGO9G&tBoAgbbbbbbbb", +"bbbbbbbbcvvvf##==;===u-=h;;9O==;h;;;hh;;;;hhh;;h;Ou;Gh;==;G&m2oAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0vv###u;h==hO===u==h=u;=;==;uu-;h=9hh=;;h=hhh;;;=hhOh;h9G&mB+Agbbbbbbbb", +"bbbbbbbb=vvvv#-u;uu=-=hu;hOhOh;;h&;uuh==hO;h=;=hG;;h;;===h9&m2iAgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbf#vvv#f=hh;h;;u==u=u==;=h=u;=-h=;hOhOO=hhGO=-;;=;Ohh;==hG&Sm2oAgbbbbbbbb", +"bbbbbbbbh#vv##uu;--uuh=-hO;hOhhGGGhh==uh;;;;;hh;;h&O;h=uhOO&x2BMAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh0vvvvf==;;GG;h=u=;;u==;;h=--u=h-u9h=9h;OGG9h==u;;;;;h;OOOGmtB+ggbbbbbbbb", +"bbbbbbbbbvf##v-uuu===;h==;=hG;;OOOGG==uu;=h;;Oh=O&O;GO==;;GGstBi+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbj00vv#u=u=&9;GO;u==;;==;;;u===h;==;uh99=O9O9Gh=;u==h;;OOhOsmmB+Agbbbbbbbb", +"bbbbbbbbbvvvf=v#===Ohh;u=uu;hOG;hhG;;h-;hO;=;;;;=GO=h=hh==hOSttBo+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb600v#0ff=uu9G;==;O;-=u=G=f=;==9hOuuu==hOOO;O9O=;uuhhO=h=;;;&mm2+ggbbbbbbbb", +"bbbbbbbbb0vv#####=h;=h=O;O==;;h9hOhhO=;;;;=uu-ff-h;;uu;OG=;h&st2Bobbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv0vvvvvv##f#;=h=u=hO;-uu;uu-uOh;=h;hhhu;;hh9hOhOO=h;h==uu-u-9St2oggbbbbbbbb", +"bbbbbbbbb0vvvv#fu-uuu;h==h9O==;hO;GG=;Ouu;====f#-;h;=-u==u=;9&xt2iibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;00v00vv#f-#f#;;h=--==u-uuu=uu=-=u;h==h;G===hO;;&;=O;-;====---GstBoggbbbbbbbb", +"bbbbbbbbbcv#vv#f#-fu-u-=hO=Oh;h=;;=;Ghu=u==;u-u==;=====uu==OO9xm22Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#0##000v#----uu;==;u===uu;=f=-=u---uuu;Gh;9=h;;;;uOG=u=u=;;u-;;GSmB+ggbbbbbbbb", +"bbbbbbbbb;vfvvf-f#-fff;hOhh==OGh=;h9;===u=u===u===;;;==u=huO;9Sxtt2Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#0v#v000vvf-uu=u==;h;;=uuhu;=u=;u-uf-f=;O=h;=hGO;;;Oh;===uu==;==hOStBMggbbbbbbbb", +"bbbbbbbbbbfv#0#f#-#f-;-uu;h=GGG=;hOh;=;u=u-u=;;u=;;;==;===h=h;Gsxtt2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=v6v#vvvv##f#-==;===;;;u;u==h==-===u-#-uuuu;;;h&Ghuh9h;===u=-u==;;hGstiMggbbbbbbbb", +"bbbbbbbbbb##f#fff-f=-==uu;hO;=hGGh=hh;=u--=;=;--=;;;=O-u=;;;hO9&smm22bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-6v#f#0v-vf#ff-;=;=fu;h;;h=u-;;;;;u;=uu-=u=u==hhh=;GG9;;9=;=--u;;;=u;&xtiAggbbbbbbbb", +"bbbbbbbbbb--#-ff#f-=;==;hu=;Oh;hhO;=;h==f-==;u-u;;h;;;;-u-=hh9G9GSmt22bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-v##v##----;==-u=h;;u==;Oh;;;=-fu;;hh==--==;==h;u;hO;;hOh;=O;=--u;;=u=;Gm2iAggbbbbbbbb", +"bbbbbbbbbbu#uf###--=hhh;h=hh;=h=hOhO;=;h;;-u=;uu;OG;==uu==u=OOhh9&xt22ibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbOf#v-f#-u=;hGGOG&&G;hhhh;;OGO===u;=u=;9==u;u=hhO;;;uO;=;;;hhOh=;hh=uu==;;OSm2igggbbbbbbbb", +"bbbbbbbbbbbff##f#u=-;;;h;;;O;==hO9h;==O;=;===uu;Oh;=;=u;;;==;;;Oh&sstt2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh9h=;;9SsxsSsxssS&G&9hOGGOh;hu;;====;=;=uh==h=hO=hO;;=;OOOh==hh;=;===u;&sm2+Aggbbbbbbbb", +"bbbbbbbbbbb-##-##-=-=;=;h;=h;=u=OGO;h;hh;h;=u-=======u;=u=;;=;hh;9S&xtt2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbxSxtttttttmmmsSGGGG9hO;=h;;=;h;=;=u=;==;;=O;;;huu=;9Oh;;hhh;h;;-=hO&mB+ggbbbbbbbbb", +"bbbbbbbbbbb-#ffff-u--==hh=-u=;;;=;h;;OG==;Ghu-==;u=;=;;==;;=u;O=hOGG&stt2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBtt222ttttxssSS&9&9OOh=;h===h;;=;uu-;=9=-uu=;;;;O;;OOO==hG=u=h9SmBMggbbbbbbbbb", +"bbbbbbbbbbbbu-----u=--=;O===u=;hO;=;O9G;;=OG;=u=u==hu=--u;=;hhhOhh9GG&xt22bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbi22t222mmmsSSSGGO;;Oh;hhhhh;;;=-==Ohu=;u;;Oh==h99OhuOGO;=O9StBMggbbbbbbbbb", +"bbbbbbbbbbbb--=----u=-u-uuh==uhOOOhhh=;OOh;;hhhuhuh;u=u===-;h;9hhOhOGGSSmm2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2222tmtmmmsSGG9h;;Gh9Oh;;=;=-uu-O==u=OhOhh;;h;OO;h;hOOGxtogggbbbbbbbbb", +"bbbbbbbbbbbb;u--uf#-ffuuf;==u==;OOO;=h;;;;hO;-=;;u;==u;=u=;;Oh;;O;;;;hGSsmmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2t2tmtmxsss&&GGGGOhO;=uu--uuu;==u=;h9Oh=;h;h;;Gh=;9Sx2ogggbbbbbbbbb", +"bbbbbbbbbbbbb-h-vf#fffu==---;;==;hhh=;h=h;===u=;;O=;;=u;;;;=OhGh-==;=;9&sxxmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb22ttttxmxss&&&SGh;;=u-u=u;-f=h;u=hhO;=;;;;h=;=;G&mB+gggbbbbbbbbb", +"bbbbbbbbbbbbb=-#-f-##uOOffu==;;=h==h=hGh;Oh=u=;;G=uOh;GhhhOhhhh=;=huuh&SG&smm2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb22t2ttmmxsS&9OhO=u=hG=--u=;h=;;uh==GO;hh;=uOGmtBMggbbbbbbbbbb", +"bbbbbbbbbbbbbG#-fffu=u--==;Ohu=;;u==hhhO;=h=u;=G==h==hhO9G;;h;u;==;;9;;;9&xmtmmbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2t2ttxmxS&GGOhG;;-u=;h9=u;;;u=;OhO;=O;uO;smtiAggbbbbbbbbbb", +"bbbbbbbbbbbbbbu-##-=--=;=u=GO;==uu=u=;h;u;;=uu;===hh;hhGOGOO=uh;=u=O;=;9hO&mmmmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2tttsxxSG&G9h;h;;=O9;===u=uu;h;=;;===O&x2ogggbbbbbbbbbb", +"bbbbbbbbbbbbbbuuuuu=uh;h==;;;hh=fu=O;=====;u==fu;hh;hhu;OOh=;h;;;hhOh999OOGSsmtmmbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2mtmmxxss&GS9O==O;;O;--=;h;===;h=;;hGmBMgggbbbbbbbbbb", +"bbbbbbbbbbbbbbbu--u==u=;;hu;G;===uu=h=u;=h==;ufuh;;9O==;h;;;hh;h;;hhO;;hhGh&sxxxmmbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2tmmxxxsSGGGO;;O9;==-u=h=u==O=uOhO&tiMggbbbbbbbbbbb", +"bbbbbbbbbbbbbbb-==-ufu-;G;;h;===u=====;;h=u;-=h=h;OhOO=hh&;uu;;=hO;h=;=OGOhGG&&sxmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbttmmsS&&&&OOhhu===;u==;;h;u;;;Ss2igggbbbbbbbbbbb", +"bbbbbbbbbbbbbbbb=uu--=;==h&h;huu;;====;;;ufuu;=-hOh;O;h99GO;=uuh;h;;;hOhhOSG9&G&sxmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbtmxxmSSGs&hh;u=;;===;;h=uu;Osx2+gggbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbu-u-===uOGO;Gh=u;=;;==h======h;=u;uhGh;G9OGG;=u=;=h;hOh;h&GhSG9GSSxmmbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbmmmsSxs&&Gh==;;;==;;;==;h&stBAggbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbb&;u--uuu=GO=huhhuuuuhOu-=;=OhO;u=uuhhO9;hhG;;;-;;Ohu;;;;=GG;O;G&GGSSmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbmxsxm&OOhO=-uu=G=f=;;;&Sm2igggbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbb=-f###vf;;;uu;OOuuu=;uuf;;h=h=h;O==;;hOOO;hO;;;;;==u--f-h;hu=hG&9G&sxx2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbm&sssGOhGG;uuu;=u-uOOG&t2+gggbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbb&--ffvvf=;;u--;uuuuuu=u=uu=uhh==hOh==;hO;9G;;O=u;u==uf#-;hh=uuhhhO&&sxxtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbmxs&9hOh=uuu-=-===OOxtiMgggbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbuuf##f-====u=uuuu=u-==uu--uuu=h9;hO=h=h;;;9h=uu==;uuu==;=;==;=;;hG&GssmmbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbSS&GOh=u==-=u;==;Gs2ogggbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbG---#-fu==;=uu=;uhuu==ufu#-f=hOhh==O9h=;hOh====uu====;u=;;h;==h9h&G&xxmmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbmSG9O9;;=-===u=;&sB+gggbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbb-uuuf-u====;u==;u=-=;-=ff-=uu=;h=GGG;=hOh==;uu=u=;;;u=;hh;=h;hOG9&&smmttt2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbSGG99;=-u===;h&tiAggbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbb&u=##-=u;uh-uu;;=;===u=-=-==uu=hO;=hGGh=OO=;u-u=;=hu-=hhh;G=hh&&Ssxmt22BBBBbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbG9GGO;;-;;=hGm2Mgggbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbb=-#f-u=u=;;---=h=O;=-fu=;==;h==hOh;hhOhu=O==--==;u-u;h9OOG&9G&xmt2BBBioo+oibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbShhOhhOu==hstiAgggbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbb&=-#=;h=-=uu=uu=hh==u=u;hhhhhuh;;=h=hhOO;;hh;;-u=h;=hGSGG&&smmt2iio+MMAAMMoobbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbSOOO9;=-OOx2+gggbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbb;-u;;u-=u-;;====;====;u;;;h;;hO;==hO9Oh;=Oh;;=;;==OGSGSsxmt2Bio+MAgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=f##vvv00v-uSSbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbSOhO=;;hsmBMgggbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbb=u-u----=====;==;=u;;==;;;h;=h;=u=hGO;h;hh;9;h;=OGGssxmtBBo+MAgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbhc##0v#v#v#v#fffhsbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbSO;h;;9xtiAggbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbh-=f-=-==uu;;=u;h=;=;-uu;;O=-==;;h;hO;;OG;;h&GOO&SxxtBBi+MMAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-#v##vf#vff#f---uOSbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbGhOhhGx2+gggbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbb;-uu=f---u;==hh;;;=;;u-=;O=uu==hhO;=;OGGOhhSs&Ssmt2Bo+MAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb9&GG;uuuufuu-GG&4bbbbbbbbbbbbbbbbbbbbbb9#f#-##v0vf#-u==h;=;Sbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb9OO9&mBAggbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbOh-;=f-f-u=-;;;G;h;==;-u-uuh;=uhOhOhOOh9G&&&smt22iiMAgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbhhf##v###v---=uuu--uf-#-fh=u=&bbbbbbbbbbbbbbbbbbbh=-f####v#--;==h=;h;h&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb9GGStigggbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbb;-=-u#uu-u=hOh;;O==u-f=u-;=====;9GOhhGGGSsmtt2BoMAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&;v#ffv###vf###f-uu--=f###vf-#-uuuu==O9&&bbbbbbbbbbbbbbbb9==u----uuuu=uuuu-u;=h&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&O&stiggbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbhu==--=;===O;G;u=u=--u===u-;h=;hOGGOGSsmm2Bi+AAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;=f#v#vv#f-##f#v#fff#u-;u##f####f-u##u;uu=hhO=;9Gbbbbbbbbbbbbbb9hOh;-=u;ufff---u=;h==9sbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&GS2oggbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbb;-h;uh=;;hh;hh===;--=O9---==hh=O;O&Gstm2BB+MAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=-#uf#-f#vv#f=#v-u#;---uu-u-fffu#v#=;###--==u==uh=;&hhGGbbbbbbbbbbbbb&&GGh;;-ff-##-;9=uu;hOG9xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbSGx2+gbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbh==;=;h9=;h======;h==u==hOO=;OG9Gsxt2Bi+Agggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbu#0v#ff-##f#vfv=fv-##---;=u-uu#----f;--#-fu;;--u==-=;hhGh;9h;xbbbbbbbbbbbmSG&9===uuf;-u#uuhOGhh9GG9bbbbbbbbbbbbbbbbbbbbbbbbbbbbbSm2+gbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbh=;hhhhhh=u;====O;==;==;GGOhOG&SxtBB+MAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbfvvvvv0v###v#vvvvf###-uuu=h=O=;ufuuf--=--fu---h;u-u--u-u;;;=hh;;=O9bbbbbbbbbbbSS9GO;u==u-fuuuuO9h;hhh999bbbbbbbbbbbbbbbbbbbbbbbbbbbxm2+bbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbb;hh-=;hhu=h;;;hhOhOOh;=hOOG&&&xt2ioMgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb###ffv60vffv#vv#-###v#-u=-=;fuh;h-u;===;;h=;Oh=uu;=;hu##-===uu==O;;h=;9&bbbbbbbbbbbS&&9GOO;=O;=-u;;hOhu=OG&GGbbbbbbbbbbbbbbbbbbbbbbbbbbt2bbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbO=====u=;h=h;;hOh;;OhG;GsSsxm2BoMAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc##vv-##vvvv#f#vf#c##cf##;=uh;uu=;;u;h;=;==;hh;=;;;u=h;=uu-uu;u-=uhuuO;=;GG9sbbbbbbbbbb&S&GGG9h==;=uuhO=;;=;hG9OG&mbbbbbbbbbbbbbbbbbbbbbbbm2bbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbsO=;;G=-u;==hh;h;;=O&9GSSxmtBiMAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv0f-#v###0vvv#v##--uf#=f#;u==h;O9=;;Ghuu;;=;h;h==uhOh=h;;u=uu=uu===;uu;uu9;9G&&&xbbbbbbbbbbSS&&O;=;Oh=;;=-uuu;;hO9G&&&bbbbbbbbbbbbbbbbbbbbbbmbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbOhGOO;=uuuh;hh;;GGGG&mmm22i+Aggggbbbbbbbbbbbbbbbbbbbbbbbbbbbb##v#f###=fvfvv##f#-f-==-#fu==f;Oh;h;hO9GO;=uuh;hh;=hO;h;G9;;uu===uu==;;u--u;huh&GGS&&tbbbbbbbbbs&GG9Ghh=9O;;uu=;=;;hO9&O99Gbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;GhOhOuuf=;=hhOG9GSmttBi+Mggggbbbbbbbbbbbbbbbbbbbbbbbbbbbcv0#vvf#v#=u#=u##--uu--;uuu==u;;=u;u;9O=9999G;=uu=u;;;Oh;;&9h99=u==h;=uh==uu=u;;;=hh9&sGsmbbbbbbbbbm&&&&hhG9hOO=uu=;===OOOOGG&&mbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbmhhhO===f;hOhhOG&Sm22B+Mgggggbbbbbbbbbbbbbbbbbbbbbbbbbbf0v###v#v#v#;=f-fuu-#--=Ou-==u;9h;uuuuhhh9hhOGO=;u;hOh=;=h==GG;;;;h=-=u;9u-=;u=9O;===;9G&ssSsbbbbbbbbbb&G&9h&&;=;=h=-=-=9=-;OO9sSs&sbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbGOO;;hu=;hhhhOO&smBiMAggggbbbbbbbbbbbbbbbbbbbbbbbbbb-fvv#v#v000000--uf#uhhu-u=;u-#;h;;;;h;hhu;;hOOhh;Oh=;hh;=uu-u-hhhu-;O9u-uu;=uf=h;;=h;;;O=O9&Ssxsmbbbbbbbbb9hh=hhhu-uOO=-uu;=u-=99GGSSssbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb9;GGu=h==hOGSsxtB+Mggggbbbbbbbbbbbbbbbbbbbbbbbbbhvfuvvfv0vvv#v00v-==--f==u-u--=u=uu;uOh;;hhO;;;;9;O&=;O=u=u===##f;hh=u-=;=-=uuuu=uu;uhh;;;h9hhO&ssstmbbbbbbbbbh;=OOh=ufu=u-=u-=u;==h;G&&&sstbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;;;G;u=;O&sxt2iMAggggbbbbbbbbbbbbbbbbbbbbbbbb;0vvvv-f000v#####f-=uu=u=uuuu==u==;;-u-c==;9hOO;h;hh;;99;==;;h=uu=u;===u==u-u==f=uuu---uuu=9hO9;99G&sSmmbbbbbbbbb9OGOh;uu=u--==-=uuuuuu;hOGxsxmbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&h9h;=;OGst2B+Aggggbbbbbbbbbbbbbbbbbbbbbbbbc#-#vv#fvv#v#v#-f--uu=;;;==u=h=O==hGS;=-=-;OGOhh;9GG;hOGOh;;;==;=;=;=;hhh;=u=huh=u;;=-uf-f=;9h;;=OGG9G&xmxxbbbbbbbbb999Ghhu-u;-;u-===-u---=9&&SSSx2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&O;;Oh&sm2oMAgggbbbbbbbbbbbbbbbbbbbbbbbb;0fu-v0#-fv#f##-#-u;;==;hhh;h;hh9;h=&x9;=u=h;;hO9OGSSG;G&GhhO;;h=;hhO;;hOhh=h;;;h=;u=;u=-f-=uu=;h;O&&O;GssSxmmbbbbbbbbbsG9O=;uu=;u=-u=uu-#-u;=h9&Sstmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbGGhGGSm2oAggggbbbbbbbbbbbbbbbbbbbbbbb-v##vv#--#v-u#--#-uh=O;uh9O9h&;hhG9GG&mSG9OOO9GOOG&S&G&sSSGGSOG9hhhGOGO=h99OOG;=;OhOhh=h;;uu==;uu=hOh=OGG&O&xSxmmbbbbbbbbbs9OG;u-====;u;=uu-=u;=;hG&SSxmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbGO&&sx2oAgggbbbbbbbbbbbbbbbbbbbbbbbc0v00###vf-u-fu;==-=hO9O;O9GS&&&SGGGSxmtmS&GGSSsSsxsSxxxsxxxsSSxS&O9&GSGO9GGSGGGGO;;O9OG9h;u=h;h;;O;=hOO;O9G99GxxmsmbbbbbbbbbsGOO=-fu==;Ouu--==;==hh;G&sSxmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&&sm2oMgggbbbbbbbbbbbbbbbbbbbbbbbv###0vv#vf#u=h9hhG&G&O&&SS&smmxxxssxxmBBtmmmmmtttttttmttmtmttttmmmtmmsxsxxssmmxSS&G&GGG&SGOhO;OGGGO9h;OO;OhhOGG&&smtmtbbbbbbbbb&h;==uuu=h==-;-=hhO;hh=GGG&ssmm2bbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbSmtB+Agbbbbbbbbbbbbbbbbbbbbbbb0vvv#vv#u#--;9&&&&&sxxxsxmxxtttttttt22t2BB22222222222B22B2222B22222222tttttmtttttmmxxmxxsssSs&GSGG&GG&OG&hh;hGGG9O9sxmtt2bbbbbbbbbG;hh=uuu;u=uuh==h;hO=OGhOG&xmmttbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbt2i+gbbbbbbbbbbbbbbbbbbbbbbcv60vvv##f=;;hGsmmxmtttt2t22t2B2BB2BBBBBBiiBiBBBiiBiiiiioiioiBBiiiBBBBBBBBBB2222222t2ttttmttmxmxxxsSsSSS&G&&O;h9&GGGGSxmtt2bbbbbbbbbbOh;==;=u==u=;=u;;;;;h;9;h9Smmmttbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbB2Bbbbbbbbbbbbbbbbbbbbbbb=00v000#f;u=OGsmmmt222BBBBBiiBBiiiiioooooooooo++++o+ooo+o+oioioooioooooooiiiiBBiiBBBBBBBB2B22t22ttttmmxmxms&SG&SGGG&O9&SSSm222bbbbbbbbbbG;;;=-u;=u=;uu-;uG;-==hO9G&xxmttbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBbbbbbbbbbbbbbbbbbbbbbb#vv0vvvvuO&&smtt2BiBiio++o++MM++++++M++++MMMMM+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb++oiooiiiBiBBBBiBBBBBB222ttttttxxxsxsxS&G&SssSst2BBbbbbbbbbbb;h;==;=;;=;;=-u;Ohu=;uhO&&&&mt22bbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc0fv###uhO&Stt2BBioo++++++MMMM+MAAAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbboiooiiBBBBBB22t2t2ttmmtmmxxsSSSxmm22Bbbbbbbbbbb&;==;=h;=;==;=u-uuh====9OG&Sxxmt2bbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv#v#f==h&4xt2Biooo+MMAAAAAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbioBBB2B2B222t222tmxxxxxmm222Bbbbbbbbbbb9;;hh=u;=uu---u-u;==u;h9&&&SxmmtBbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#vv--OO9Smt2iio+MMMAAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbboB2BB222222ttmmmmmt2BBibbbbbbbbbbO=;hh;u-u----=u;-f=h;u;O9&G&mmtt2bbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbG#v-c;9sxt2iii+AAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbsS&SGSsx222bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBB2222t2ttttt22iibbbbbbbbbbbOh;hu-u=u-u;O=--u=;h=;h=G9Gmmm22bbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-f=hh9smt2BobbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbG=#v###0v#=;;G&S&msmBbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbi2B2Bt2t22BioobbbbbbbbbbS;h--u-=-;u;u-u;hO=u;;hu;O&Smxtt2bbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-ch9SsmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbGfvvvv0vffvv#-u;;hGGO;OO&s2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBt22222iiobbbbbbbbbbbhu=u-#u=;uu;===O9;=======9&Ssmtt2bbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcu;u9xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&-ff#fu##vv#f-u-fu;9O;;===O;;hSmibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbi22BBiibbbbbbbbbbbbh==u==;=;9hh=uh;hO;--=hOhO9&stttBbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-hObbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;fvv##f####-#f;;;;;;;h9;u;uhuu9=;hStibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBBBiobbbbbbbbbbbS=;u-==;;==h;=;hO;;=uu;O;;9&sxm22bbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbO##0#####v#uh;=h9G9G&G&99hh;;=u;uu9hG&x2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbiiBbbbbbbbbbbbb;u==u=u-u;O9=;hhu==u;u=;hOG&smttBbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbS#000v####-=9O&&mmxmxxmmxxs&&G9=---;;uhS&&tBbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbboBbbbbbbbbbbbb==;uuuuO;h;G9;;=u=;====hhGGGSmtBBbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;#-v000##=h9ssmm222BB22222tmmmsS9Oh=;;;=OOGsmt+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbu-fuu-;;==GGO9O;u=;h;==hhhOGsxt2Bbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbf#f#0vvf=G&SttBBio+iiooiiBB222txmsS&SGh=uu;G&sxtobbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;;ufu-=u=G&;;;;h=-===G=u;O9&tt22Bbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&#v#vv---hSmt2Bio++M+AAAMAAMMMiBBtmtmxS&GOhhh=O&sxtibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;=-f###f#=;huu=OO;-u=;=uu;GGsx22Bibbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh0v#vf;-;SmtBo+AMMgM*,lqn:D::nql,Voo2tmsmS&9OhO;OGSmxBbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb--#ffvvv=h;u-u===-=uu=u;=;9Gxt2Bibbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;0v0vv#c&mt2oMAgggVy%aa%:nDDD::DD%%ayqVitss&&&9OO;9GSxm2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-f-###ff==;=uu==-uu;-=u===;h&xt2iobbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc0vf#v-;st2oMggg*qn:aaa<a::DDD::D%%aa%nnlVimxmSGO=OGGGSxtBgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbff###---=;;;uuu;=;=u===uu=;O&t2Bibbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=0#--##Om2iMggg*qnnnn%a<<aDnDDDDnD%%a<:nn:D:qomSSGG&Gh;&mmmBbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv##ffff==;;u;u=;;==-===uu-=hsxtBiobbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb9vvv0#h&m2iAgggqnnnnnnDa<<<%nDDDD:D%a<a:n:D%:nnV2xS&hO99GGxtmobbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbO-fffv#=;=;;=u-;=;=;u;==uuhh&sm2iobbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&06v##-GmB+ggg*:::nnnnn:a<<N%:D%DD:Daa<ann:%D:nnnqix&&hOOG9&st2Mbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbf##vv#-h=;;;u--=;;hh==fu=;9GSm2Bi+bbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#00v#fGxBMgggq::::::nnnn%NNNa::%DDD%a<N%n:D%Dnnnn::,mGGh;;OGSxm2Abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbf##fvf=O;=u=uuuu=;O;=u;-;OG&smt2i+bbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-00vf#OxBMggA:D::n:n:nnnnDNNC<:D%%:D%aNNDn:%%nnnnn::D,m9O9OhO9Sm2Bgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh##v#u;===h-=;====h=;=u;=;O9&mt2iobbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh00vv-Os2MggADDD:::::::nnn:<>C>DDa%DDa<NN:nD%%nnnn:DDD:,m99GhhO&mt2obbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbf0###f-=-u======;u;=u;h==h9&Sm2io+bbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb00#00u&2+gg*lDDDDD::::::nn:aC$C%:a%DDaNC<n:%%:nnn:DDD:::,mhhOu;9smtBAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv#u#==u;;u=;;u=h;=;;u==hhxxt2iobbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv0vvv-9togggn:DD%DDDD:::::nn%C11a:aaD%<>$%:Da%nnn:DD%DD::n,xh;uhGSxm2ogbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbuvv#v#u=u=u-u=;=;h;;h=;;=u;Osxm2o+Mbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbS06jv#GmiAggqn::DD%%DD::D::nn:C1d<Daa%%N$1D:%<:nn:DD%D:::nnn.Sh;=uOSm22MbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbO-f#v--;u=uuu=u=;;OO=h;=;==;O&t2io+bbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0jj00cs2Mggq:nn::DD%%%D:D:D:n:<rrCD<a%aC1C:Daann::%%%D:::nnnn2O;u=;9xtBogbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbhvv#fv#u=uu===u;hO;;O;==u-u;;GmtBoMbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb4jjj0fGmogg*nn:::::D%%%%D:DD:nnar5dD<<%<$5N:a<Dnn:%%%D:::nnn:Dlxhu-=;&m2BMbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbvvv#u-u==u==;;uhOOO=u=uuuu;h&&mBo+bbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbvj0#uuSBAggn:::n:::DD%aa%DDDD:nDdzz%N>a>r3a:<<nnDDa%%D::nn:::::.Guuh=9xtBigbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0v#uf#-h=Oh;hhh;hO;==;=--hGhh&m2o+Abbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0v0v#ht+ggq:nnn:::::D%%aa%DDDDn:$p NC1<dz8%aC%n:Daa%D::nn::DD:DDx===h;&t2iAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#v--vfu=;O;GO9;;huu;=;=h;;=;9SmBi+Abbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-v00v;sBAggn::::::::::D%a<<%D%%D:NX6115C3 zD$C::Da<%D::n::DD:DD%aZh=uuu9xti+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0vv#vfu;uO9OGOOhu;==u=;h=u;h9&mBi+Abbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#v0#=&toggqD:::n:::::D:D%aN<a%aaDaXjp58r jr<5<:%<Na%D:n:DDDDD%<N<<x--ff;stBogbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv00vf=-;h==OOO;=h;;;hhOh;GOOOGmtB+Mbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbsv##v=sBMgADD:D:::::::D:DDaNC><<Na%pj@3Xz6j$53%%N$>%D:::D%DDaN>N>N<7=#-#h9xBiMbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv0j###=;;===h=hhh;h;=;OOhhhO9&s2i+Agbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcvvv#=miggVDDDDDDD::D::DDDDa$r1$$$<5jjpjXj61X1aC51<%::D%%DaNCCC><<a%&ff--hmtiMbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0vv##uuh9u;;G9=u;h=;hhhh=uhG&GstBoMAbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-v0vuStMggn:D%%%%%DD:D::DD%a>5835311jj6j6j68@N$88$aD:%a%aN$11$CNaa%De=--#-&tB+gbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0vjv=uuh=hhOG9hu=u;;O;;;hOhOOsxt2oAgbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbjv0#hs2MggnnnnDD%%a%%DDDDD%aNdp@www56jjjjjX68r @5>a%Naa>d5rd$N<a%%DDk;f##uGmBoAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv#v0##-h9=999OGOu=u=u;;;Oh;=&SxtBoMgbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbttbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbGvv0#;miggV:n:nn::Daa<aa%D%%<>186j66@Xjjjjj6j8@jXrN>1C$5zz5dCNaa%DDD::9vf#-OtBiMbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#vv00vu;hOO;O9G=;=uhOh;;hO;;&xSx2iMgbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbm=h&xxbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;v00#=xigglDDD::n:n:D%<<N<a<<Cr3@jjjjjjjjjjj66j6wr335w@ 851><a%DDDDDD:xv0#uhStB+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0#0##=#u=hhOhO;hOu;;h;uuu-u-hGSx2iAgbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbGf=hGG&stbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#000-9moggn::DDDDDD:::D%N$dd1158@6jjjjjjjjjjjjj6 @@@jj6pdC<a%%%DDDDDD%Z##0#;9t2Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv#vv#-=;u=;Oh;&;;hhu=;u==-#fhGSxtBMgbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbhv##=9&sxtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv00#-Gt+g*n::::DDD%%%DDD:%>3wwwX6jjjjjjjjjjjjjj6jjjjj6pd><a%%%%a%aaaa%7#vv0#;sm2gbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc000vu-;;=h;=;;;h9;uu==;=uuuuh9GxtiMggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;v##fuhGsm2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0j0#=sBMg*::::::::DDD%a<<aaNr 6jjjjjjjjjjjjjjjjjjjjj6pr$N<<<NNN<<<aaaa7=v00vuOstgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbfjjvfuuuu;9h;;;OO;=;=-u======;9&xtBMggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbO0vvv#uh&xmBibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb000#;xBMg*n::::D:D:DDDDDaN1533p6jjjjjjjjjjjjjjjjjjjjX8z5rd11$C>NN<<aa%Dh0v00#hsxMbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbj000vv-u;GGhu;9h;=;===-=u;h==hO&xtiMggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcvvvvvf;Gxt2ibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbj00uOmiMgqnn:n:::::DDD%%a<>13X@6jjjjjjjjjjjjjjjjjjjjj66 z51$><<a%DDD:::90v0v-;&&ibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0j000#==h;hOOG;=Gu;uuu-;=;;-uhGGxtiMggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb9#0###vv-GstBiMbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbj0#uGmBMgqnnnnnnn::n:::DD%<$rw@jjjjjjjjjjjjjjjjjjjjj6Xzd><a%%%DDDDDDDDD9000#-OGSBbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;0v00#f#=;O=hOOh;=h;=ffu;==uuuhGSx2BMggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-###f##f=hSmBoAAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb##v=&tiMgqn:n::n:n::::::D%aN15w6jjjjjjjjjjjjjjjjjjjjj@X pzz355rd11$C>>N96v0#=9sxibbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb00v#v--f;;;;;;;Ohh;;h;=u=u=;uuG&SstBAggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbb#0vff##vfh&m2iMgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbff-u&mBAgq:::::DDDDD%%a<>158w66jjjjjjjjjjjjjjjjjjjj@ pzrd$CC>>>NNN<<<<aOv0#v=GStobbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb00vv#-f=O==u;OOOh=u;h;==uu=u=OGO&xtiMggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbO#00v#uf#=OxtiMggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb==-;&xBMglDD%D%D%%a%%%%%%%aNr8@jjjjjjjjjjjjjjjjjjjjXz1<aDDDD:D:::::::::h0v##=&mt+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc600v#f-;=Ou-uhGOh;hhhh;h=;-==;hh&stiAggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbj00vvvvf=;GmB+gggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbuuhhOxB+g*:::::n:nn:::D%N5 6jjjjjjjjjjjjjjjjjjjjjjjj6@85Ca%D::::::::::nh00#v=&tBgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0jj0vv=u#uu;;;=;Oh;hhh==h9uu===O=SxtiAggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbb#06000v#u-=&tiMgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;-O9Gs2oA*nnnnn:DD%<>$53p @66666jjjjjjjjjjjjjjjjjX8w8z5d$CCN<a%DD::nn:nc#0#uhsB+gbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh0v0jv#;=-==-=hO;==hGGG;uOGOuu=;=O&x2oAggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbj00v000f-=G&tiMgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbO;-;9x2iM*::D%%<NC$$1dddr535rr3Xjjjjjjjjjjjjjjj6j6w$NNN><a<a<aaaa%%DD:lu0#v-&tiAgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv0000vvff;==u=OhOh;h=h;Oh;;hOh==OOsx2igggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbc06jvv00v#=GxtiMgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbhuu;=GtiMA%a<<N<N>>C>>>N<<aaN5@jjjjjjjjjjjjjjjjj XjX1aDDD%%%%%%%%%%%%%7##vv=&2+ggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc00j000##fhu=-=;OOOh;;;;Oh;O;=;;h;O&m2ogggbbbbbb", +"bbbbbbbbbbbbbbbbbbbbXjj0v0j0#-uhStiMgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbOuf-;hxB+A7aa<<<<<<<aa%DDD%Nz6@ 66jjjjjjjjjjjjjjjz5 X5<D::::D%DDDDDDDDev00#=sBAgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0j0j00v#-;f-u;;u;hOO==h;;;;;h==uh9GStB+ggbbbbbbb", +"bbbbbbbbbbbbbbbbbbbvj0v#j60vf=h&mB+gggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbs=f##=x2oAyaa%%%%%%DDD:::%>3855w86jjjjjjjjj@@jj@jj3<13r>D::nn::DDDDD:D400v-Omoggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbfj0v0jv-;uf--==;==;uh;=9h;;hO;u=h9OGStBMggbbbbbbb", +"bbbbbbbbbbbbbbbbbb00v0000vfc=;9m2ogggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbx--ffh&2i+VD%%%DDD::n::Da>d1N$51 jjjjjjjjjj88XjXw66z%%>$CaD::nnn::::::f00vuG2Mggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbj0000f#--fu=;O==;;;u;=hOO;;9xm9=OGOGstiAggbbbbbbb", +"bbbbbbbbbbbbbbbbb60v000vv#fOh9&tBMggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;f##-GmBiADD:D::::n:D%NCC<%>CN36 @@wj6jjjj3r1@j3rw 3%D%N>N%D:nnnnn::7v00v=xBAggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb000jvv-ffu===hG;u=;=u=uhhh;=hGmh;;hh&x2igggbbbbbbb", +"bbbbbbbbbbbbbbbb0vvvv##-##=h9Sm2ogggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=u#vf=S2iMq::nnnn::%a<N<%D<a%$w83w38@Xjjj63NNr6X>$53d%:D%<<a%::nnnnnxvvv-9togggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0000v#f--O;;=uhhhh=--=;;=;=u=hhmhuuhGsmB+gggbbbbbbb", +"bbbbbbbbbbbbbbb#00vv#v#--=uh&st2+ggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbs#vuf-GtBo*nnnn::D%a<<%DDa%D<5315r$pp8@6jj3a<a363aNC1dan:Daaa%D::nnnu0vvu&2Mggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-v0vvv#-==;;h;u=hO;;=-u=h=u=;;=;mGu-O&StB+gggbbbbbbb", +"bbbbbbbbbbbbbbv6vvv#vv#=h;;9&stiAggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-uv#;Om2iAn:n:DDaaaaD:%aDDa$1NC$CNw13pX668%%D<z >DaNC$<:n:%aaa%:::Z000#;xiAggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#j000v#fuuuu;OO;;hhu==u;u===h=;u;G&G;O&xtiAggbbbbbbbb", +"bbbbbbbbbbbbbb6vvvvvvu==;;&G&xtiAgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-#v-fc42Bo*::D%%a%%::%%::%N1a<N<aN3>138 @8%:D:N33%Da<NC<Dnn:D%%%D:u00v-&togggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=060jvvu--u=O;h=GG;;u====;==;=O=--=9m9Gxm2oAggbbbbbbbb", +"bbbbbbbbbbbbb0jj00v#f=uu;GGGsm2oAgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbS-#-=uhmtBA:D%%%%::DD%::%<$a%aaaDCC<C1rzw3%:DnD>5$DD%a<N<Dnn:DD%%Fvj0v-&2Aggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#fv000#vu==hh=uG9OOO;-=hh===hh===;=httttt2+gggbbbbbbbb", +"bbbbbbbbbbbbv0jvv###uu=;9SGOsx2oggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh;=--;Gm2oV%%%D:::%D::Da>a%a%%DD$aa<$1r35annnn%Cr<:D%aa<<%nn::Dy=6v0#Otigggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbv#fjv0vf==u;;O=;&S;;O=h=-===Ouu;===GOGG&x2oAgggbbbbbbbb", +"bbbbbbbbbbbb#00vv###ff-f-OhGGs2oAgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbSu-uu;&xm2MlD::nDD::nDaN<D%%%D:%>%%a<>$dda:n:n:a$1a::%%aa<%nnnnsvvvvuS2Aggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb4#vv0##v#u==uuu-uf=;huu=9O=--=h=-f=O;h=9O&xB+gggbbbbbbbbb", +"bbbbbbbbbbb-00#00v#f-f#vuhOGGstB+gbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=hu-uO&tt2Ann:DD:::D%aa%D%%DD:<<D%%<<>$1<nnnnnD<$CD:DD%%aa%:ny#-0vuGmiAggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#v#vv=vv-ufuuu=uf##;;h=u-=;=-=-u=-;-=;=9GGSmB+gggbbbbbbbbb", +"bbbbbbbbbbbvfv0jv#----u-=hh99&tBoMbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&-u-uOGxmti*::D:nn:%aa%DDDDD:D<%D%%a<NC$<:nnnnn%NC<:nDD%%%a%:-0v#-=&2Aggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbfv00vvvf=-#fu=;u---u=;==-===uu==-=uu=u--;hGS2iAgggbbbbbbbbb", +"bbbbbbbbbbb#v00vvvfu=uu=u;hOGSx2iobbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc-uhh;Gsm2oqD:n::D%a%:D%DD::D<DDD%aa<NCNDnnnnn:%>>a:::DD%%%O00#f-9togggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbf0#vvvvfuf-uu-u;u=====;;;=uuu;u;;-;===--uu;&mBogggbbbbbbbbbb", +"bbbbbbbbbbcv0vv0vfff=;;==;OOG&xtBi+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbx=u--;h&ttt+qnn:D%a%:DDDD:::aa:DD%aa<N>NDnnnnn:DaN<D:::DDD460f##OxBAggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb00--v0vu-f-=uu=-uu=;===;h;=;u==;==uu==uufu;&SmBMgggbbbbbbbbbb", +"bbbbbbbbbb##v0vvv#-==;--=;;Oh&&xtBBbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&-u=;h9&mt2Mq:D%%%D:DDD::::a%:DDD%%a<<N%nnnnnn:%a<<Dn:::xf##0#OS2Mgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-#v#v##fu#-h-uuu--=;;;fu;;=;;=uu;=;==u=;uu-;h&stoAggbbbbbbbbbbb", +"bbbbbbbbbb-vv#vv0vuu=ufu=;h;O&&Smt2Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbt9;cu;h9Gmm2MlD%%D::D:D::nDaD:DD%%%aa<<%nnnnnnnD%a<%:nnx0vv##u&t+gggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-06v#v0f-uu-u;;=-fu==u-u-=O;;h;u--=;;hh;;fu;OGStBMgggbbbbbbbbbbb", +"bbbbbbbbbbc#vvvff---=;-uhOGh;O9&smt22bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbmG===h;GG4mto,%:::DD:::::%%:::DD%%%a<<%:nnnnnnnD%aa%:xvvvvf;&tiAggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbhvvv0vvv##fu=;;=;;;uu=u==u=hGh===u=uu=hhh=-h-h&Sm2oggggbbbbbbbbbbb", +"bbbbbbbbbb=#vv#ffu--=uu;OOh;;h;GSxmmttbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbxhO9c=;9SxxmBV:::D::::n:%%::DDDD%%aaaa:nnnnnnn:Daa7G000v-;&tiAgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbfvv#0v-vv#-=;h;=uh;;==u==u=hOh;=;uu;=u=uO;;=uOh&xtiMgggbbbbbbbbbbbb", +"bbbbbbbbbb=#f#--f=u;=-u=;;;=;=O9GSsmmmtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbS99Ou-;9s44xtol:::::nnD%Dn::DDD%%%aa%DnnnnnnnnDDFuv#6j#uSmBMgggbbbbbbbbbbbbbbbbbbbbbbbbbbb#0vv0vvv#-##f=Ohh;;h;h;;=;f=====;uu====u;;====hOO&m2ogggbbbbbbbbbbbbb", +"bbbbbbbbbbb###u#fuh=-u=u;=uh=;OhOGSssxmmbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbB9h;hh==9&GSsmB,::::n:D%::::DDDD%%aaa:nnnnnnnny&vj00v#uOmiAgggbbbbbbbbbbbbbbbbbbbbbbbbbb=v606v0-v0v#fu=u;O;;hhh=;Ohuuu==hfh;uhhu=;;==hh;hGGStiAgggbbbbbbbbbbbbb", +"bbbbbbbbbbbfu==-#-GO=uu;-=;;=;==;G9Gsssxxtbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2&O;9h9;;h&sx4x2Vn:n:%D::::DDDDD%%%aDnnnnnnqxffv60vv=GtBMgggbbbbbbbbbbbbbbbbbbbbbbbbbb#0vv0j0v-fv#-fu=O=;=;GGO=uO&hu-;=u;;==uuu=;=;h;;9h&sm2ogggbbbbbbbbbbbbbb", +"bbbbbbbbbbbu-f--u=u;;hh#Ouhhu=uu;;hG&&mSss&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2&OGG99hhO9GG&&x2,n:%:n::::DDDDD%%%Dnnnnk4vvj00v##=StiAgggbbbbbbbbbbbbbbbbbbbbbbbbb##0v00vvv0#vu---=hhhh;;=O;Oh;;hO;=u;=h=;uuu==;h;O&h&Sm2iAgggbbbbbbbbbbbbbb", +"bbbbbbbbbbb=-f-uu-;;=u;;=uh==u;;=;;O&9G&sSG&&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbB&G&&G9h;hhGGGG&&s2.ln::::DDDD%%%%D:,Z;#0j00jv--hStiAgggbbbbbbbbbbbbbbbbbbbbbbbb;#vv#v00000#vf=-=-uhOOhh;;;hhh;O;==;h-===uu====;OOhO&SxtiMgggbbbbbbbbbbbbbbb", +"bbbbbbbbbbbb#--f--u==u==hh=h;u==;;;;G9SGO999OOObbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbboxG&SGG=;h=hhhhG=;GGte.kkyy:yyZZeS;#000000v#--OxBoAgggbbbbbbbbbbbbbbbbbbbbbbb;0####v0000vv#f=ff=;=u;hhO==h=;;=;huu=;O;;;===;;;uhGGG&Sm2+ggggbbbbbbbbbbbbbbb", +"bbbbbbbbbbbb-u;--==-f-;;h;uOh=OhhhOhOhGh;9Gh;O&&hsbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbms&GS99G;hO;=uu;h9;-hG;Gh;;;uf#u#v##000f=u;&mBMggggbbbbbbbbbbbbbbbbbbbbbb;#vv#vfv0vfvvvu;u#f-=;;u===h;=Gh;hh;u-=;O;==O=hOOOhhOO&&&mBoAgggbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbb===u-u=-;=Ghu;=hOOOG9h;h;=;hhh;9O&G9GGsbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBx&&&S&Gh;h;-;u9;-u-u==uh=ufffvv#v#v--=OGm2oMggggbbbbbbbbbbbbbbbbbbbbb9v-#fvv#0vv###u-=ufu=hh===h;u;=hOO;;;;=;=OO=;=;OOhGO9hOG9&m2iMgggbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbb===#u---u=;uuhh=;O9OGhO;u;;u=;9h9xtmm9S&O&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbotssss49GO==cu=ufu=u-=;uhuu-#####-;O9&m2iMAgggbbbbbbbbbbbbbbbbbbbbb-v#u#u###vv###fu;u-u===OG=u===u=uhhh=;;==u=;=u;;h=OGOG99GG&xtiMgggbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbhu---=ff-uu;hh;hO=OGOO=;hh;;;OOGm&&9hOO99O;=hSbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbimxxsS&S9;;=u==;--=#-;=;--===;h&sxtBi+AggggbbbbbbbbbbbbbbbbbbbOfv#fvv-#-#v#--fu;;==Ohh=uh;hh=--=;;=;===h=uuuu;;O;hO;;9GGGGSmti+ggggbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbf=-=f-=-#uh;;hO=u;hh;;hh=h;;h&xGhh;h=h99h;u==h9&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbimxxmsSxGh;Gh=;;---u==;hGO&sxt2Bi+AAgggbbbbbbbbbbbbbbbbbbb###v##v0v####-uf===;hO;h;h=u;hhh;uuu=O=u==h=-h=-f;h;OOhu;h9OGSxtB+ggggbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbO==--=#-=u;;hOOh=hh9;==h;=h;OmG=uhOh=hh;u;==;=;=h;OG&bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbi2mmtxxxSS&G99O-hhGGGSmmt2BioMAggggbbbbbbbbbbbbbbbbbbc0#0#v##f-v##c-ffu=u==;h;=u;OO=;hhu==u;u===;;;=;=-;=h;Oh99=OO&&&xtB+ggggbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbb;;-#ff=u-hOhhhhhO9&h=u==;hOGxhhh;;;9h==uu=====;;hhu-==G9bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+2tmtmxxmsGGOOOSmmmt2Bio+MAAAggbbbbbbbbbbbbbbbbbc000v#6vuf#f#--=h;-f--;=O;;;;O;h;GO;;=u===;==;=hu--=u;-=GOOOhOO&sxxmBoAgggbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbb=uu=-=;-uh=hG;=G99OG;=-==hmGhO;=;9G;Oh--=;=u=-Ou;u=;uhO=u9hsbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbAoi2tmmS&sGhssttii++AAgAggbbbbbbbbbbbbbbbbO=#vvvv0v#vv#v#cc#;;hh9;=u-;uh;=hh;=GGOOO;-=h;===h;;===u;h;=h;=GG;&Sxm2Boggggbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbb==uh;h=--fuOOh9;hOGh=;u;;GmO;;h;9&9u9=;u-f=-;=-u=uu;OO=u=-uhO9G9GbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbA+222m&G&stBMAgAgggbbbbbbbbbbbbbbb9f##-0vvvv#--#vvvv-uu==u;O9-;u=;hh=;;O=;&&;hh;;=-===O=u;===OOh;uu-h9GGSSm2BoAgggbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbb9;h=;u;=h=-;hOOOO;;9;u;9&x;=uu-fO;;u-;9;-f-=;u##hu=u=;;=h=-;;9hOhhh9;mbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgbbbbbbbbbbbbbbbbbbbb-f;-000v-v00##v#v-##-u#-=h;hhh=Oh==hh=uuuuuf;;huu=GO=u-=h=-f;h=O=O=;;G=hGSxm2B+Agggbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbb;h=G=;==;h=;;OOh9G;;9;;x9==u##-=h;=-u=;--------#u;fhu=u==;u=uhO;hG==O;-=uu;mbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc0#-f#00###0#6vv0#0#-vc---u-==uuhOhh&;=h;u====uf#f=hh=--=;=-;-u=-=-=h=hO;;hhO&G&m2B+ggggbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbOu=u;u=OOh;=;=;;h;9h;-hm9=u-u-=;;=uuu=u--uu---uuf#--u-=hh;;u=u=u;;hhuf-=u=---f-=u=uhmbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbs-f#fv#vvv###vvvv#0vvv0vvv#v0v#---hhO;=;=;=;h;O;uu==;uu-u-=;==uu==-uu=-uu==u--==;hGGSSsm2i+ggggbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbb;=-=h9O=;;hOh;;;9h===;s9;=uu=u=;;;=u-=;uh-u==--#f##fuhhuuu=;=uuuh;u-u-f-=u--u-uuu=u-#-uf=-#uu-######u;;---u=u---=u-#f#vvf##v#v#####v0v#v-#vf########=h9=;=hOh;;=hO;u==uu;==u===;;;==uu;u;=u==;u---fu;G&GSxt2oMggggbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbb=O;h==h=O9G;u;Ghu;hu=Gs;=;;==;h=;=;===;u=-==--ff#=u=u-;u;99=-=h=-u=f-u##fu---u==ufu--uuf-#--#f#vv#-ff#u-u;h=v-;u##-v##vvv##v##ff######f#fvf-#####-=uuu;;;GGOu=GO=;;u==-uu;;u==;h;==u=;;==u;;uuuf-uhhOGsxtB+Mggggbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbb9h;;OOhhhOO9O=Ohu==-;s9=;u-==;;uh-u=;;==uu;u=fu-uu-u;h;;;h;hh-=;--f###u-u-#---u-=###u---#f-#f####f##-=uuu==u=#-=###vvvf#f#0v#ff#-###uf---fuuu#-uu=-u;hhhhhOh9=;O===-u-;=;;-u;;=;;=uu;=;;=u===u-;;OhGst2B+Aggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbOG9hh9O;;9Oh;=;h=ufuh===fu=h;;;h=--u=;=Oh=u-uuu;u;=uuhh==Ohh=uu=u-##u---###u=--=-###-u-=uf#v###-##-##uuf#=u=-f#-fvvv####v##-u--=-###u=u;;=u#uuu;u=;=uhh;=OOO;;=h;u-f===u-u-;h;;h;u-u;;;h;;=-=;hOGSxmtiMAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbb&GOOO9;O;;OOhhh;h==u==;u-;O9h===uu-=;;h=uu=-;hh;hh=;=h=hu;hhh;;u=uufu-u-fu=h=f--#f##-u=-f#-#-uuuuuf#-u-uff-uu-----fv-#-##-=h=--ufuf-=;h=u-=f=hhh;h;u;h;h;;hOhh;;h;=-==;=uuOGh===u=uu=hhh==h=h&Ssm2BiMggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbb&G&&OhhhGOOhu=h;;=uu=uu;OOh==;-=;=u=;;==uu;=;;hhh=hO=;=;OOhh=u;h==--u--u;h;uuu#uu-f--=--#f-fuuuu=-u=f-fu;===--uuu-ff-f--;h==u=fu==u=uh===u;==;;;h=;O;==;OOhO==;;;==uu=u=hhh;=;u=h====O;h;;GGSxt2BoAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbSGSGh;O9GOhh;O;;O=;=uu=;;;==u;====;;===u;;u=;=;;;;hhuu;hGh;;;hh=h===fu==u=uu-uuuu-uu-uuf==#-uuuu==;=f#u;O;uuu;==;u==#u====ucu==u=u;;=====;u=;;;;;h;O=u=hGO;;;hhh;;;;f==;;=;=======hh;;OhGsSxtBo+gggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbG&G&GOOGGhhh9;;;O;u-=u;=uhu=h=u;;=-;h===;-====9u-=u;=;=h9;;hO==;O;-u=u==u;uuh=uu==-u;uuu=-uuuuh-f-u===-;O=;;h;==h;--uuu;-h=u;;==;;-=h=u=;uuu==G=u===;;=h9;;hhh=;hhu-u==huh==h;==hh=hGGGSmm2BoAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbb&G&&&&Ohh9&&;==GG;uu;u==h===uu;==;h;;h=;=--=OO;uu=u;;O==;hGGh=uGG;u-=uu=;=uuuu===;;;=;u==-f=hO;-uu-;;O===hO9h=u9G;u-;uu=;===-u====;;=h=;;u-=;9;uu=u;;O;;=hGGO==O&huu;;u=;=====;hhO&&Smm2Bi+Aggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbxGsSSSGG9h9OhO;OhOh-huhhu=-uu==;h;Gh;;;=;u=f;u;;=uhhhO;;h=O;hh=hhh;u;=hhu=-uu===;;9h=h=u;u=f=u;==u=hhh;;;;O;hh=hhO;u;=;hu=-u-===h;9O=;==;u=f;u;==u=hhhh;h;O;hh=hhG;=uh=O=;u==hh9&SmttBB+Aggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbsxxss&GGOG9hOO==;;=uhu;u;;==u;O;;;9;u=ufuu-;;==u=h9Oh;h;;OO;hh===;;-;u=u===uuhOh;;O;==uf-uf=hu=u=h9Ohh;;;hhhhh=u==;-===u===uu;Oh;;9hu=u--u-uh==u=h9Ohh;;;hOhhG==;;h-;;;;;hOOGSmmt2i+Mggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbssmxsG&G9OOhhhu=;hh=O;u=u==;;9h9h=uuu-u-u==--=;==;OOhu;;==;;;h-=uhh=h=u====;uhhOh=u-uf-fu==f-=;=u;OOhu=;==;=;h-=uhh;;;=====huhOOO=uuu---u=h--=;;u;OOh=;h;;h=;hu==hO;OhhhGGSxxtBi+MAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbtSsxSsxG&&Oh==hhO;uhh=9Ohhh;hh9;u;;u-uhOu#-u=h==;==h=hG;hO;=u-;;h;=hhuOh;hhh;;9;u;;u--hh=f--=;==;=uO;;G;hhh=u-=hh;=;huOOhhhhh;9;u;hu--hh=#-u=;;=;==O;;Gh;hh;uu=hOOhO&GSsmm22ioMAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbmxxmmssG&Gh9;&O=h;hOOhGOO;h;u=;;;u;=;u-=;h;=;=h==;;hOh;;h;uh=GO===hhOhGOO;;huu===u;=;=f=;hh=;=;;=;=hOO;;;huh=99u;=hhO;GhO;;huu;==u;=;=f=;;h=;;hh=;;hOO;hhh=h;G&hOG&xmm22io+Aggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbxmxmSsSGG999h;9O;;9GOGhOh=;==u;hh=u==;=GO;u;==uu;hhOu;;=uu;;u=hh;;OGOG;Oh=;;===hh=u====O9;u;=uu==hhh=;;==u=;=u;;h=hGOGhhh=;==u;hh=u====OG;=;==u==hhO;;h;;;OGGGSxmm2Bi+MAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbtmxxxmSGGG9GGGOOG;OG99;=;h;;;hh;hOO;u;Ohhhu-u=h==;===Ouuuuu;;h;;OuhGO9;=;h;=;hh;;Oh;u;hhhhu-uuh==;===hu-uuu;hO;;9=;GO9h=;;;;;hh;;9hh=;OO;h=-u=h;;h=;;Gh;hOGSstm2BBoMAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbtmmxxmsG&s&&&&hhhOOhhOh;hhhh9Oh;h;;uhhhh;uu==h=-==huuOu--h;;hO===;h;;hh=h;hhOhhhh;;=;hhh;uuu;h=u==huuO=--;;;hO;==;h;;hh;h;;hOOhOhh;u;hhO;=u==O;=hhGhOS&&Smt2BioMAAgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2mtxxxxxsSss&OGGGO;hOh;h;hh;==O9h=hO;u==u==;=;;h=u;-u==h;hO9Ouhh9;==h;=;;hh;==hOO=hhhu==u;u;==;;==;uu;uh;hhOOuhh9;=;hh;hhhO;;u;OO;hOh==;=h;hhOGG&&ssstt2ii+AAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2xtmxmtmxxssSsx&hhh;OOGh;;hhhOhGO;;=u==;==;;;Ouuuu;;u;9Ohhhhh9&O=u==;;9;;=;h;hhOO=;u=u=====;;hu-u-=;-;9OhhhOh9&G;u==;;O;;=hOhOhGOh;=;;;hOOG&&xSsmttBBoMAgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2mmtmmtmstxxsxGO;OO;9OOGO;hGGO9O=u;h;;==O=;u=;uhhu=O=;GO=&9GOG;=u=;uh;;Oh;;9GOOO=-;hh===O=;u==u;h==h;;G9=GGGOGh=u=;uhhhOO;;9&GGGO;O&&&&&mmmt22Bi+MMgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2mtttttmmmmxSS9&G&GO99GOGsG;Ghh;;-;=h;==;==;OO;=uuuOhOO;hOG9;;==hhO=hhO;OSG;9hh;=-;=;h==;==;G9;==uuhOhhhhhG9=;=;hOO=hhGh9Ssh&&G&GGSsmtttBBio+Agggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbtt222tttmtxssxs&G9OOh;G9O;=O&O=u=;9=--O;h;;h;;h;u;h9OhOh;O;u;hh;==uu=fhhhuu;Ghuuu=9=--h;;;=O=;;hu;hGOOOO;OO=;O9h;;=hh=G&&9Gsmmxmm2BBBi+MAgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbt22222tmtmxxssSGO;OG&G9;;hOh;hu;;==u;9uGhh;h;O;;=OGhO&;;Oh=====u##f;;h=-u=;=u=-uuu;-;Ou9hh;hhhh;;OGOO&h;9OhhOh9h;;hSsxxsmt222iBo+MAgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb22222tmttmmxxSSSssSGGG&9hhhO;;;;h=u=;h;hGG9Ohh;h;hO99hu=;;;u=uu=;h;===;;uu=;u==u=u-=;h=;99GO;OhOh9GG&GhhGG&G&&SSmmttt2Biio+MAAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbB2222tt2tmmtmmmxxxS&&&GsG9&G9hhh;==O&&OOOOGOO9hGGh;;;=;Oh;=;=h;hhh===h=O;=hhh=u=uuuhG&h99O&GGGG&S&GSS&Smmxmtt22iiioo+MAAggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbB2t22222t2tttmmmmmxssSSsGG9OOGGG99GG&ss&hOS&hOGhhO=;;OOhhO9OO;O;hOOhh=hO=;;u;;G99O&G&sxsG&mxsxmxmmmtt2BBiio++MAAAgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBB22222222ttttttmmmmmxSssssSSsxsssxsssGSsGGGOOO&G&GhGG&GG&999&G&GG9&GGhOGG&GGsssxxmmmtmtttt222BBiioo+MMAAgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBiBBBB222222222ttttmmtmtmmmtmmxtmmxsxxsS&&sSsS&&&ssssxS&G&SssxxsS&sssxxmmmmtttt22B22BBiBBio++MMMAAggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbiiBBBBBBBBB222BB22222tt222t2t2tttttmmmmmmmmmtttmmmmmxtttttmmtmt2t222222BBBBBiooo++MMMMAAAAgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbooBBBBBBBBiiBBBi2B2BBBBB2222B2222222222222t222222B2222B2BBBBBiiooo++M+MMMMMAAAAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbo+iiiiiiiiBiioiiiioiiiBBBBBBiiBBBiBBiBBiiiiiiioioo++o+++M++MMAAAAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+++++oioioioooiiooiooooo+o+o+oooo++o+o++++MMAAbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbggggggggggbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbggggggggbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbggggggbbbbbbbbbgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbgggggbbbbbbbbgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbggggggbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggggbbbgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbggggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggggggggggggggggggggggbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbggggggbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbggggggbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbggggggbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbgggbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbgggggbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbggbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbggggggbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggbbbbbbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggggggbbbbbbbbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbggbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbggggggbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbggggggbbbbbbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbgbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbggggggbbbbbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggbbbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbggggggbbbbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbgbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbggggggbbbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbgbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbgggggggggbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbbbbbbggbbbbbbggggbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbgggbbbbbggggggbbbbbbbbggbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbgggggbbbbbbbbbbbggbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbgggggggggbbbbbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbggbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbgggbbbbbbggggggbbbbbbbggbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbggggggggggggggggggbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbgggggggggbbbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbggbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbgggbbbbbbbggggggbbbbbbggbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbggggggggggggggggggbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbggggggggbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbbbbbbgggggggggbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbbbbggbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbgggbbbbbbbbgggggggbbbbggbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbgggggbbbbbbbbbbbggbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbgggbggggggbbbbbbbbbbbbbbbgbbbbbbbbbbbbbbbbbbbbbbbbbggggggggbbbbbbbbbbbbbbbgbbbbbbbbbbbbbbbbbbbbbggbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbgbbbbbbbbbbbbbbbbbgggbbbbbbbbbbggggggbbbggbbbbbbbbbbbbbbbbbgbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbgbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbgggbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggggggggggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbggggggbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbggbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbgggggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbggbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbggggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbggbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbggbbbbbbb", +"bbbbbbbbbbbbbbggbbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbbgggbbbbbbb", +"bbbbbbbbbbbbbggbbbbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbbbbbbgggbbbbbbbb", +"bbbbbbbbbbbbgggbbbbbbbbbggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggbbbbbbbbbggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbbgggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbggggggbbbbbbbbbbbbgggggbbbbbbbb", +"bbbbbbbbbbggggggbbbbbbbggggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbggggggggbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbggggggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggbbbbbbbbbbbbbbbbbggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbgggggggggggggggggggggggbbbbbbbbb", +"bbbbbbbbbbgggggggbbbbggggggggggggbbbbbbbbbbbbbbbbbbbbbbbbbbgbbbbbbgggggbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +}; diff --git a/frontend/xsane-preferences.c b/frontend/xsane-preferences.c new file mode 100644 index 0000000..8c13c5d --- /dev/null +++ b/frontend/xsane-preferences.c @@ -0,0 +1,292 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-preferences.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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-preferences.h" +#include "xsane-rc-io.h" + +/* --------------------------------------------------------------------- */ + +#define POFFSET(field) ((char *) &((Preferences *) 0)->field - (char *) 0) +#define PFIELD(p,offset,type) (*((type *)(((char *)(p)) + (offset)))) + +#define PRTOFFSET(field) ((char *) &((Preferences_printer_t *) 0)->field - (char *) 0) + +/* --------------------------------------------------------------------- */ + +Preferences preferences = + { + 0, /* no default filename */ + 0137, /* image umask (permission mask for -rw-r------) */ + 0027, /* image umask (permission mask for -rwxr-x----) */ + 0, /* no fax project */ + 0, /* no default faxcommand */ + 0, /* no default fax receiver option */ + 0, /* no default fax postscript option */ + 0, /* no default fax normal option */ + 0, /* no default fax fine option */ + 0, /* no fax viewer */ + 210.0, /* fax_width: width of fax paper in mm */ + 296.98, /* fax_height: height of fax paper in mm */ + 0.0, /* fax_leftoffset */ + 0.0, /* fax_bottomoffset */ + 0, /* no doc viewer */ + 80.0, /* jpeg_quality */ + 7.0, /* png_compression */ + 5, /* tiff_compression_nr */ + 5, /* tiff_compression_1_nr */ + 1, /* overwrite_warning */ + 1, /* increase_filename_counter */ + 1, /* skip_existing_numbers */ + 1, /* tooltips enabled */ + 0, /* (dont) show histogram */ + 0, /* (dont) show standard options */ + 0, /* (dont) show advanced options */ + 0, /* (dont) show resolution list */ + 10.0, /* length unit */ + 1, /* main window fixed (1) or scrolled (0) */ + 1, /* preserve_preview */ + 0, /* preview_own_cmap */ + 1.0, /* preview_gamma */ + 1.0, /* preview_gamma_red */ + 1.0, /* preview_gamma_green */ + 1.0, /* preview_gamma_blue */ + 1.6, /* gamma */ + 1.0, /* gamma red */ + 1.0, /* gamma green */ + 1.0, /* gamma blue */ + 0.0, /* brightness */ + 0.0, /* brightness red */ + 0.0, /* brightness green */ + 0.0, /* brightness blue */ + 0.0, /* contrast */ + 0.0, /* contrast red */ + 0.0, /* contrast green */ + 0.0, /* contrast blue */ + 1, /* rgb default */ + 0, /* negative */ + GTK_UPDATE_DISCONTINUOUS, /* update policy for gtk frontend sliders */ + 0, /* psrotate: rotate in postscript mode (landscape) */ + 0, /* printernr */ + 0 /* printerdefinitions */ + }; + +/* --------------------------------------------------------------------- */ + +static struct + { + SANE_String name; + void (*codec) (Wire *w, void *p, long offset); + long offset; + } +desc[] = + { + {"filename", xsane_rc_pref_string, POFFSET(filename)}, + {"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)}, + {"fax-command", xsane_rc_pref_string, POFFSET(fax_command)}, + {"fax-receiver-option", xsane_rc_pref_string, POFFSET(fax_receiver_option)}, + {"fax-postscript-option", xsane_rc_pref_string, POFFSET(fax_postscript_option)}, + {"fax-normal-option", xsane_rc_pref_string, POFFSET(fax_normal_option)}, + {"fax-fine-option", xsane_rc_pref_string, POFFSET(fax_fine_option)}, + {"fax-viewer", xsane_rc_pref_string, POFFSET(fax_viewer)}, + {"fax-left-offset", xsane_rc_pref_double, POFFSET(fax_leftoffset)}, + {"fax-bottom-offset", xsane_rc_pref_double, POFFSET(fax_bottomoffset)}, + {"fax-width", xsane_rc_pref_double, POFFSET(fax_width)}, + {"fax-height", xsane_rc_pref_double, POFFSET(fax_height)}, + {"doc-viewer", xsane_rc_pref_string, POFFSET(doc_viewer)}, + {"overwrite-warning", xsane_rc_pref_int, POFFSET(overwrite_warning)}, + {"increase-filename-counter", xsane_rc_pref_int, POFFSET(increase_filename_counter)}, + {"skip-existing-numbers", xsane_rc_pref_int, POFFSET(skip_existing_numbers)}, + {"jpeg-quality", xsane_rc_pref_double, POFFSET(jpeg_quality)}, + {"png-compression", xsane_rc_pref_double, POFFSET(png_compression)}, + {"tiff-compression_nr", xsane_rc_pref_int, POFFSET(tiff_compression_nr)}, + {"tiff-compression_1_nr", xsane_rc_pref_int, POFFSET(tiff_compression_1_nr)}, + {"tool-tips", xsane_rc_pref_int, POFFSET(tooltips_enabled)}, + {"show-histogram", xsane_rc_pref_int, POFFSET(show_histogram)}, + {"show-standard-options", xsane_rc_pref_int, POFFSET(show_standard_options)}, + {"show-advanced-options", xsane_rc_pref_int, POFFSET(show_advanced_options)}, + {"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)}, + {"preserve-preview", xsane_rc_pref_int, POFFSET(preserve_preview)}, + {"preview-own-cmap", xsane_rc_pref_int, POFFSET(preview_own_cmap)}, + {"preview-gamma", xsane_rc_pref_double, POFFSET(preview_gamma)}, + {"preview-gamma-red", xsane_rc_pref_double, POFFSET(preview_gamma_red)}, + {"preview-gamma-green", xsane_rc_pref_double, POFFSET(preview_gamma_green)}, + {"preview-gamma-blue", xsane_rc_pref_double, POFFSET(preview_gamma_blue)}, + {"gamma", xsane_rc_pref_double, POFFSET(xsane_gamma)}, + {"gamma-red", xsane_rc_pref_double, POFFSET(xsane_gamma_red)}, + {"gamma-green", xsane_rc_pref_double, POFFSET(xsane_gamma_green)}, + {"gamma-blue", xsane_rc_pref_double, POFFSET(xsane_gamma_blue)}, + {"brightness", xsane_rc_pref_double, POFFSET(xsane_brightness)}, + {"brightness-red", xsane_rc_pref_double, POFFSET(xsane_brightness_red)}, + {"brightness-green", xsane_rc_pref_double, POFFSET(xsane_brightness_green)}, + {"brightness-blue", xsane_rc_pref_double, POFFSET(xsane_brightness_blue)}, + {"contrast", xsane_rc_pref_double, POFFSET(xsane_contrast)}, + {"contrast-red", xsane_rc_pref_double, POFFSET(xsane_contrast_red)}, + {"contrast-green", xsane_rc_pref_double, POFFSET(xsane_contrast_green)}, + {"contrast-blue", xsane_rc_pref_double, POFFSET(xsane_contrast_blue)}, + {"rgb-default", xsane_rc_pref_int, POFFSET(xsane_rgb_default)}, + {"negative", xsane_rc_pref_int, POFFSET(xsane_negative)}, + {"gtk-update-policy", xsane_rc_pref_int, POFFSET(gtk_update_policy)}, + {"postscript-rotate", xsane_rc_pref_int, POFFSET(psrotate)}, + {"printernr", xsane_rc_pref_int, POFFSET(printernr)}, + {"printerdefinitions", xsane_rc_pref_int, POFFSET(printerdefinitions)} + }; + +/* --------------------------------------------------------------------- */ + +static struct + { + SANE_String name; + void (*codec) (Wire *w, void *p, long offset); + long offset; + } +desc_printer[] = + { + {"printer-name", xsane_rc_pref_string, PRTOFFSET(name)}, + {"printer-command", xsane_rc_pref_string, PRTOFFSET(command)}, + {"printer-copy-number-option", xsane_rc_pref_string, PRTOFFSET(copy_number_option)}, + {"printer-resolution", xsane_rc_pref_int, PRTOFFSET(resolution)}, + {"printer-width", xsane_rc_pref_double, PRTOFFSET(width)}, + {"printer-height", xsane_rc_pref_double, PRTOFFSET(height)}, + {"printer-left-offset", xsane_rc_pref_double, PRTOFFSET(leftoffset)}, + {"printer-bottom-offset", xsane_rc_pref_double, PRTOFFSET(bottomoffset)}, + {"printer-gamma", xsane_rc_pref_double, PRTOFFSET(gamma)}, + {"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)} + }; + +/* --------------------------------------------------------------------- */ + +void preferences_save(int fd) +{ + Wire w; + int i, n; + + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + xsane_rc_io_w_init(&w); + xsane_rc_io_w_set_dir(&w, WIRE_ENCODE); + + for (i = 0; i < NELEMS(desc); ++i) + { + xsane_rc_io_w_string(&w, &desc[i].name); + (*desc[i].codec) (&w, &preferences, desc[i].offset); + } + + n=0; + + while (n < preferences.printerdefinitions) + { + for (i = 0; i < NELEMS(desc_printer); ++i) + { + xsane_rc_io_w_string(&w, &desc_printer[i].name); + (*desc_printer[i].codec) (&w, preferences.printer[n], desc_printer[i].offset); + } + n++; + } + + xsane_rc_io_w_set_dir(&w, WIRE_DECODE); /* flush it out */ +} + +/* --------------------------------------------------------------------- */ + +void preferences_restore(int fd) +{ + SANE_String name; + Wire w; + int i, n; + + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + xsane_rc_io_w_init(&w); + xsane_rc_io_w_set_dir(&w, WIRE_DECODE); + + + while (1) + { + xsane_rc_io_w_space(&w, 3); + if (w.status) + { + return; + } + + xsane_rc_io_w_string(&w, &name); + if (w.status || !name) + { + return; + } + + for (i = 0; i < NELEMS (desc); ++i) + { + if (strcmp(name, desc[i].name) == 0) + { + (*desc[i].codec) (&w, &preferences, desc[i].offset); + break; + } + } + if (!strcmp(name, "printerdefinitions")) + { + break; + } + } + + + n=0; + while (n < preferences.printerdefinitions) + { + preferences.printer[n] = calloc(sizeof(Preferences_printer_t), 1); + for (i = 0; i < NELEMS(desc_printer); ++i) + { + xsane_rc_io_w_space (&w, 3); + if (w.status) + { + return; + } + + xsane_rc_io_w_string(&w, &name); + if (w.status || !name) + { + return; + } + + if (strcmp(name, desc_printer[i].name) == 0) + { + (*desc_printer[i].codec) (&w, preferences.printer[n], desc_printer[i].offset); + } + else + { + break; + } + } + n++; + } + +} diff --git a/frontend/xsane-preferences.h b/frontend/xsane-preferences.h new file mode 100644 index 0000000..19482fa --- /dev/null +++ b/frontend/xsane-preferences.h @@ -0,0 +1,122 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-preferences.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifndef xsane_preferences_h +#define xsane_preferences_h + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#include <sane/sane.h> +#include <gtk/gtk.h> + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +typedef struct + { + char *name; /* user defined printer name */ + char *command; /* printercommand */ + char *copy_number_option; /* option to define number of copies */ + int resolution; /* printer resolution for copy mode */ + double width; /* printer width of printable area in mm */ + double height; /* printer height of printable area in mm */ + double leftoffset; /* printer left offset in mm */ + double bottomoffset;/* printer bottom offset in mm */ + double gamma; /* printer gamma */ + double gamma_red; /* printer gamma red */ + double gamma_green; /* printer gamma green */ + double gamma_blue; /* printer gamma blue */ + } +Preferences_printer_t; + +typedef struct + { + char *filename; /* default filename */ + mode_t image_umask; /* image umask (permisson mask) */ + mode_t directory_umask; /* directory umask (permisson mask) */ + + char *fax_project; /* fax project */ + char *fax_command; /* faxcommand */ + char *fax_receiver_option; /* fax receiver option */ + char *fax_postscript_option; /* fax postscript option */ + char *fax_normal_option; /* fax normal mode option */ + char *fax_fine_option; /* fax fine mode option */ + char *fax_viewer; /* fax viewer */ + double fax_width; /* width of fax paper in mm */ + double fax_height; /* height of fax paper in mm */ + double fax_leftoffset; /* left offset of fax paper in mm */ + double fax_bottomoffset; /* bottom offset of fax paper in mm */ + + char *doc_viewer; /* doc viewer for helpfiles */ + + double jpeg_quality; /* quality when saving image as jpeg */ + double png_compression; /* compression when saving image as pnm */ + int tiff_compression_nr; /* compression type nr when saving multi bit image as tiff */ + int tiff_compression_1_nr; /* compression type nr when saving one bit image as tiff */ + int overwrite_warning; /* warn if file exists */ + int increase_filename_counter; /* automatically increase counter */ + int skip_existing_numbers; /* automatically increase counter */ + + int tooltips_enabled; /* should tooltips be disabled? */ + int show_histogram; /* show histogram ? */ + int show_standard_options; /* show standard options ? */ + int show_advanced_options; /* show advanced options ? */ + int show_resolution_list; /* show resolution list instead of slider ? */ + double length_unit; /* 1.0==mm, 10.0==cm, 25.4==inches, etc. */ + int main_window_fixed; /* fixed (1) or scrolled (0) main window */ + int preserve_preview; /* save/restore preview image(s)? */ + int preview_own_cmap; /* install colormap for preview */ + double preview_gamma; /* gamma value for previews */ + double preview_gamma_red; /* red gamma value for previews */ + double preview_gamma_green; /* green gamma value for previews */ + double preview_gamma_blue; /* blue gamma value for previews */ + double xsane_gamma; + double xsane_gamma_red; + double xsane_gamma_green; + double xsane_gamma_blue; + double xsane_brightness; + double xsane_brightness_red; + double xsane_brightness_green; + double xsane_brightness_blue; + double xsane_contrast; + double xsane_contrast_red; + double xsane_contrast_green; + double xsane_contrast_blue; + + int xsane_rgb_default; + int xsane_negative; + GtkUpdateType gtk_update_policy; + + int psrotate; /* rotate by 90 degree in postscript mode - landscape */ + int printernr; /* number of printers */ + int printerdefinitions; + Preferences_printer_t *printer[10]; + } +Preferences; + +extern Preferences preferences; + +extern void preferences_save (int fd); +extern void preferences_restore (int fd); + +#endif /* preferences_h */ diff --git a/frontend/xsane-preview.c b/frontend/xsane-preview.c new file mode 100644 index 0000000..a75b12a --- /dev/null +++ b/frontend/xsane-preview.c @@ -0,0 +1,3257 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-preview.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* + + The preview strategy is as follows: + ----------------------------------- + + 1) The preview is done on the full scan area or a part of it. + + 2) The preview is zoomable so the user can precisely pick + the selection area even for small scans on a large scan + surface. + + 3) The preview window is resizeable. + + 4) The preview scan resolution depends on preview window size + and the selected preview surface (zoom area). + + 5) We let the user/backend pick whether a preview is in color, + grayscale, lineart or what not. The only options that the + preview may (temporarily) modify are: + + - resolution (set so the preview fills the window) + - scan area options (top-left corner, bottom-right corner) + - preview option (to let the backend know we're doing a preview) + - gamma table is set to default (gamma=1.0) + + 5) The initial size of the scan surface is determined based on the constraints + of the four corner coordinates. Missing constraints are replaced + by 0/+INF as appropriate (0 for top-left, +INF for bottom-right coords). + + 6) Given the preview window size and the scan surface size, we + select the resolution so the acquired preview image just fits + in the preview window. The resulting resolution may be out + of range in which case we pick the minum/maximum if there is + a range or word-list constraint or a default value if there is + no such constraint. + + 7) Once a preview image has been acquired, we know the size of the + preview image (in pixels). An initial scale factor is chosen + so the image fits into the preview window. + +*/ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#include "xsane.h" +/* #include <sys/param.h> */ +#include "xsane-back-gtk.h" +#include "xsane-front-gtk.h" +#include "xsane-preview.h" +#include "xsane-preferences.h" +#include "xsane-gamma.h" + + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +extern const char *prog_name; +extern const char *device_text; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* Cut fp conversion routines some slack: */ +#define GROSSLY_DIFFERENT(f1,f2) (fabs ((f1) - (f2)) > 1e-3) +#define GROSSLY_EQUAL(f1,f2) (fabs ((f1) - (f2)) < 1e-3) + +#ifdef __alpha__ + /* This seems to be necessary for at least some XFree86 3.1.2 + servers. It's known to be necessary for the XF86_TGA server for + Linux/Alpha. Fortunately, it's no great loss so we turn this on + by default for now. */ +# define XSERVER_WITH_BUGGY_VISUALS +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#define PRESET_AREA_ITEMS 11 +typedef struct +{ + char *name; + float width; + float height; +} Preset_area; + +static const Preset_area preset_area[] = +{ + { "full size", INF, INF }, + { "DIN A3", 296.98, 420.0 }, + { "DIN A4", 210.0, 296.98 }, + { "DIN A4H", 296.98, 210.0 }, + { "DIN A5", 148.5, 210.0 }, + { "DIN A5H", 210.0, 148.5 }, + { "9x13 cm", 90.0, 130.0 }, + { "13x9 cm", 130.0, 90.0 }, + { "legal", 215.9, 355.6 }, + { "letter", 215.9, 279.4 }, + { "custom", INF, INF } +}; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static SANE_Int *preview_gamma_data_red = 0; +static SANE_Int *preview_gamma_data_green = 0; +static SANE_Int *preview_gamma_data_blue = 0; + +static SANE_Int *histogram_gamma_data_red = 0; +static SANE_Int *histogram_gamma_data_green = 0; +static SANE_Int *histogram_gamma_data_blue = 0; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* forward declarations */ +static void preview_order_selection(Preview *p); +static void preview_bound_selection(Preview *p); +static void preview_draw_rect(Preview *p, GdkWindow *win, GdkGC *gc, float coord[4]); +static void preview_draw_selection(Preview *p); +static void preview_update_selection(Preview *p); +static void preview_establish_selection(Preview *p); +/* static void preview_update_batch_selection(Preview *p); */ +static void preview_get_scale_device_to_image(Preview *p, float *xscalep, float *yscalep); +static void preview_get_scale_device_to_preview(Preview *p, float *xscalep, float *yscalep); +static void preview_get_scale_preview_to_image(Preview *p, float *xscalep, float *yscalep); +static void preview_paint_image(Preview *p); +static void preview_display_partial_image(Preview *p); +static void preview_display_maybe(Preview *p); +static void preview_display_image(Preview *p); +static void preview_save_option(Preview *p, int option, SANE_Word *save_loc, int *valid); +static void preview_restore_option(Preview *p, int option, SANE_Word saved_value, int valid); +static void preview_set_option_float(Preview *p, int option, float value); +static void preview_set_option_bool(Preview *p, int option, SANE_Bool value); +static void preview_set_option_int(Preview *p, int option, SANE_Int value); +static int preview_increment_image_y(Preview *p); +static void preview_read_image_data(gpointer data, gint source, GdkInputCondition cond); +static void preview_scan_done(Preview *p); +static void preview_scan_start(Preview *p); +static int preview_make_image_path(Preview *p, size_t filename_size, char *filename, int level); +static void preview_restore_image(Preview *p); +static gint preview_expose_handler(GtkWidget *window, GdkEvent *event, gpointer data); +static gint preview_event_handler(GtkWidget *window, GdkEvent *event, gpointer data); +static void preview_start_button_clicked(GtkWidget *widget, gpointer data); +static void preview_cancel_button_clicked(GtkWidget *widget, gpointer data); +static void preview_area_correct(Preview *p); +static void preview_save_image(Preview *p); +static void preview_zoom_not(GtkWidget *window, gpointer data); +static void preview_zoom_out(GtkWidget *window, gpointer data); +static void preview_zoom_in(GtkWidget *window, gpointer data); +static void preview_zoom_undo(GtkWidget *window, gpointer data); +static void preview_get_color(Preview *p, int x, int y, int *red, int *green, int *blue); +static void preview_pipette_white(GtkWidget *window, gpointer data); +static void preview_pipette_gray(GtkWidget *window, gpointer data); +static void preview_pipette_black(GtkWidget *window, gpointer data); +static void preview_full_preview_area(GtkWidget *widget, gpointer call_data); +static void preview_preset_area_callback(GtkWidget *widget, gpointer call_data); + +void preview_do_gamma_correction(Preview *p); +void preview_calculate_histogram(Preview *p, + SANE_Int *count_raw, SANE_Int *count_raw_red, SANE_Int *count_raw_green, SANE_Int *count_raw_blue, + SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue); +void preview_gamma_correction(Preview *p, + SANE_Int *gamma_red, SANE_Int *gamma_green, SANE_Int *gamma_blue, + SANE_Int *gamma_red_hist, SANE_Int *gamma_green_hist, SANE_Int *gamma_blue_hist); +void preview_area_resize(GtkWidget *widget); +void preview_update_maximum_output_size(Preview *p); +void preview_set_maximum_output_size(Preview *p, float width, float height); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_order_selection(Preview *p) +{ + float tmp_coordinate; + + p->selection.active = ( (p->selection.coordinate[0] != p->selection.coordinate[2]) && + (p->selection.coordinate[1] != p->selection.coordinate[3]) ); + + + if (p->selection.active) + { + if (p->selection.coordinate[0] > p->selection.coordinate[2]) + { + tmp_coordinate = p->selection.coordinate[0]; + p->selection.coordinate[0] = p->selection.coordinate[2]; + p->selection.coordinate[2] = tmp_coordinate; + + p->selection_xedge = (p->selection_xedge + 2) & 3; + } + + if (p->selection.coordinate[1] > p->selection.coordinate[3]) + { + tmp_coordinate = p->selection.coordinate[1]; + p->selection.coordinate[1] = p->selection.coordinate[3]; + p->selection.coordinate[3] = tmp_coordinate; + + p->selection_yedge = (p->selection_yedge + 2) & 3; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_bound_selection(Preview *p) +{ + + p->selection.active = ( (p->selection.coordinate[0] != p->selection.coordinate[2]) && + (p->selection.coordinate[1] != p->selection.coordinate[3]) ); + + + if (p->selection.active) + { + if (p->selection.coordinate[0] < p->scanner_surface[0]) + { + p->selection.coordinate[0] = p->scanner_surface[0]; + } + + if (p->selection.coordinate[1] < p->scanner_surface[1]) + { + p->selection.coordinate[1] = p->scanner_surface[1]; + } + + if (p->selection.coordinate[2] > p->scanner_surface[2]) + { + p->selection.coordinate[2] = p->scanner_surface[2]; + } + + if (p->selection.coordinate[3] > p->scanner_surface[3]) + { + p->selection.coordinate[3] = p->scanner_surface[3]; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_draw_rect(Preview *p, GdkWindow *win, GdkGC *gc, float coordinate[4]) +{ + float xscale, yscale; + float x, y, w, h; + gint xi, yi, wi, hi; + + x = coordinate[0]; + y = coordinate[1]; + w = coordinate[2] - x; + h = coordinate[3] - y; + + if (w < 0) + { + x = coordinate[2]; + w = -w; + } + + if (h < 0) + { + y = coordinate[3]; + h = -h; + } + + preview_get_scale_device_to_preview(p, &xscale, &yscale); + + x = x - p->surface[0]; + y = y - p->surface[1]; + + xi = (gint) (x * xscale + 0.5); + yi = (gint) (y * yscale + 0.5); + wi = (gint) (w * xscale + 0.5); + hi = (gint) (h * yscale + 0.5); + + gdk_draw_rectangle(win, gc, FALSE, xi, yi, wi + 1, hi + 1); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_draw_selection(Preview *p) +{ + if (!p->gc_selection) /* window isn't mapped yet */ + { + return; + } + + while (gtk_events_pending()) /* make sure all drawing actions are finished */ + { + gtk_main_iteration(); + } + + if (p->previous_selection.active) + { + preview_draw_rect(p, p->window->window, p->gc_selection, p->previous_selection.coordinate); + } + + if (p->selection.active) + { + preview_draw_rect(p, p->window->window, p->gc_selection, p->selection.coordinate); + } + + p->previous_selection = p->selection; + + + if (!p->gc_selection_maximum) /* window isn't mapped yet */ + { + return; + } + + if (p->previous_selection_maximum.active) + { + preview_draw_rect(p, p->window->window, p->gc_selection_maximum, p->previous_selection_maximum.coordinate); + } + + if (p->selection_maximum.active) + { + preview_draw_rect(p, p->window->window, p->gc_selection_maximum, p->selection_maximum.coordinate); + } + + p->previous_selection_maximum = p->selection_maximum; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_update_selection(Preview *p) +/* draw selection box as defined in backend */ +{ + const SANE_Option_Descriptor *opt; + SANE_Status status; + SANE_Word val; + int i, optnum; + + p->previous_selection = p->selection; + + for (i = 0; i < 4; ++i) + { + optnum = p->dialog->well_known.coord[i]; + if (optnum > 0) + { + opt = sane_get_option_descriptor(p->dialog->dev, optnum); + status = sane_control_option(p->dialog->dev, optnum, SANE_ACTION_GET_VALUE, &val, 0); + if (status != SANE_STATUS_GOOD) + { + continue; + } + if (opt->type == SANE_TYPE_FIXED) + { + p->selection.coordinate[i] = SANE_UNFIX(val); + } + else + { + p->selection.coordinate[i] = val; + } + } + else /* backend does not use scanarea options */ + { + switch (i) + { + case 0: + case 1: + p->selection.coordinate[i] = 0; + break; + + case 2: + p->selection.coordinate[i] = p->preview_width; + break; + + case 3: + p->selection.coordinate[i] = p->preview_height; + break; + } + } + } + + for (i = 0; i < 2; ++i) + { + if (p->selection.coordinate[i + 2] < p->selection.coordinate[i]) + { + p->selection.coordinate[i + 2] = p->selection.coordinate[i]; + } + } + + p->selection.active = ( (p->selection.coordinate[0] != p->selection.coordinate[2]) && + (p->selection.coordinate[1] != p->selection.coordinate[3]) ); + + preview_draw_selection(p); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_establish_selection(Preview *p) +{ + /* This routine only shall be called if the preview area really is changed. */ + + int i; + + preview_order_selection(p); + + xsane.block_update_param = TRUE; /* do not change parameters each time */ + + for (i = 0; i < 4; ++i) + { + preview_set_option_float(p, p->dialog->well_known.coord[i], p->selection.coordinate[i]); + } + + xsane_back_gtk_update_scan_window(p->dialog); + + xsane.block_update_param = FALSE; + + if (p->dialog->param_change_callback) + { + (*p->dialog->param_change_callback) (p->dialog, p->dialog->param_change_arg); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#if 0 +static void preview_update_batch_selection(Preview *p) +{ + Batch_selection *batch_selection; + + if (!p->gc_selection) /* window isn't mapped yet */ + { + return; + } + + batch_selection = p->batch_selection; + + while (batch_selection) + { + preview_draw_rect(p, p->window->window, p->gc_selection, batch_selection->coordinate); + + batch_selection = batch_selection->next; + } +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_get_scale_device_to_image(Preview *p, float *xscalep, float *yscalep) +{ + float device_width, device_height; + float xscale = 1.0; + float yscale = 1.0; + + device_width = fabs(p->image_surface[2] - p->image_surface[0]); + device_height = fabs(p->image_surface[3] - p->image_surface[1]); + + if ( (device_width >0) && (device_width < INF) ) + { + xscale = p->image_width / device_width; + } + + if ( (device_height >0) && (device_height < INF) ) + { + yscale = p->image_height / device_height; + } + + if (p->surface_unit == SANE_UNIT_PIXEL) + { + if (xscale > yscale) + { + yscale = xscale; + } + else + { + xscale = yscale; + } + } + + *xscalep = xscale; + *yscalep = yscale; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_get_scale_device_to_preview(Preview *p, float *xscalep, float *yscalep) +{ + float device_width, device_height; + float xscale = 1.0; + float yscale = 1.0; + + device_width = fabs(p->image_surface[2] - p->image_surface[0]); + device_height = fabs(p->image_surface[3] - p->image_surface[1]); + + if ( (device_width >0) && (device_width < INF) ) + { + xscale = p->preview_width / device_width; + } + + if ( (device_height >0) && (device_height < INF) ) + { + yscale = p->preview_height / device_height; + } + + if (p->surface_unit == SANE_UNIT_PIXEL) + { + if (xscale > yscale) + { + yscale = xscale; + } + else + { + xscale = yscale; + } + } + + *xscalep = xscale; + *yscalep = yscale; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_get_scale_preview_to_image(Preview *p, float *xscalep, float *yscalep) +{ + float xscale = 1.0; + float yscale = 1.0; + + if (p->image_width > 0) + { + xscale = p->image_width / (float) p->preview_width; + } + + if (p->image_height > 0) + { + yscale = p->image_height / (float) p->preview_height; + } + + if (p->surface_unit == SANE_UNIT_PIXEL) + { + if (xscale > yscale) + { + yscale = xscale; + } + else + { + xscale = yscale; + } + } + + *xscalep = xscale; + *yscalep = yscale; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_paint_image(Preview *p) +{ + float xscale, yscale, src_x, src_y; + int dst_x, dst_y, height, x, y, old_y, src_offset; + + preview_get_scale_preview_to_image(p, &xscale, &yscale); + + memset(p->preview_row, 0x80, 3*p->preview_window_width); + + /* don't draw last line unless it's complete: */ + height = p->image_y; + + if (p->image_x == 0 && height < p->image_height) + { + ++height; + } + + /* for now, use simple nearest-neighbor interpolation: */ + src_offset = 0; + src_x = src_y = 0.0; + old_y = -1; + + for (dst_y = 0; dst_y < p->preview_height; ++dst_y) + { + y = (int) (src_y + 0.5); + if (y >= height) + { + break; + } + src_offset = y * 3 * p->image_width; + + if ((p->image_data_enh) && (old_y != y)) + { + old_y = y; + for (dst_x = 0; dst_x < p->preview_width; ++dst_x) + { + x = (int) (src_x + 0.5); + if (x >= p->image_width) + { + break; + } + + p->preview_row[3*dst_x + 0] = p->image_data_enh[src_offset + 3*x + 0]; + p->preview_row[3*dst_x + 1] = p->image_data_enh[src_offset + 3*x + 1]; + p->preview_row[3*dst_x + 2] = p->image_data_enh[src_offset + 3*x + 2]; + src_x += xscale; + } + } + gtk_preview_draw_row(GTK_PREVIEW(p->window), p->preview_row, 0, dst_y, p->preview_window_width); + src_x = 0.0; + src_y += yscale; + } + + if (dst_y >= p->preview_height-5) + { + memset(p->preview_row, 0x80, 3*p->preview_window_width); + for (dst_y = p->preview_height-1; dst_y < p->preview_window_height; ++dst_y) + { + gtk_preview_draw_row(GTK_PREVIEW(p->window), p->preview_row, 0, dst_y, p->preview_window_width); + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_display_partial_image(Preview *p) +{ + preview_paint_image(p); + + if (GTK_WIDGET_DRAWABLE(p->window)) + { + GtkPreview *preview = GTK_PREVIEW(p->window); + int src_x, src_y; + + src_x = (p->window->allocation.width - preview->buffer_width)/2; + src_y = (p->window->allocation.height - preview->buffer_height)/2; + gtk_preview_put(preview, p->window->window, p->window->style->black_gc, src_x, src_y, + 0, 0, p->preview_width, p->preview_height); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_display_maybe(Preview *p) +{ + time_t now; + + time(&now); + + if (now > p->image_last_time_updated) /* wait at least one secone */ + { + p->image_last_time_updated = now; + preview_display_partial_image(p); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_display_image(Preview *p) +{ + /* if image height was unknown and got larger than expected get missing memory */ + if (p->params.lines <= 0 && p->image_y < p->image_height) + { + p->image_height = p->image_y; + p->image_data_raw = realloc(p->image_data_raw, 3 * p->image_width * p->image_height); + p->image_data_enh = realloc(p->image_data_enh, 3 * p->image_width * p->image_height); + assert(p->image_data_raw); + assert(p->image_data_enh); + } + + memcpy(p->image_data_raw, p->image_data_enh, 3 * p->image_width * p->image_height); + + preview_do_gamma_correction(p); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_save_option(Preview *p, int option, SANE_Word *save_loc, int *valid) +{ + SANE_Status status; + + if (option <= 0) + { + *valid = 0; + return; + } + + status = sane_control_option(p->dialog->dev, option, SANE_ACTION_GET_VALUE, save_loc, 0); + *valid = (status == SANE_STATUS_GOOD); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_restore_option(Preview *p, int option, SANE_Word saved_value, int valid) +{ + const SANE_Option_Descriptor *opt; + SANE_Status status; + SANE_Handle dev; + + if (!valid) + { + return; + } + + dev = p->dialog->dev; + status = sane_control_option(dev, option, SANE_ACTION_SET_VALUE, &saved_value, 0); + + if (status != SANE_STATUS_GOOD) + { + char buf[256]; + opt = sane_get_option_descriptor(dev, option); + snprintf(buf, sizeof(buf), "%s %s: %s.", ERR_SET_OPTION, opt->name, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, TRUE); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_set_option_float(Preview *p, int option, float value) +{ + const SANE_Option_Descriptor *opt; + SANE_Handle dev; + SANE_Word word; + + if (option <= 0 || value <= -INF || value >= INF) + { + return; + } + + dev = p->dialog->dev; + opt = sane_get_option_descriptor(dev, option); + if (opt->type == SANE_TYPE_FIXED) + { + word = SANE_FIX(value) + 0.5; + } + else + { + word = value + 0.5; + } + + sane_control_option(dev, option, SANE_ACTION_SET_VALUE, &word, 0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_set_option_bool(Preview *p, int option, SANE_Bool value) +{ + SANE_Handle dev; + + if (option <= 0) + return; + + dev = p->dialog->dev; + sane_control_option(dev, option, SANE_ACTION_SET_VALUE, &value, 0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_set_option_int(Preview *p, int option, SANE_Int value) +{ + SANE_Handle dev; + + if (option <= 0) + return; + + dev = p->dialog->dev; + sane_control_option(dev, option, SANE_ACTION_SET_VALUE, &value, 0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int preview_increment_image_y(Preview *p) +{ + size_t extra_size, offset; + char buf[256]; + + p->image_x = 0; + ++p->image_y; + if (p->params.lines <= 0 && p->image_y >= p->image_height) + { + offset = 3 * p->image_width*p->image_height; + extra_size = 3 * 32 * p->image_width; + p->image_height += 32; + p->image_data_raw = realloc(p->image_data_raw, offset + extra_size); + p->image_data_enh = realloc(p->image_data_enh, offset + extra_size); + if ( (!p->image_data_enh) || (!p->image_data_raw) ) + { + snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_ALLOCATE_IMAGE, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + preview_scan_done(p); + return -1; + } + memset(p->image_data_enh + offset, 0xff, extra_size); + } + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_read_image_data(gpointer data, gint source, GdkInputCondition cond) +{ + SANE_Status status; + Preview *p = data; + u_char buf[8192]; + SANE_Handle dev; + SANE_Int len; + int i, j; + + dev = p->dialog->dev; + while (1) + { + status = sane_read(dev, buf, sizeof(buf), &len); + if (status != SANE_STATUS_GOOD) + { + if (status == SANE_STATUS_EOF) + { + if (p->params.last_frame) /* got all preview image data */ + { + preview_display_image(p); /* display preview image */ + preview_save_image(p); /* save preview image */ + preview_scan_done(p); /* scan is done */ + return; /* ok, all finished */ + } + else + { + preview_scan_start(p); + break; + } + } + else + { + snprintf(buf, sizeof(buf), "%s %s.", ERR_DURING_READ, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, TRUE); + } + preview_scan_done(p); + return; + } + + if (!len) + { + break; /* out of data for now */ + } + + switch (p->params.format) + { + case SANE_FRAME_RGB: + if (p->params.depth != 8) + { + goto bad_depth; + } + + for (i = 0; i < len; ++i) + { + p->image_data_enh[p->image_offset++] = buf[i]; + if (p->image_offset%3 == 0) + { + if (++p->image_x >= p->image_width && preview_increment_image_y(p) < 0) + { + return; + } + } + } + break; + + case SANE_FRAME_GRAY: + switch (p->params.depth) + { + case 1: + for (i = 0; i < len; ++i) + { + u_char mask = buf[i]; + + for (j = 7; j >= 0; --j) + { + u_char gl = (mask & (1 << j)) ? 0x00 : 0xff; + p->image_data_enh[p->image_offset++] = gl; + p->image_data_enh[p->image_offset++] = gl; + p->image_data_enh[p->image_offset++] = gl; + if (++p->image_x >= p->image_width) + { + if (preview_increment_image_y(p) < 0) + { + return; + } + break; /* skip padding bits */ + } + } + } + break; + + case 8: + for (i = 0; i < len; ++i) + { + u_char gl = buf[i]; + p->image_data_enh[p->image_offset++] = gl; + p->image_data_enh[p->image_offset++] = gl; + p->image_data_enh[p->image_offset++] = gl; + if (++p->image_x >= p->image_width && preview_increment_image_y(p) < 0) + { + return; + } + } + break; + + default: + goto bad_depth; + } + break; + + case SANE_FRAME_RED: + case SANE_FRAME_GREEN: + case SANE_FRAME_BLUE: + switch (p->params.depth) + { + case 1: + for (i = 0; i < len; ++i) + { + u_char mask = buf[i]; + + for (j = 0; j < 8; ++j) + { + u_char gl = (mask & 1) ? 0xff : 0x00; + mask >>= 1; + p->image_data_enh[p->image_offset++] = gl; + p->image_offset += 3; + if (++p->image_x >= p->image_width && preview_increment_image_y(p) < 0) + { + return; + } + } + } + break; + + case 8: + for (i = 0; i < len; ++i) + { + p->image_data_enh[p->image_offset] = buf[i]; + p->image_offset += 3; + if (++p->image_x >= p->image_width && preview_increment_image_y(p) < 0) + { + return; + } + } + break; + + default: + goto bad_depth; + } + break; + + default: + fprintf(stderr, "preview_read_image_data: %s %d\n", ERR_BAD_FRAME_FORMAT, p->params.format); + preview_scan_done(p); + return; + } + + if (p->input_tag < 0) + { + preview_display_maybe(p); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + } + } + preview_display_maybe(p); + return; + +bad_depth: + snprintf(buf, sizeof(buf), "%s %d.", ERR_PREVIEW_BAD_DEPTH, p->params.depth); + xsane_back_gtk_error(buf, TRUE); + preview_scan_done(p); + return; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_scan_done(Preview *p) +{ + int i; + + p->scanning = FALSE; + + if (p->input_tag >= 0) + { + gdk_input_remove(p->input_tag); + p->input_tag = -1; + } + + sane_cancel(p->dialog->dev); + + xsane.block_update_param = TRUE; /* do not change parameters each time */ + + preview_restore_option(p, p->dialog->well_known.dpi, p->saved_dpi, p->saved_dpi_valid); + preview_restore_option(p, p->dialog->well_known.dpi_x, p->saved_dpi_x, p->saved_dpi_x_valid); + preview_restore_option(p, p->dialog->well_known.dpi_y, p->saved_dpi_y, p->saved_dpi_y_valid); + + for (i = 0; i < 4; ++i) + { + preview_restore_option(p, p->dialog->well_known.coord[i], p->saved_coord[i], p->saved_coord_valid[i]); + } + + preview_restore_option(p, p->dialog->well_known.bit_depth, p->saved_bit_depth, p->saved_bit_depth_valid); + + preview_set_option_bool(p, p->dialog->well_known.preview, SANE_FALSE); + + gtk_widget_set_sensitive(p->cancel, FALSE); + xsane_set_sensitivity(TRUE); + + xsane.block_update_param = FALSE; + + preview_update_surface(p, 0); /* if surface was not defined it's necessary to redefine it now */ + + preview_update_selection(p); + xsane_update_histogram(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int preview_get_memory(Preview *p) +{ + char buf[256]; + + if (p->image_data_enh) + { + free(p->image_data_enh); + p->image_data_enh = 0; + } + + if (p->image_data_raw) + { + free(p->image_data_raw); + p->image_data_raw = 0; + } + + if (p->preview_row) + { + free(p->preview_row); + p->preview_row = 0; + } + + p->image_data_enh = malloc(3 * p->image_width * (p->image_height)); + p->image_data_raw = malloc(3 * p->image_width * (p->image_height)); + p->preview_row = malloc(3 * p->preview_window_width); + + if ( (!p->image_data_raw) || (!p->image_data_enh) || (!p->preview_row) ) + { + if (p->image_data_enh) + { + free(p->image_data_enh); + p->image_data_enh = 0; + } + + if (p->image_data_raw) + { + free(p->image_data_raw); + p->image_data_raw = 0; + } + + if (p->preview_row) + { + free(p->preview_row); + p->preview_row = 0; + } + + snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_ALLOCATE_IMAGE, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + + return -1; /* error */ + } + + memset(p->image_data_enh, 0xff, 3*p->image_width*p->image_height); /* clean memory */ + + return 0; /* ok */ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_scan_start(Preview *p) +{ + SANE_Handle dev = p->dialog->dev; + SANE_Status status; + char buf[256]; + int fd, y, i; + int gamma_gray_size = 256; /* set this values to image depth for more than 8bpp input support!!! */ + int gamma_red_size = 256; + int gamma_green_size = 256; + int gamma_blue_size = 256; + int gamma_gray_max = 255; /* set this to to image depth for more than 8bpp output support */ + int gamma_red_max = 255; + int gamma_green_max = 255; + int gamma_blue_max = 255; + + for (i=0; i<4; i++) + { + p->image_surface[i] = p->surface[i]; + } + + xsane_clear_histogram(&xsane.histogram_raw); + xsane_clear_histogram(&xsane.histogram_enh); + gtk_widget_set_sensitive(p->cancel, TRUE); + xsane_set_sensitivity(FALSE); + + /* clear old preview: */ + memset(p->preview_row, 0xff, 3*p->preview_width); + for (y = 0; y < p->preview_height; ++y) + { + gtk_preview_draw_row(GTK_PREVIEW(p->window), p->preview_row, 0, y, p->preview_width); + } + + if (p->input_tag >= 0) + { + gdk_input_remove(p->input_tag); + p->input_tag = -1; + } + + if (p->dialog->well_known.gamma_vector >0) + { + const SANE_Option_Descriptor *opt; + + opt = sane_get_option_descriptor(p->dialog->dev, p->dialog->well_known.gamma_vector); + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + SANE_Int *gamma_data; + + opt = sane_get_option_descriptor(p->dialog->dev, p->dialog->well_known.gamma_vector); + gamma_gray_size = opt->size / sizeof(opt->type); + gamma_gray_max = opt->constraint.range->max; + + gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int)); + xsane_create_gamma_curve(gamma_data, 0, 1.0, 0.0, 0.0, gamma_gray_size, gamma_gray_max); + xsane_back_gtk_update_vector(p->dialog, p->dialog->well_known.gamma_vector, gamma_data); + free(gamma_data); + } + } + + if (p->dialog->well_known.gamma_vector_r >0) + { + const SANE_Option_Descriptor *opt; + + opt = sane_get_option_descriptor(p->dialog->dev, p->dialog->well_known.gamma_vector_r); + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + SANE_Int *gamma_data_red, *gamma_data_green, *gamma_data_blue; + + opt = sane_get_option_descriptor(p->dialog->dev, p->dialog->well_known.gamma_vector_r); + gamma_red_size = opt->size / sizeof(opt->type); + gamma_red_max = opt->constraint.range->max; + + opt = sane_get_option_descriptor(p->dialog->dev, p->dialog->well_known.gamma_vector_g); + gamma_green_size = opt->size / sizeof(opt->type); + gamma_green_max = opt->constraint.range->max; + + opt = sane_get_option_descriptor(p->dialog->dev, p->dialog->well_known.gamma_vector_b); + gamma_blue_size = opt->size / sizeof(opt->type); + gamma_blue_max = opt->constraint.range->max; + + gamma_data_red = malloc(gamma_red_size * sizeof(SANE_Int)); + gamma_data_green = malloc(gamma_green_size * sizeof(SANE_Int)); + gamma_data_blue = malloc(gamma_blue_size * sizeof(SANE_Int)); + + xsane_create_gamma_curve(gamma_data_red, 0, 1.0, 0.0, 0.0, gamma_red_size, gamma_red_max); + xsane_create_gamma_curve(gamma_data_green, 0, 1.0, 0.0, 0.0, gamma_green_size, gamma_green_max); + xsane_create_gamma_curve(gamma_data_blue, 0, 1.0, 0.0, 0.0, gamma_blue_size, gamma_blue_max); + + xsane_back_gtk_update_vector(p->dialog, p->dialog->well_known.gamma_vector_r, gamma_data_red); + xsane_back_gtk_update_vector(p->dialog, p->dialog->well_known.gamma_vector_g, gamma_data_green); + xsane_back_gtk_update_vector(p->dialog, p->dialog->well_known.gamma_vector_b, gamma_data_blue); + + free(gamma_data_red); + free(gamma_data_green); + free(gamma_data_blue); + } + } + + status = sane_start(dev); + if (status != SANE_STATUS_GOOD) + { + snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_START_SCANNER, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, TRUE); + preview_scan_done(p); + return; + } + + status = sane_get_parameters(dev, &p->params); + if (status != SANE_STATUS_GOOD) + { + snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_GET_PARAMS, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, TRUE); + preview_scan_done(p); + return; + } + + p->image_offset = p->image_x = p->image_y = 0; + + if (p->params.format >= SANE_FRAME_RED && p->params.format <= SANE_FRAME_BLUE) + { + p->image_offset = p->params.format - SANE_FRAME_RED; + } + + if ( (!p->image_data_enh) || (p->params.pixels_per_line != p->image_width) + || ( (p->params.lines >= 0) && (p->params.lines != p->image_height) ) ) + { + p->image_width = p->params.pixels_per_line; + p->image_height = p->params.lines; + + if (p->image_height < 0) + { + p->image_height = 32; /* may have to adjust as we go... */ + } + + if (preview_get_memory(p)) + { + preview_scan_done(p); /* error */ + return; + } + } + +/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ +/* THIS IS A BIT STRANGE HERE */ + p->selection.active = FALSE; + p->previous_selection_maximum.active = FALSE; +/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + + p->scanning = TRUE; + + if (sane_set_io_mode(dev, SANE_TRUE) == SANE_STATUS_GOOD && sane_get_select_fd(dev, &fd) == SANE_STATUS_GOOD) + { + p->input_tag = gdk_input_add(fd, GDK_INPUT_READ, preview_read_image_data, p); + } + else + { + preview_read_image_data(p, -1, GDK_INPUT_READ); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int preview_make_image_path(Preview *p, size_t filename_size, char *filename, int level) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), "preview-level-%d-", level); + return xsane_back_gtk_make_path(filename_size, filename, 0, 0, buf, p->dialog->dev_name, ".ppm", XSANE_PATH_TMP); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int preview_restore_image_from_file(Preview *p, FILE *in, int min_quality) +{ + u_int psurface_type, psurface_unit; + int image_width, image_height; + int xoffset, yoffset, width, height; + int quality; + int y; + float psurface[4]; + size_t nread; + char *imagep; + + if (!in) + { + return min_quality; + } + + /* See whether there is a saved preview and load it if present: */ + + if (fscanf(in, "P6\n# surface: %g %g %g %g %u %u\n%d %d\n255\n", + psurface + 0, psurface + 1, psurface + 2, psurface + 3, + &psurface_type, &psurface_unit, + &image_width, &image_height) != 8) + { + return min_quality; + } + + if ((psurface_type != p->surface_type) || (psurface_unit != p->surface_unit)) + { + return min_quality; + } + + xoffset = (p->surface[0] - psurface[0])/(psurface[2] - psurface[0]) * image_width; + yoffset = (p->surface[1] - psurface[1])/(psurface[3] - psurface[1]) * image_height; + width = (p->surface[2] - p->surface[0])/(psurface[2] - psurface[0]) * image_width; + height = (p->surface[3] - p->surface[1])/(psurface[3] - psurface[1]) * image_height; + quality = width; + + if ((xoffset < 0) || (yoffset < 0) || + (xoffset+width > image_width) || (yoffset+height > image_height) || + (width == 0) || (height == 0)) + { + return min_quality; + } + + if (quality < min_quality) + { + return min_quality; + } + + p->params.depth = 8; + p->image_width = width; + p->image_height = height; + + if (preview_get_memory(p)) + { + return min_quality; /* error allocating memory */ + } + + fseek(in, yoffset * 3 * image_width, SEEK_CUR); /* skip unused lines */ + + imagep = p->image_data_enh; + + for (y = yoffset; y < yoffset + height; y++) + { + fseek(in, xoffset * 3, SEEK_CUR); /* skip unused pixel left of area */ + + nread = fread(imagep, 3, width, in); + imagep += width * 3; + + fseek(in, (image_width - width - xoffset) * 3, SEEK_CUR); /* skip unused pixel right of area */ + } + + p->image_y = height; + p->image_x = width; + + p->image_surface[0] = p->surface[0]; + p->image_surface[1] = p->surface[1]; + p->image_surface[2] = p->surface[2]; + p->image_surface[3] = p->surface[3]; + + return quality; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_restore_image(Preview *p) +{ + char filename[PATH_MAX]; + FILE *in; + int status; + int quality = 0; + int level; + + /* See whether there is a saved preview and load it if present: */ + + for(level = 2; level >= 0; level--) + { + status = preview_make_image_path(p, sizeof(filename), filename, level); + if (status >= 0) + { + in = fopen(filename, "r"); + if (in) + { + quality = preview_restore_image_from_file(p, in, quality); + } + } + } + memcpy(p->image_data_raw, p->image_data_enh, 3 * p->image_width * p->image_height); + +/* the following commands may be removed because they are done because a event is emmited */ + preview_do_gamma_correction(p); + xsane_update_histogram(); + preview_draw_selection(p); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* This is executed _after_ the gtkpreview's expose routine. */ +static gint preview_expose_handler(GtkWidget *window, GdkEvent *event, gpointer data) +{ + Preview *p = data; + + p->previous_selection.active = FALSE; /* ok, old selections are overpainted */ + p->previous_selection_maximum.active = FALSE; + p->selection.active = TRUE; /* ok, old selections are overpainted */ + p->selection_maximum.active = TRUE; + preview_draw_selection(p); /* draw selections again */ + + return FALSE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static gint preview_event_handler(GtkWidget *window, GdkEvent *event, gpointer data) +{ + Preview *p = data; + GdkCursor *cursor; + GdkColor color; + GdkColormap *colormap; + float preview_selection[4]; + float xscale, yscale; + static int event_count = 0; + int cursornr; + + event_count++; + + preview_get_scale_device_to_preview(p, &xscale, &yscale); + + preview_selection[0] = xscale * (p->selection.coordinate[0] - p->surface[0]); + preview_selection[1] = yscale * (p->selection.coordinate[1] - p->surface[1]); + preview_selection[2] = xscale * (p->selection.coordinate[2] - p->surface[0]); + preview_selection[3] = yscale * (p->selection.coordinate[3] - p->surface[1]); + + if (event->type == GDK_EXPOSE) + { + if (!p->gc_selection) + { + colormap = gdk_window_get_colormap(p->window->window); + + p->gc_selection = gdk_gc_new(p->window->window); + gdk_gc_set_function(p->gc_selection, GDK_INVERT); + gdk_gc_set_line_attributes(p->gc_selection, 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER); + + p->gc_selection_maximum = gdk_gc_new(p->window->window); + gdk_gc_set_function(p->gc_selection_maximum, GDK_XOR); + gdk_gc_set_line_attributes(p->gc_selection_maximum, 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER); + color.red = 0; + color.green = 65535; + color.blue = 30000; + gdk_color_alloc(colormap, &color); + gdk_gc_set_foreground(p->gc_selection_maximum, &color); + + preview_paint_image(p); + } + else + { + while (gtk_events_pending()) /* make sure image is updated */ + { + gtk_main_iteration(); + } + + p->previous_selection.active = FALSE; /* ok, old selections are overpainted */ + p->previous_selection_maximum.active = FALSE; + preview_draw_selection(p); /* draw selections again */ + } + } + else if (!p->scanning) + { + switch (event->type) + { + case GDK_UNMAP: + case GDK_MAP: + break; + + case GDK_BUTTON_PRESS: + switch (p->mode) + { + case MODE_PIPETTE_WHITE: + { + if ( ( (((GdkEventButton *)event)->button == 1) || (((GdkEventButton *)event)->button == 2) ) && + (p->image_data_raw) ) /* left or middle button */ + { + int r,g,b; + + preview_get_color(p, event->button.x, event->button.y, &r, &g, &b); + + xsane.slider_gray.value[2] = sqrt( (r*r+g*g+b*b) / 3)/2.55; + + if ( (!xsane.enhancement_rgb_default) && (((GdkEventButton *)event)->button == 2) ) /* middle button */ + { + xsane.slider_red.value[2] = r/2.55; + xsane.slider_green.value[2] = g/2.55; + xsane.slider_blue.value[2] = b/2.55; + } + else + { + xsane.slider_red.value[2] = xsane.slider_gray.value[2]; + xsane.slider_green.value[2] = xsane.slider_gray.value[2]; + xsane.slider_blue.value[2] = xsane.slider_gray.value[2]; + } + + if (xsane.slider_gray.value[2] < 2) + { + xsane.slider_gray.value[2] = 2; + } + if (xsane.slider_gray.value[1] >= xsane.slider_gray.value[2]) + { + xsane.slider_gray.value[1] = xsane.slider_gray.value[2]-1; + if (xsane.slider_gray.value[0] >= xsane.slider_gray.value[1]) + { + xsane.slider_gray.value[0] = xsane.slider_gray.value[1]-1; + } + } + + if (xsane.slider_red.value[2] < 2) + { + xsane.slider_red.value[2] = 2; + } + if (xsane.slider_red.value[1] >= xsane.slider_red.value[2]) + { + xsane.slider_red.value[1] = xsane.slider_red.value[2]-1; + if (xsane.slider_red.value[0] >= xsane.slider_red.value[1]) + { + xsane.slider_red.value[0] = xsane.slider_red.value[1]-1; + } + } + + if (xsane.slider_green.value[2] < 2) + { + xsane.slider_green.value[2] = 2; + } + if (xsane.slider_green.value[1] >= xsane.slider_green.value[2]) + { + xsane.slider_green.value[1] = xsane.slider_green.value[2]-1; + if (xsane.slider_green.value[0] >= xsane.slider_green.value[1]) + { + xsane.slider_green.value[0] = xsane.slider_green.value[1]-1; + } + } + + if (xsane.slider_blue.value[2] < 2) + { + xsane.slider_blue.value[2] = 2; + } + if (xsane.slider_blue.value[1] >= xsane.slider_blue.value[2]) + { + xsane.slider_blue.value[1] = xsane.slider_blue.value[2]-1; + if (xsane.slider_blue.value[0] >= xsane.slider_blue.value[1]) + { + xsane.slider_blue.value[0] = xsane.slider_blue.value[1]-1; + } + } + + xsane_enhancement_by_histogram(); + } + + p->mode = MODE_NORMAL; + + cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW); + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = XSANE_CURSOR_PREVIEW; + } + break; + + case MODE_PIPETTE_GRAY: + { + if ( ( (((GdkEventButton *)event)->button == 1) || (((GdkEventButton *)event)->button == 2) ) && + (p->image_data_raw) ) /* left or middle button */ + { + int r,g,b; + + preview_get_color(p, event->button.x, event->button.y, &r, &g, &b); + + xsane.slider_gray.value[1] = sqrt( (r*r+g*g+b*b) / 3)/2.55; + + if ( (!xsane.enhancement_rgb_default) && (((GdkEventButton *)event)->button == 2) ) /* middle button */ + { + xsane.slider_red.value[1] = r/2.55; + xsane.slider_green.value[1] = g/2.55; + xsane.slider_blue.value[1] = b/2.55; + } + else + { + xsane.slider_red.value[1] = xsane.slider_gray.value[1]; + xsane.slider_green.value[1] = xsane.slider_gray.value[1]; + xsane.slider_blue.value[1] = xsane.slider_gray.value[1]; + } + + if (xsane.slider_gray.value[1] == 0) + { + xsane.slider_gray.value[1] += 1; + } + if (xsane.slider_gray.value[1] == 100) + { + xsane.slider_gray.value[1] -= 1; + } + if (xsane.slider_gray.value[1] >= xsane.slider_gray.value[2]) + { + xsane.slider_gray.value[2] = xsane.slider_gray.value[1]+1; + } + if (xsane.slider_gray.value[1] <= xsane.slider_gray.value[0]) + { + xsane.slider_gray.value[0] = xsane.slider_gray.value[1]-1; + } + + if (xsane.slider_red.value[1] == 0) + { + xsane.slider_red.value[1] += 1; + } + if (xsane.slider_red.value[1] == 100) + { + xsane.slider_red.value[1] -= 1; + } + if (xsane.slider_red.value[1] >= xsane.slider_red.value[2]) + { + xsane.slider_red.value[2] = xsane.slider_red.value[1]+1; + } + if (xsane.slider_red.value[1] <= xsane.slider_red.value[0]) + { + xsane.slider_red.value[0] = xsane.slider_red.value[1]-1; + } + + if (xsane.slider_green.value[1] == 0) + { + xsane.slider_green.value[1] += 1; + } + if (xsane.slider_green.value[1] == 100) + { + xsane.slider_green.value[1] -= 1; + } + if (xsane.slider_green.value[1] >= xsane.slider_green.value[2]) + { + xsane.slider_green.value[2] = xsane.slider_green.value[1]+1; + } + if (xsane.slider_green.value[1] <= xsane.slider_green.value[0]) + { + xsane.slider_green.value[0] = xsane.slider_green.value[1]-1; + } + + if (xsane.slider_blue.value[1] == 0) + { + xsane.slider_blue.value[1] += 1; + } + if (xsane.slider_blue.value[1] == 100) + { + xsane.slider_blue.value[1] -= 1; + } + if (xsane.slider_blue.value[1] >= xsane.slider_blue.value[2]) + { + xsane.slider_blue.value[2] = xsane.slider_blue.value[1]+1; + } + if (xsane.slider_blue.value[1] <= xsane.slider_blue.value[0]) + { + xsane.slider_blue.value[0] = xsane.slider_blue.value[1]-1; + } + + xsane_enhancement_by_histogram(); + } + + p->mode = MODE_NORMAL; + + cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW); + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = XSANE_CURSOR_PREVIEW; + } + break; + + case MODE_PIPETTE_BLACK: + { + if ( ( (((GdkEventButton *)event)->button == 1) || (((GdkEventButton *)event)->button == 2) ) && + (p->image_data_raw) ) /* left or middle button */ + { + int r,g,b; + + preview_get_color(p, event->button.x, event->button.y, &r, &g, &b); + + xsane.slider_gray.value[0] = sqrt( (r*r+g*g+b*b) / 3)/2.55; + + if ( (!xsane.enhancement_rgb_default) && (((GdkEventButton *)event)->button == 2) ) /* middle button */ + { + xsane.slider_red.value[0] = r/2.55; + xsane.slider_green.value[0] = g/2.55; + xsane.slider_blue.value[0] = b/2.55; + } + else + { + xsane.slider_red.value[0] = xsane.slider_gray.value[0]; + xsane.slider_green.value[0] = xsane.slider_gray.value[0]; + xsane.slider_blue.value[0] = xsane.slider_gray.value[0]; + } + + if (xsane.slider_gray.value[0] > 98) + { + xsane.slider_gray.value[0] = 98; + } + if (xsane.slider_gray.value[1] <= xsane.slider_gray.value[0]) + { + xsane.slider_gray.value[1] = xsane.slider_gray.value[0]+1; + if (xsane.slider_gray.value[2] <= xsane.slider_gray.value[1]) + { + xsane.slider_gray.value[2] = xsane.slider_gray.value[1]+1; + } + } + + if (xsane.slider_red.value[0] > 98) + { + xsane.slider_red.value[0] = 98; + } + if (xsane.slider_red.value[1] <= xsane.slider_red.value[0]) + { + xsane.slider_red.value[1] = xsane.slider_red.value[0]+1; + if (xsane.slider_red.value[2] <= xsane.slider_red.value[1]) + { + xsane.slider_red.value[2] = xsane.slider_red.value[1]+1; + } + } + + if (xsane.slider_green.value[0] > 98) + { + xsane.slider_green.value[0] = 98; + } + if (xsane.slider_green.value[1] <= xsane.slider_green.value[0]) + { + xsane.slider_green.value[1] = xsane.slider_green.value[0]+1; + if (xsane.slider_green.value[2] <= xsane.slider_green.value[1]) + { + xsane.slider_green.value[2] = xsane.slider_green.value[1]+1; + } + } + + if (xsane.slider_blue.value[0] > 98) + { + xsane.slider_blue.value[0] = 98; + } + if (xsane.slider_blue.value[1] <= xsane.slider_blue.value[0]) + { + xsane.slider_blue.value[1] = xsane.slider_blue.value[0]+1; + if (xsane.slider_blue.value[2] <= xsane.slider_blue.value[1]) + { + xsane.slider_blue.value[2] = xsane.slider_blue.value[1]+1; + } + } + + xsane_enhancement_by_histogram(); + } + + p->mode = MODE_NORMAL; + + cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW); + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = XSANE_CURSOR_PREVIEW; + } + break; + + case MODE_NORMAL: + { + switch (((GdkEventButton *)event)->button) + { + case 1: /* left button */ + p->selection_xedge = -1; + if ( (preview_selection[0] - SELECTION_RANGE_OUT < event->button.x) && (event->button.x < preview_selection[0] + SELECTION_RANGE_IN) ) /* left */ + { + p->selection_xedge = 0; + } + else if ( (preview_selection[2] - SELECTION_RANGE_IN < event->button.x) && (event->button.x < preview_selection[2] + SELECTION_RANGE_OUT) ) /* right */ + { + p->selection_xedge = 2; + } + + p->selection_yedge = -1; + if ( (preview_selection[1] - SELECTION_RANGE_OUT < event->button.y) && (event->button.y < preview_selection[1] + SELECTION_RANGE_IN) ) /* top */ + { + p->selection_yedge = 1; + } + else if ( (preview_selection[3] - SELECTION_RANGE_IN < event->button.y) && (event->button.y < preview_selection[3] + SELECTION_RANGE_OUT) ) /* bottom */ + { + p->selection_yedge = 3; + } + + if ( (p->selection_xedge != -1) && (p->selection_yedge != -1) ) /* move edge */ + { + p->selection_drag_edge = TRUE; + p->selection.coordinate[p->selection_xedge] = p->surface[0] + event->button.x / xscale; + p->selection.coordinate[p->selection_yedge] = p->surface[1] + event->button.y / yscale; + preview_draw_selection(p); + } + else /* select new area */ + { + p->selection_xedge = 2; + p->selection_yedge = 3; + p->selection.coordinate[0] = p->surface[0] + event->button.x / xscale; + p->selection.coordinate[1] = p->surface[1] + event->button.y / yscale; + p->selection_drag = TRUE; + + cursornr = GDK_CROSS; + cursor = gdk_cursor_new(cursornr); /* set curosr */ + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = cursornr; + } + break; + + case 2: /* middle button */ + case 3: /* right button */ + if ( (preview_selection[0]-SELECTION_RANGE_OUT < event->button.x) && + (preview_selection[2]+SELECTION_RANGE_OUT > event->button.x) && + (preview_selection[1]-SELECTION_RANGE_OUT < event->button.y) && + (preview_selection[3]+SELECTION_RANGE_OUT > event->button.y) ) + { + p->selection_drag = TRUE; + p->selection_xpos = event->button.x; + p->selection_ypos = event->button.y; + + cursornr = GDK_HAND2; + cursor = gdk_cursor_new(cursornr); /* set curosr */ + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = cursornr; + } + break; + + default: + break; + } + } + } + break; + + case GDK_BUTTON_RELEASE: + switch (((GdkEventButton *)event)->button) + { + case 1: /* left button */ + case 2: /* middle button */ + case 3: /* right button */ + if (p->selection_drag) + { + cursornr = XSANE_CURSOR_PREVIEW; + cursor = gdk_cursor_new(cursornr); /* set curosr */ + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = cursornr; + } + + if ( (p->selection_drag) || (p->selection_drag_edge) ) + { + + if (((GdkEventButton *)event)->button == 1) /* left button */ + { + p->selection.coordinate[p->selection_xedge] = p->surface[0] + event->button.x / xscale; + p->selection.coordinate[p->selection_yedge] = p->surface[1] + event->button.y / yscale; + } + + p->selection_drag_edge = FALSE; + p->selection_drag = FALSE; + + preview_order_selection(p); + preview_bound_selection(p); + preview_update_maximum_output_size(p); + preview_draw_selection(p); + preview_establish_selection(p); + } + default: + break; + } + break; + + case GDK_MOTION_NOTIFY: + switch (((GdkEventMotion *)event)->state) + { + case 256: /* left button */ + if (p->selection_drag_edge) + { + p->selection.active = TRUE; + p->selection.coordinate[p->selection_xedge] = p->surface[0] + event->button.x / xscale; + p->selection.coordinate[p->selection_yedge] = p->surface[1] + event->button.y / yscale; + + preview_order_selection(p); + preview_bound_selection(p); + preview_update_maximum_output_size(p); + preview_draw_selection(p); + + if ((preferences.gtk_update_policy == GTK_UPDATE_CONTINUOUS) && (event_count == 1)) + { + preview_establish_selection(p); + } + else if ((preferences.gtk_update_policy == GTK_UPDATE_DELAYED) && (event_count == 1)) + { + preview_establish_selection(p); + } + } + + if (p->selection_drag) + { + p->selection.active = TRUE; + p->selection.coordinate[p->selection_xedge] = p->surface[0] + event->motion.x / xscale; + p->selection.coordinate[p->selection_yedge] = p->surface[1] + event->motion.y / yscale; + + preview_order_selection(p); + preview_bound_selection(p); + preview_update_maximum_output_size(p); + preview_draw_selection(p); + + if ((preferences.gtk_update_policy == GTK_UPDATE_CONTINUOUS) && (event_count == 1)) + { + preview_establish_selection(p); + } + else if ((preferences.gtk_update_policy == GTK_UPDATE_DELAYED) && (event_count == 1)) + { + preview_establish_selection(p); + } + } + + cursornr = p->cursornr; + + if ( ( (preview_selection[0] - SELECTION_RANGE_OUT < event->button.x) && (event->button.x < preview_selection[0] + SELECTION_RANGE_IN) ) && /* left */ + ( (preview_selection[1] - SELECTION_RANGE_OUT < event->button.y) && (event->button.y < preview_selection[1] + SELECTION_RANGE_IN) ) ) /* top */ + { + cursornr = GDK_TOP_LEFT_CORNER; + } + else if ( ( (preview_selection[2] - SELECTION_RANGE_IN < event->button.x) && (event->button.x < preview_selection[2] + SELECTION_RANGE_OUT) ) && /* right */ + ( (preview_selection[1] - SELECTION_RANGE_OUT < event->button.y) && (event->button.y < preview_selection[1] + SELECTION_RANGE_IN) ) ) /* top */ + { + cursornr = GDK_TOP_RIGHT_CORNER; + } + else if ( ( (preview_selection[0] - SELECTION_RANGE_OUT < event->button.x) && (event->button.x < preview_selection[0] + SELECTION_RANGE_IN) ) && /* left */ + ( (preview_selection[3] - SELECTION_RANGE_IN < event->button.y) && (event->button.y < preview_selection[3] + SELECTION_RANGE_OUT) ) ) /* bottom */ + { + cursornr = GDK_BOTTOM_LEFT_CORNER; + } + else if ( ( (preview_selection[2] - SELECTION_RANGE_IN < event->button.x) && (event->button.x < preview_selection[2] + SELECTION_RANGE_OUT) ) && /* right */ + ( (preview_selection[3] - SELECTION_RANGE_IN < event->button.y) && (event->button.y < preview_selection[3] + SELECTION_RANGE_OUT) ) ) /* bottom */ + { + cursornr = GDK_BOTTOM_RIGHT_CORNER; + } + + if (cursornr != p->cursornr) + { + cursor = gdk_cursor_new(cursornr); /* set curosr */ + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = cursornr; + } + break; + + case 512: /* middle button */ + case 1024: /* right button */ + if (p->selection_drag) + { + int dx, dy; + + dx = p->selection_xpos - event->motion.x; + dy = p->selection_ypos - event->motion.y; + + p->selection_xpos = event->motion.x; + p->selection_ypos = event->motion.y; + + p->selection.active = TRUE; + p->selection.coordinate[0] -= dx / xscale; + p->selection.coordinate[1] -= dy / yscale; + p->selection.coordinate[2] -= dx / xscale; + p->selection.coordinate[3] -= dy / yscale; + + preview_bound_selection(p); + preview_update_maximum_output_size(p); + preview_draw_selection(p); + + if ((preferences.gtk_update_policy == GTK_UPDATE_CONTINUOUS) && (event_count == 1)) + { + preview_establish_selection(p); + } + else if ((preferences.gtk_update_policy == GTK_UPDATE_DELAYED) && (event_count == 1)) + { + preview_establish_selection(p); + } + } + break; + + default: + if ( ( (preview_selection[0] - SELECTION_RANGE_OUT < event->button.x) && (event->button.x < preview_selection[0] + SELECTION_RANGE_IN) ) && /* left */ + ( (preview_selection[1] - SELECTION_RANGE_OUT < event->button.y) && (event->button.y < preview_selection[1] + SELECTION_RANGE_IN) ) ) /* top */ + { + cursornr = GDK_TOP_LEFT_CORNER; + } + else if ( ( (preview_selection[2] - SELECTION_RANGE_IN < event->button.x) && (event->button.x < preview_selection[2] + SELECTION_RANGE_OUT) ) && /* right */ + ( (preview_selection[1] - SELECTION_RANGE_OUT < event->button.y) && (event->button.y < preview_selection[1] + SELECTION_RANGE_IN) ) ) /* top */ + { + cursornr = GDK_TOP_RIGHT_CORNER; + } + else if ( ( (preview_selection[0] - SELECTION_RANGE_OUT < event->button.x) && (event->button.x < preview_selection[0] + SELECTION_RANGE_IN) ) && /* left */ + ( (preview_selection[3] - SELECTION_RANGE_IN < event->button.y) && (event->button.y < preview_selection[3] + SELECTION_RANGE_OUT) ) ) /* bottom */ + { + cursornr = GDK_BOTTOM_LEFT_CORNER; + } + else if ( ( (preview_selection[2] - SELECTION_RANGE_IN < event->button.x) && (event->button.x < preview_selection[2] + SELECTION_RANGE_OUT) ) && /* right */ + ( (preview_selection[3] - SELECTION_RANGE_IN < event->button.y) && (event->button.y < preview_selection[3] + SELECTION_RANGE_OUT) ) ) /* bottom */ + { + cursornr = GDK_BOTTOM_RIGHT_CORNER; + } + else + { + cursornr = XSANE_CURSOR_PREVIEW; + } + + if ((cursornr != p->cursornr) && (p->cursornr != -1)) + { + cursor = gdk_cursor_new(cursornr); /* set curosr */ + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = cursornr; + } + break; + } + break; + + default: +#if 0 + fprintf(stderr, "preview_event_handler: unhandled event type %d\n", event->type); +#endif + break; + } + } + + while (gtk_events_pending()) /* make sure all selection draw is done now */ + { + gtk_main_iteration(); + } + + event_count--; + + return FALSE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_start_button_clicked(GtkWidget *widget, gpointer data) +{ + preview_scan(data); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_cancel_button_clicked(GtkWidget *widget, gpointer data) +{ + preview_scan_done(data); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +Preview *preview_new(GSGDialog *dialog) +{ + static int first_time = 1; + GtkWidget *table, *frame; + GtkSignalFunc signal_func; + GtkWidgetClass *class; + GtkBox *vbox, *hbox; + GdkCursor *cursor; + GtkWidget *preset_area_option_menu, *preset_area_menu, *preset_area_item; + Preview *p; + int i; + char buf[256]; + + p = malloc(sizeof(*p)); + if (!p) + { + return 0; + } + memset(p, 0, sizeof(*p)); + + p->mode = MODE_NORMAL; /* no pipette functions etc */ + p->dialog = dialog; + p->input_tag = -1; + + if (first_time) + { + first_time = 0; + gtk_preview_set_gamma(1.0); + gtk_preview_set_install_cmap(preferences.preview_own_cmap); + } + + p->preset_width = INF; /* use full scanarea */ + p->preset_height = INF; /* use full scanarea */ + + p->maximum_output_width = INF; /* full output with */ + p->maximum_output_height = INF; /* full output height */ + +#ifndef XSERVER_WITH_BUGGY_VISUALS + gtk_widget_push_visual(gtk_preview_get_visual()); +#endif + gtk_widget_push_colormap(gtk_preview_get_cmap()); + + snprintf(buf, sizeof(buf), "%s %s", WINDOW_PREVIEW, device_text); + p->top = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(p->top), buf); + vbox = GTK_BOX(GTK_DIALOG(p->top)->vbox); + hbox = GTK_BOX(GTK_DIALOG(p->top)->action_area); + + xsane_set_window_icon(p->top, 0); + + /* top hbox for pipette buttons */ + p->button_box = gtk_hbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(p->button_box), 4); + gtk_box_pack_start(GTK_BOX(vbox), p->button_box, FALSE, FALSE, 0); + + /* White, gray and black pipette button */ + p->pipette_white = xsane_button_new_with_pixmap(p->button_box, pipette_white_xpm, DESC_PIPETTE_WHITE, (GtkSignalFunc) preview_pipette_white, p); + p->pipette_gray = xsane_button_new_with_pixmap(p->button_box, pipette_gray_xpm, DESC_PIPETTE_GRAY, (GtkSignalFunc) preview_pipette_gray, p); + p->pipette_black = xsane_button_new_with_pixmap(p->button_box, pipette_black_xpm, DESC_PIPETTE_BLACK, (GtkSignalFunc) preview_pipette_black, p); + + /* Zoom not, zoom out and zoom in button */ + p->zoom_not = xsane_button_new_with_pixmap(p->button_box, zoom_not_xpm, DESC_ZOOM_FULL, (GtkSignalFunc) preview_zoom_not, p); + p->zoom_out = xsane_button_new_with_pixmap(p->button_box, zoom_out_xpm, DESC_ZOOM_OUT, (GtkSignalFunc) preview_zoom_out, p); + p->zoom_in = xsane_button_new_with_pixmap(p->button_box, zoom_in_xpm, DESC_ZOOM_IN, (GtkSignalFunc) preview_zoom_in, p); + p->zoom_undo = xsane_button_new_with_pixmap(p->button_box, zoom_undo_xpm, DESC_ZOOM_UNDO, (GtkSignalFunc) preview_zoom_undo, p); + + gtk_widget_set_sensitive(p->zoom_not, FALSE); /* no zoom at this point, so no zoom not */ + gtk_widget_set_sensitive(p->zoom_out, FALSE); /* no zoom at this point, so no zoom out */ + gtk_widget_set_sensitive(p->zoom_undo, FALSE); /* no zoom at this point, so no zoom undo */ + + + + xsane_button_new_with_pixmap(p->button_box, full_preview_area_xpm, DESC_FULL_PREVIEW_AREA, + (GtkSignalFunc) preview_full_preview_area, p); + + /* select maximum scanarea */ + preset_area_menu = gtk_menu_new(); + + for (i = 0; i < PRESET_AREA_ITEMS; ++i) + { + preset_area_item = gtk_menu_item_new_with_label(preset_area[i].name); + gtk_container_add(GTK_CONTAINER(preset_area_menu), preset_area_item); + gtk_signal_connect(GTK_OBJECT(preset_area_item), "activate", (GtkSignalFunc) preview_preset_area_callback, p); + gtk_object_set_data(GTK_OBJECT(preset_area_item), "Selection", (void *) i); + + gtk_widget_show(preset_area_item); + } + + preset_area_option_menu = gtk_option_menu_new(); + gtk_box_pack_start(GTK_BOX(p->button_box), preset_area_option_menu, FALSE, FALSE, 2); + gtk_option_menu_set_menu(GTK_OPTION_MENU(preset_area_option_menu), preset_area_menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(preset_area_option_menu), 0); /* full area */ +/* xsane_back_gtk_set_tooltip(tooltips, preset_area_option_menu, desc); */ + + gtk_widget_show(preset_area_option_menu); + p->preset_area_option_menu = preset_area_option_menu; + + gtk_widget_show(p->button_box); + + + + /* construct the preview area (table with sliders & preview window) */ + table = gtk_table_new(2, 2, /* homogeneous */ FALSE); + gtk_table_set_col_spacing(GTK_TABLE(table), 0, 1); + gtk_table_set_row_spacing(GTK_TABLE(table), 0, 1); + gtk_container_set_border_width(GTK_CONTAINER(table), 2); + gtk_box_pack_start(vbox, table, /* expand */ TRUE, /* fill */ TRUE, /* padding */ 0); + + /* the empty box in the top-left corner */ + frame = gtk_frame_new(/* label */ 0); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT); + gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + + /* the horizontal ruler */ + p->hruler = gtk_hruler_new(); + gtk_table_attach(GTK_TABLE(table), p->hruler, 1, 2, 0, 1, GTK_FILL, 0, 0, 0); + + /* the vertical ruler */ + p->vruler = gtk_vruler_new(); + gtk_table_attach(GTK_TABLE(table), p->vruler, 0, 1, 1, 2, 0, GTK_FILL, 0, 0); + + /* the preview area */ + + p->window = gtk_preview_new(GTK_PREVIEW_COLOR); + gtk_preview_set_expand(GTK_PREVIEW(p->window), TRUE); + gtk_widget_set_events(p->window, + GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + gtk_signal_connect(GTK_OBJECT(p->window), "event", (GtkSignalFunc) preview_event_handler, p); + gtk_signal_connect_after(GTK_OBJECT(p->window), "expose_event", (GtkSignalFunc) preview_expose_handler, p); + gtk_signal_connect_after(GTK_OBJECT(p->window), "size_allocate", (GtkSignalFunc) preview_area_resize, 0); + gtk_object_set_data(GTK_OBJECT(p->window), "PreviewPointer", p); + + /* Connect the motion-notify events of the preview area with the rulers. Nifty stuff! */ + + class = GTK_WIDGET_CLASS(GTK_OBJECT(p->hruler)->klass); + signal_func = (GtkSignalFunc) class->motion_notify_event; + gtk_signal_connect_object(GTK_OBJECT(p->window), "motion_notify_event", signal_func, GTK_OBJECT(p->hruler)); + + class = GTK_WIDGET_CLASS(GTK_OBJECT(p->vruler)->klass); + signal_func = (GtkSignalFunc) class->motion_notify_event; + gtk_signal_connect_object(GTK_OBJECT(p->window), "motion_notify_event", signal_func, GTK_OBJECT(p->vruler)); + + p->viewport = gtk_frame_new(/* label */ 0); + gtk_frame_set_shadow_type(GTK_FRAME(p->viewport), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER(p->viewport), p->window); + + gtk_table_attach(GTK_TABLE(table), p->viewport, 1, 2, 1, 2, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0); + + preview_update_surface(p, 0); + + /* fill in action area: */ + + /* Start button */ + p->start = gtk_button_new_with_label(BUTTON_PREVIEW_ACQUIRE); + gtk_signal_connect(GTK_OBJECT(p->start), "clicked", (GtkSignalFunc) preview_start_button_clicked, p); + gtk_box_pack_start(GTK_BOX(hbox), p->start, TRUE, TRUE, 0); + + /* Cancel button */ + p->cancel = gtk_button_new_with_label(BUTTON_PREVIEW_CANCEL); + gtk_signal_connect(GTK_OBJECT(p->cancel), "clicked", (GtkSignalFunc) preview_cancel_button_clicked, p); + gtk_box_pack_start(GTK_BOX(hbox), p->cancel, TRUE, TRUE, 0); + gtk_widget_set_sensitive(p->cancel, FALSE); + + gtk_widget_show(p->cancel); + gtk_widget_show(p->start); + gtk_widget_show(p->viewport); + gtk_widget_show(p->window); + gtk_widget_show(p->hruler); + gtk_widget_show(p->vruler); + gtk_widget_show(frame); + gtk_widget_show(table); + gtk_widget_show(p->top); + + cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW); /* set default curosr */ + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = XSANE_CURSOR_PREVIEW; + + gtk_widget_pop_colormap(); +#ifndef XSERVER_WITH_BUGGY_VISUALS + gtk_widget_pop_visual(); +#endif + return p; +} + + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_area_correct(Preview *p) +{ + float width, height, max_width, max_height; + + width = p->preview_width; + height = p->preview_height; + max_width = p->preview_window_width; + max_height = p->preview_window_height; + + width = max_width; + height = width / p->aspect; + + if (height > max_height) + { + height = max_height; + width = height * p->aspect; + } + + p->preview_width = width + 0.5; + p->preview_height = height + 0.5; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void preview_update_surface(Preview *p, int surface_changed) +{ + float val; + float width, height; + float max_width, max_height; + float preset_width, preset_height; + const SANE_Option_Descriptor *opt; + int i; + SANE_Value_Type type; + SANE_Unit unit; + double min, max; + + unit = SANE_UNIT_PIXEL; + type = SANE_TYPE_INT; + + for (i = 0; i < 4; ++i) /* test if surface (max vals of scanarea) has changed */ + { +/* val = (i & 2) ? INF : -INF; */ + val = (i & 2) ? INF : 0; + + if (p->dialog->well_known.coord[i] > 0) + { + opt = sane_get_option_descriptor(p->dialog->dev, p->dialog->well_known.coord[i]); + assert(opt->unit == SANE_UNIT_PIXEL || opt->unit == SANE_UNIT_MM); + unit = opt->unit; + type = opt->type; + + xsane_get_bounds(opt, &min, &max); + + if (i & 2) + { + val = max; + } + else + { + val = min; + } + } + + if (p->max_scanner_surface[i] != val) + { + surface_changed = 2; + p->max_scanner_surface[i] = val; + } + } + + if (surface_changed == 2) /* redefine all surface subparts */ + { + for (i = 0; i < 4; i++) + { + val = p->max_scanner_surface[i]; + p->scanner_surface[i] = val; + p->surface[i] = val; + p->image_surface[i] = val; + } + } + + max_width = p->max_scanner_surface[xsane_back_gtk_BR_X] - p->max_scanner_surface[xsane_back_gtk_TL_X]; + max_height = p->max_scanner_surface[xsane_back_gtk_BR_Y] - p->max_scanner_surface[xsane_back_gtk_TL_Y]; + + width = p->scanner_surface[xsane_back_gtk_BR_X] - p->scanner_surface[xsane_back_gtk_TL_X]; + height = p->scanner_surface[xsane_back_gtk_BR_Y] - p->scanner_surface[xsane_back_gtk_TL_Y]; + + preset_width = p->preset_width; + preset_height = p->preset_height; + + if (preset_width > max_width) + { + preset_width = max_width; + } + + if (preset_height > max_height) + { + preset_height = max_height; + } + + if ( (width != preset_width) || (height != preset_height) ) + { + p->scanner_surface[xsane_back_gtk_TL_X] = p->scanner_surface[xsane_back_gtk_TL_X]; + p->surface[xsane_back_gtk_TL_X] = p->scanner_surface[xsane_back_gtk_TL_X]; + p->image_surface[xsane_back_gtk_TL_X] = p->scanner_surface[xsane_back_gtk_TL_X]; + + p->scanner_surface[xsane_back_gtk_BR_X] = p->scanner_surface[xsane_back_gtk_TL_X] + preset_width; + p->surface[xsane_back_gtk_BR_X] = p->scanner_surface[xsane_back_gtk_TL_X] + preset_width; + p->image_surface[xsane_back_gtk_BR_X] = p->scanner_surface[xsane_back_gtk_TL_X] + preset_width; + + p->scanner_surface[xsane_back_gtk_TL_Y] = p->scanner_surface[xsane_back_gtk_TL_Y]; + p->surface[xsane_back_gtk_TL_Y] = p->scanner_surface[xsane_back_gtk_TL_Y]; + p->image_surface[xsane_back_gtk_TL_Y] = p->scanner_surface[xsane_back_gtk_TL_Y]; + + p->scanner_surface[xsane_back_gtk_BR_Y] = p->scanner_surface[xsane_back_gtk_TL_Y] + preset_height; + p->surface[xsane_back_gtk_BR_Y] = p->scanner_surface[xsane_back_gtk_TL_Y] + preset_height; + p->image_surface[xsane_back_gtk_BR_Y] = p->scanner_surface[xsane_back_gtk_TL_Y] + preset_height; + + surface_changed = 1; + } + + if (p->surface_unit != unit) + { + surface_changed = 1; + p->surface_unit = unit; + } + + if (p->surface_unit == SANE_UNIT_MM) + { + gtk_widget_set_sensitive(p->preset_area_option_menu, TRUE); /* enable preset area */ + } + else + { + gtk_widget_set_sensitive(p->preset_area_option_menu, FALSE); /* disable preset area */ + } + + if (p->surface_type != type) + { + surface_changed = 1; + p->surface_type = type; + } + + if (surface_changed) + { + /* guess the initial preview window size: */ + + width = p->surface[xsane_back_gtk_BR_X] - p->surface[xsane_back_gtk_TL_X]; + height = p->surface[xsane_back_gtk_BR_Y] - p->surface[xsane_back_gtk_TL_Y]; + + if (p->surface_type == SANE_TYPE_INT) + { + width += 1.0; + height += 1.0; + } + else + { + width += SANE_UNFIX(1.0); + height += SANE_UNFIX(1.0); + } + + assert(width > 0.0 && height > 0.0); + + if (width >= INF || height >= INF) + { + p->aspect = 1.0; + } + else + { + p->aspect = width/height; + } + } + else if ( (p->image_height) && (p->image_width) ) + { + p->aspect = p->image_width/(float) p->image_height; + } + + if ( (surface_changed) && (p->preview_window_width == 0) ) + { + p->preview_window_width = 0.5 * gdk_screen_width(); + p->preview_window_height = 0.5 * gdk_screen_height(); + } + + preview_area_correct(p); + + if (surface_changed) + { + gtk_widget_set_usize(GTK_WIDGET(p->window), p->preview_width, p->preview_height); + /* preview_area_resize is automatically called by signal handler */ + + preview_bound_selection(p); /* make sure selection is not larger than surface */ + preview_restore_image(p); /* draw selected surface of the image */ + } + else + { + preview_update_selection(p); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void preview_scan(Preview *p) +{ + double min, max, swidth, sheight, width, height, dpi = 0; + const SANE_Option_Descriptor *opt; + gint gwidth, gheight; + int i; + + xsane.block_update_param = TRUE; /* do not change parameters each time */ + + preview_save_option(p, p->dialog->well_known.dpi, &p->saved_dpi, &p->saved_dpi_valid); + preview_save_option(p, p->dialog->well_known.dpi_x, &p->saved_dpi_x, &p->saved_dpi_x_valid); + preview_save_option(p, p->dialog->well_known.dpi_y, &p->saved_dpi_y, &p->saved_dpi_y_valid); + + for (i = 0; i < 4; ++i) + { + preview_save_option(p, p->dialog->well_known.coord[i], &p->saved_coord[i], p->saved_coord_valid + i); + } + preview_save_option(p, p->dialog->well_known.bit_depth, &p->saved_bit_depth, &p->saved_bit_depth_valid); + + /* determine dpi, if necessary: */ + + if (p->dialog->well_known.dpi > 0) + { + opt = sane_get_option_descriptor(p->dialog->dev, p->dialog->well_known.dpi); + + gwidth = p->preview_width; + gheight = p->preview_height; + + height = gheight; + width = height * p->aspect; + + if (width > gwidth) + { + width = gwidth; + height = width / p->aspect; + } + + swidth = (p->surface[xsane_back_gtk_BR_X] - p->surface[xsane_back_gtk_TL_X]); + + if (swidth < INF) + { + dpi = MM_PER_INCH * width/swidth; + } + else + { + sheight = (p->surface[xsane_back_gtk_BR_Y] - p->surface[xsane_back_gtk_TL_Y]); + if (sheight < INF) + { + dpi = MM_PER_INCH * height/sheight; + } + else + { + dpi = 18.0; + } + } + + xsane_get_bounds(opt, &min, &max); + + if (dpi < min) + { + dpi = min; + } + + if (dpi > max) + { + dpi = max; + } + + xsane_set_resolution(p->dialog->well_known.dpi, dpi); /* set resolution to dpi or next higher value that is available */ + xsane_set_resolution(p->dialog->well_known.dpi_x, dpi); /* set resolution to dpi or next higher value that is available */ + xsane_set_resolution(p->dialog->well_known.dpi_y, dpi); /* set resolution to dpi or next higher value that is available */ + } + + /* set the scan window (necessary since backends may default to non-maximum size): */ + + for (i = 0; i < 4; ++i) + { + preview_set_option_float(p, p->dialog->well_known.coord[i], p->surface[i]); + } + + preview_set_option_bool(p, p->dialog->well_known.preview, SANE_TRUE); + + if ( (p->saved_bit_depth > 8) && (p->saved_bit_depth_valid) ) /* don't scan with more than 8bpp */ + { + preview_set_option_int(p, p->dialog->well_known.bit_depth, 8); + } + + xsane.block_update_param = FALSE; + + /* OK, all set to go */ + preview_scan_start(p); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_save_image_file(Preview *p, FILE *out) +{ + if (out) + { + /* always save it as a PPM image: */ + fprintf(out, "P6\n# surface: %g %g %g %g %u %u\n%d %d\n255\n", + p->surface[0], p->surface[1], p->surface[2], p->surface[3], + p->surface_type, p->surface_unit, p->image_width, p->image_height); + + fwrite(p->image_data_raw, 3, p->image_width*p->image_height, out); + fclose(out); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_save_image(Preview *p) +{ + char filename[PATH_MAX]; + FILE *out; + int status; + + if (!p->image_data_enh) + { + return; + } + + if ( GROSSLY_EQUAL(p->max_scanner_surface[0], p->surface[0]) && /* full device surface */ + GROSSLY_EQUAL(p->max_scanner_surface[1], p->surface[1]) && + GROSSLY_EQUAL(p->max_scanner_surface[2], p->surface[2]) && + GROSSLY_EQUAL(p->max_scanner_surface[3], p->surface[3]) ) + { + status = preview_make_image_path(p, sizeof(filename), filename, 0); + } + else if ( GROSSLY_EQUAL(p->scanner_surface[0], p->surface[0]) && /* user defined surface */ + GROSSLY_EQUAL(p->scanner_surface[1], p->surface[1]) && + GROSSLY_EQUAL(p->scanner_surface[2], p->surface[2]) && + GROSSLY_EQUAL(p->scanner_surface[3], p->surface[3]) ) + { + status = preview_make_image_path(p, sizeof(filename), filename, 1); + } + else /* zoom area */ + { + status = preview_make_image_path(p, sizeof(filename), filename, 2); + } + + if (status >= 0) + { + /* save preview image */ + remove(filename); /* remove existing preview */ + umask(0177); /* creare temporary file with "-rw-------" permissions */ + out = fopen(filename, "w"); + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + + preview_save_image_file(p, out); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void preview_destroy(Preview *p) +{ + int level; + int status; + char filename[PATH_MAX]; + + if (p->scanning) + { + preview_scan_done(p); /* don't save partial window */ + } + else + { + preview_save_image(p); + } + + if (!preferences.preserve_preview) + { + for(level = 0; level <= 2; level++) + { + status = preview_make_image_path(p, sizeof(filename), filename, level); + if (status >= 0) + { + remove(filename); /* remove existing preview */ + } + } + } + + if (p->image_data_enh) + { + free(p->image_data_enh); + p->image_data_enh = 0; + } + + if (p->image_data_raw) + { + free(p->image_data_raw); + p->image_data_raw = 0; + } + + if (p->preview_row) + { + free(p->preview_row); + p->preview_row = 0; + } + + if (p->gc_selection) + { + gdk_gc_destroy(p->gc_selection); + } + + if (p->gc_selection_maximum) + { + gdk_gc_destroy(p->gc_selection_maximum); + } + + if (p->top) + { + gtk_widget_destroy(p->top); + } + free(p); + + p = 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_zoom_not(GtkWidget *window, gpointer data) +{ + Preview *p=data; + int i; + + for (i=0; i<4; i++) + { + p->surface[i] = p->scanner_surface[i]; + } + + preview_update_surface(p, 1); + gtk_widget_set_sensitive(p->zoom_not, FALSE); /* forbid unzoom */ + gtk_widget_set_sensitive(p->zoom_out, FALSE); /* forbid zoom out */ + gtk_widget_set_sensitive(p->zoom_undo,TRUE); /* allow zoom undo */ + + while (gtk_events_pending()) /* make sure all selection draw is done now */ + { + gtk_main_iteration(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_zoom_out(GtkWidget *window, gpointer data) +{ + Preview *p=data; + int i; + float delta_width = (p->surface[2] - p->surface[0]) * 0.2; + float delta_height = (p->surface[3] - p->surface[1]) * 0.2; + + for (i=0; i<4; i++) + { + p->old_surface[i] = p->surface[i]; + } + + p->surface[0] -= delta_width; + p->surface[1] -= delta_height; + p->surface[2] += delta_width; + p->surface[3] += delta_height; + + if (p->surface[0] < p->scanner_surface[0]) + { + p->surface[0] = p->scanner_surface[0]; + } + + if (p->surface[1] < p->scanner_surface[1]) + { + p->surface[1] = p->scanner_surface[1]; + } + + if (p->surface[2] > p->scanner_surface[2]) + { + p->surface[2] = p->scanner_surface[2]; + } + + if (p->surface[3] > p->scanner_surface[3]) + { + p->surface[3] = p->scanner_surface[3]; + } + + preview_update_surface(p, 1); + gtk_widget_set_sensitive(p->zoom_not, TRUE); /* allow unzoom */ + gtk_widget_set_sensitive(p->zoom_undo,TRUE); /* allow zoom undo */ + + while (gtk_events_pending()) /* make sure all selection draw is done now */ + { + gtk_main_iteration(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_zoom_in(GtkWidget *window, gpointer data) +{ + Preview *p=data; + const SANE_Option_Descriptor *opt; + SANE_Status status; + SANE_Word val; + int i, optnum; + + for (i=0; i<4; i++) + { + p->old_surface[i] = p->surface[i]; + + optnum = p->dialog->well_known.coord[i]; + if (optnum > 0) + { + opt = sane_get_option_descriptor(p->dialog->dev, optnum); + status = sane_control_option(p->dialog->dev, optnum, SANE_ACTION_GET_VALUE, &val, 0); + if (status != SANE_STATUS_GOOD) + { + continue; + } + + if (opt->type == SANE_TYPE_FIXED) + { + p->surface[i] = SANE_UNFIX(val); + } + else + { + p->surface[i] = val; + } + } + } + + preview_update_surface(p, 1); + gtk_widget_set_sensitive(p->zoom_not, TRUE); /* allow unzoom */ + gtk_widget_set_sensitive(p->zoom_out, TRUE); /* allow zoom out */ + gtk_widget_set_sensitive(p->zoom_undo,TRUE); /* allow zoom undo */ + + while (gtk_events_pending()) /* make sure all selection draw is done now */ + { + gtk_main_iteration(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_zoom_undo(GtkWidget *window, gpointer data) +{ + Preview *p=data; + int i; + + for (i=0; i<4; i++) + { + p->surface[i] = p->old_surface[i]; + } + + preview_update_surface(p, 1); + gtk_widget_set_sensitive(p->zoom_not, TRUE); /* allow unzoom */ + gtk_widget_set_sensitive(p->zoom_out, TRUE); /* allow zoom out */ + gtk_widget_set_sensitive(p->zoom_undo, FALSE); /* forbid zoom undo */ + + while (gtk_events_pending()) /* make sure all selection draw is done now */ + { + gtk_main_iteration(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_get_color(Preview *p, int x, int y, int *red, int *green, int *blue) +{ + int image_x, image_y; + float xscale_p2i, yscale_p2i; + int offset; + + if (p->image_data_raw) + { + preview_get_scale_preview_to_image(p, &xscale_p2i, &yscale_p2i); + + image_x = x * xscale_p2i; + image_y = y * yscale_p2i; + + offset = 3 * (image_y * p->image_width + image_x); + + if (!xsane.negative) /* positive */ + { + *red = p->image_data_raw[offset ]; + *green = p->image_data_raw[offset + 1]; + *blue = p->image_data_raw[offset + 2]; + } + else /* negative */ + { + *red = 255 - p->image_data_raw[offset ]; + *green = 255 - p->image_data_raw[offset + 1]; + *blue = 255 - p->image_data_raw[offset + 2]; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_pipette_white(GtkWidget *window, gpointer data) +{ + Preview *p=data; + GdkCursor *cursor; + GdkColor fg; + GdkColor bg; + GdkPixmap *pixmap; + GdkPixmap *mask; + + p->mode = MODE_PIPETTE_WHITE; + + pixmap = gdk_bitmap_create_from_data(p->top->window, cursor_pipette_white, CURSOR_PIPETTE_WIDTH, CURSOR_PIPETTE_HEIGHT); + mask = gdk_bitmap_create_from_data(p->top->window, cursor_pipette_mask, CURSOR_PIPETTE_WIDTH, CURSOR_PIPETTE_HEIGHT); + + fg.red = 0; + fg.green = 0; + fg.blue = 0; + + bg.red = 65535; + bg.green = 65535; + bg.blue = 65535; + + cursor = gdk_cursor_new_from_pixmap(pixmap, mask, &fg, &bg, CURSOR_PIPETTE_HOT_X, CURSOR_PIPETTE_HOT_Y); + + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = -1; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_pipette_gray(GtkWidget *window, gpointer data) +{ + Preview *p=data; + GdkCursor *cursor; + GdkColor fg; + GdkColor bg; + GdkPixmap *pixmap; + GdkPixmap *mask; + + p->mode = MODE_PIPETTE_GRAY; + + pixmap = gdk_bitmap_create_from_data(p->top->window, cursor_pipette_gray, CURSOR_PIPETTE_WIDTH, CURSOR_PIPETTE_HEIGHT); + mask = gdk_bitmap_create_from_data(p->top->window, cursor_pipette_mask, CURSOR_PIPETTE_WIDTH, CURSOR_PIPETTE_HEIGHT); + + fg.red = 0; + fg.green = 0; + fg.blue = 0; + + bg.red = 65535; + bg.green = 65535; + bg.blue = 65535; + + cursor = gdk_cursor_new_from_pixmap(pixmap, mask, &fg, &bg, CURSOR_PIPETTE_HOT_X, CURSOR_PIPETTE_HOT_Y); + + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = -1; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_pipette_black(GtkWidget *window, gpointer data) +{ + Preview *p=data; + GdkCursor *cursor; + GdkColor fg; + GdkColor bg; + GdkPixmap *pixmap; + GdkPixmap *mask; + + p->mode = MODE_PIPETTE_BLACK; + + pixmap = gdk_bitmap_create_from_data(p->top->window, cursor_pipette_black, CURSOR_PIPETTE_WIDTH, CURSOR_PIPETTE_HEIGHT); + mask = gdk_bitmap_create_from_data(p->top->window, cursor_pipette_mask , CURSOR_PIPETTE_WIDTH, CURSOR_PIPETTE_HEIGHT); + + fg.red = 0; + fg.green = 0; + fg.blue = 0; + + bg.red = 65535; + bg.green = 65535; + bg.blue = 65535; + + cursor = gdk_cursor_new_from_pixmap(pixmap, mask, &fg, &bg, CURSOR_PIPETTE_HOT_X, CURSOR_PIPETTE_HOT_Y); + + gdk_window_set_cursor(p->window->window, cursor); + gdk_cursor_destroy(cursor); + p->cursornr = -1; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_full_preview_area(GtkWidget *widget, gpointer call_data) +{ + Preview *p = call_data; + int i; + + p->selection.active = TRUE; + + for (i=0; i<4; i++) + { + p->selection.coordinate[i] = p->surface[i]; + } + + preview_update_maximum_output_size(p); + preview_draw_selection(p); + preview_establish_selection(p); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void preview_preset_area_callback(GtkWidget *widget, gpointer call_data) +{ + Preview *p = call_data; + int selection; + + selection = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection"); + + p->preset_width = preset_area[selection].width; + p->preset_height = preset_area[selection].height; + + preview_update_surface(p, 0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void preview_do_gamma_correction(Preview *p) +{ + int x,y; + int offset; + + if (p->image_data_raw) + { + if ((p->image_data_raw) && (p->params.depth > 1) && (preview_gamma_data_red)) + { + for (y=0; y < p->image_height; y++) + { + for (x=0; x < p->image_width; x++) + { + offset = 3 * (y * p->image_width + x); + p->image_data_enh[offset ] = preview_gamma_data_red [p->image_data_raw[offset ]]; + p->image_data_enh[offset + 1] = preview_gamma_data_green[p->image_data_raw[offset + 1]]; + p->image_data_enh[offset + 2] = preview_gamma_data_blue [p->image_data_raw[offset + 2]]; + } + } + } + + preview_display_partial_image(p); + + p->previous_selection.active = FALSE; /* previous selection is not drawn */ + p->previous_selection_maximum.active = FALSE; + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void preview_calculate_histogram(Preview *p, + SANE_Int *count_raw, SANE_Int *count_raw_red, SANE_Int *count_raw_green, SANE_Int *count_raw_blue, + SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue) +{ + int x, y; + int offset; + SANE_Int red_raw, green_raw, blue_raw; + SANE_Int red, green, blue; + SANE_Int min_x, max_x, min_y, max_y; + float xscale, yscale; + + preview_get_scale_device_to_image(p, &xscale, &yscale); + + min_x = (p->selection.coordinate[0] - p->surface[0]) * xscale; + min_y = (p->selection.coordinate[1] - p->surface[1]) * yscale; + max_x = (p->selection.coordinate[2] - p->surface[0]) * xscale; + max_y = (p->selection.coordinate[3] - p->surface[1]) * yscale; + + if (min_x < 0) + { + min_x = 0; + } + + if (max_x >= p->image_width) + { + max_x = p->image_width-1; + } + + if (min_y < 0) + { + min_y = 0; + } + + if (max_y >= p->image_height) + { + max_y = p->image_height-1; + } + + if ((p->image_data_raw) && (p->params.depth > 1) && (preview_gamma_data_red)) + { + for (y = min_y; y <= max_y; y++) + { + for (x = min_x; x <= max_x; x++) + { + offset = 3 * (y * p->image_width + x); + red_raw = p->image_data_raw[offset ]; + green_raw = p->image_data_raw[offset + 1]; + blue_raw = p->image_data_raw[offset + 2]; + + red = histogram_gamma_data_red [red_raw]; + green = histogram_gamma_data_green[green_raw]; + blue = histogram_gamma_data_blue [blue_raw]; + +/* count_raw [(int) sqrt((red_raw*red_raw + green_raw*green_raw + blue_raw*blue_raw)/3.0)]++; */ + count_raw [(int) ((red_raw + green_raw + blue_raw)/3)]++; + count_raw_red [red_raw]++; + count_raw_green[green_raw]++; + count_raw_blue [blue_raw]++; + +/* count [(int) sqrt((red*red + green*green + blue*blue)/3.0)]++; */ + count [(int) ((red + green + blue)/3)]++; + count_red [red]++; + count_green[green]++; + count_blue [blue]++; + } + } + } + else /* no preview image => all colors = 1 */ + { + int i; + + for (i = 1; i <= 254; i++) + { + count_raw [i] = 0; + count_raw_red [i] = 0; + count_raw_green[i] = 0; + count_raw_blue [i] = 0; + + count [i] = 0; + count_red [i] = 0; + count_green[i] = 0; + count_blue [i] = 0; + } + + count_raw [0] = 10; + count_raw_red [0] = 10; + count_raw_green[0] = 10; + count_raw_blue [0] = 10; + + count [0] = 10; + count_red [0] = 10; + count_green[0] = 10; + count_blue [0] = 10; + + count_raw [255] = 10; + count_raw_red [255] = 10; + count_raw_green[255] = 10; + count_raw_blue [255] = 10; + + count [255] = 10; + count_red [255] = 10; + count_green[255] = 10; + count_blue [255] = 10; + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void preview_gamma_correction(Preview *p, + SANE_Int *gamma_red, SANE_Int *gamma_green, SANE_Int *gamma_blue, + SANE_Int *gamma_red_hist, SANE_Int *gamma_green_hist, SANE_Int *gamma_blue_hist) +{ + preview_gamma_data_red = gamma_red; + preview_gamma_data_green = gamma_green; + preview_gamma_data_blue = gamma_blue; + + histogram_gamma_data_red = gamma_red_hist; + histogram_gamma_data_green = gamma_green_hist; + histogram_gamma_data_blue = gamma_blue_hist; + + preview_do_gamma_correction(p); + preview_draw_selection(p); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void preview_area_resize(GtkWidget *widget) +{ + float min_x, max_x, delta_x; + float min_y, max_y, delta_y; + float xscale, yscale, f; + Preview *p; + + p = gtk_object_get_data(GTK_OBJECT(widget), "PreviewPointer"); + + p->preview_window_width = widget->allocation.width; + p->preview_window_height = widget->allocation.height; + + p->preview_width = widget->allocation.width; + p->preview_height = widget->allocation.height; + + preview_area_correct(p); /* set preview dimensions (with right aspect) that they fit into the window */ + + if (p->preview_row) /* make sure preview_row is large enough for one line of the new size */ + { + p->preview_row = realloc(p->preview_row, 3 * p->preview_window_width); + } + else + { + p->preview_row = malloc(3 * p->preview_window_width); + } + + /* set the ruler ranges: */ + + min_x = p->surface[xsane_back_gtk_TL_X]; + if (min_x <= -INF) + { + min_x = 0.0; + } + + max_x = p->surface[xsane_back_gtk_BR_X]; + if (max_x >= INF) + { + max_x = p->image_width - 1; + } + + min_y = p->surface[xsane_back_gtk_TL_Y]; + if (min_y <= -INF) + { + min_y = 0.0; + } + + max_y = p->surface[xsane_back_gtk_BR_Y]; + if (max_y >= INF) + { + max_y = p->image_height - 1; + } + + /* convert mm to inches if that's what the user wants: */ + + if (p->surface_unit == SANE_UNIT_MM) + { + double factor = 1.0/preferences.length_unit; + + min_x *= factor; + max_x *= factor; + min_y *= factor; + max_y *= factor; + } + + preview_get_scale_preview_to_image(p, &xscale, &yscale); + + if (p->image_width > 0) + { + f = xscale * p->preview_width / p->image_width; + } + else + { + f = 1.0; + } + + min_x *= f; + max_x *= f; + delta_x = max_x - min_x; + + gtk_ruler_set_range(GTK_RULER(p->hruler), min_x, min_x + delta_x*p->preview_window_width/p->preview_width, + min_x, /* max_size */ 20); + + if (p->image_height > 0) + { + f = yscale * p->preview_height / p->image_height; + } + else + { + f = 1.0; + } + + min_y *= f; + max_y *= f; + delta_y = max_y - min_y; + + gtk_ruler_set_range(GTK_RULER(p->vruler), min_y, min_y + delta_y*p->preview_window_height/p->preview_height, + min_y, /* max_size */ 20); + + preview_paint_image(p); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void preview_update_maximum_output_size(Preview *p) +{ + if ( (p->maximum_output_width >= INF) || (p->maximum_output_height >= INF) ) + { + if (p->selection_maximum.active) + { + p->selection_maximum.active = FALSE; + } + } + else + { + p->previous_selection_maximum = p->selection_maximum; + + p->selection_maximum.active = TRUE; + p->selection_maximum.coordinate[0] = p->selection.coordinate[0]; + p->selection_maximum.coordinate[1] = p->selection.coordinate[1]; + p->selection_maximum.coordinate[2] = p->selection.coordinate[0] + p->maximum_output_width; + p->selection_maximum.coordinate[3] = p->selection.coordinate[1] + p->maximum_output_height; + + if (p->selection_maximum.coordinate[2] > p->max_scanner_surface[2]) + { + p->selection_maximum.coordinate[2] = p->max_scanner_surface[2]; + } + + if (p->selection_maximum.coordinate[3] > p->max_scanner_surface[3]) + { + p->selection_maximum.coordinate[3] = p->max_scanner_surface[3]; + } + + if ( (p->selection.coordinate[0] < p->selection_maximum.coordinate[0]) || + (p->selection.coordinate[1] < p->selection_maximum.coordinate[1]) || + (p->selection.coordinate[2] > p->selection_maximum.coordinate[2]) || + (p->selection.coordinate[3] > p->selection_maximum.coordinate[3]) ) + { + if (p->selection.coordinate[2] > p->selection_maximum.coordinate[2]) + { + p->selection.coordinate[2] = p->selection_maximum.coordinate[2]; + } + + if (p->selection.coordinate[3] > p->selection_maximum.coordinate[3]) + { + p->selection.coordinate[3] = p->selection_maximum.coordinate[3]; + } + preview_draw_selection(p); + preview_establish_selection(p); + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void preview_set_maximum_output_size(Preview *p, float width, float height) +{ + /* witdh and height in device units */ + + p->maximum_output_width = width; + p->maximum_output_height = height; + + preview_update_maximum_output_size(p); + preview_draw_selection(p); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-preview.h b/frontend/xsane-preview.h new file mode 100644 index 0000000..fd452ee --- /dev/null +++ b/frontend/xsane-preview.h @@ -0,0 +1,178 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-preview.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ------------------------------------------------------------------------------------------------------ */ + +#ifndef xsanepreview_h +#define xsanepreview_h + +/* ------------------------------------------------------------------------------------------------------ */ + +#include <sys/types.h> + +#include <sane/config.h> +#include <sane/sane.h> + +#define SELECTION_RANGE_IN 4 +#define SELECTION_RANGE_OUT 8 +#define XSANE_CURSOR_PREVIEW GDK_LEFT_PTR + +/* ------------------------------------------------------------------------------------------------------ */ + +enum +{ + MODE_NORMAL, + MODE_PIPETTE_WHITE, + MODE_PIPETTE_GRAY, + MODE_PIPETTE_BLACK +}; + +/* ------------------------------------------------------------------------------------------------------ */ + +typedef struct Batch_selection +{ + float coordinate[4]; /* batch selection coordinate (device coord) */ + struct Batch_selection *next; +} Batch_selection; + +typedef struct +{ + int active; + float coordinate[4]; /* selection coordinate (device coord) */ +} Tselection; + +/* ------------------------------------------------------------------------------------------------------ */ + +typedef struct +{ + int mode; + GSGDialog *dialog; /* the dialog for this preview */ + + int cursornr; + + SANE_Value_Type surface_type; + SANE_Unit surface_unit; + float surface[4]; /* the corners of the selected surface (device coords) */ + float old_surface[4]; /* the corners of the old selected surface (device coords) */ + float max_scanner_surface[4]; /* the scanner defined corners of the scanner surface (device coords) */ + float scanner_surface[4]; /* the user defined corners of the scanner surface (device coords) */ + float image_surface[4]; /* the corners of the surface (device coords) of the scanned image */ + float aspect; /* the aspect ratio of the scan surface */ + + float preset_width; /* user selected maximum scan width */ + float preset_height; /* user selected maximum scan height */ + + float maximum_output_width; /* maximum output width (photocopy) */ + float maximum_output_height; /* maximum output height (photocopy) */ + + int saved_dpi_valid; + int saved_dpi_x_valid; + int saved_dpi_y_valid; + SANE_Word saved_dpi; + SANE_Word saved_dpi_x; + SANE_Word saved_dpi_y; + int saved_coord_valid[4]; + SANE_Word saved_coord[4]; + int saved_custom_gamma_valid; + SANE_Word saved_custom_gamma; + int saved_bit_depth_valid; + SANE_Word saved_bit_depth; + + /* desired/user-selected preview-window size: */ + int preview_width; /* used with for displaying the preview image */ + int preview_height; /* used height for displaying the preview image */ + int preview_window_width; /* width of the preview window */ + int preview_window_height; /* height of the preview window */ + u_char *preview_row; + + int scanning; + time_t image_last_time_updated; + gint input_tag; + SANE_Parameters params; + int image_offset; + int image_x; + int image_y; + int image_width; /* width of preview image in pixels */ + int image_height; /* height of preview image in pixel lines */ + u_char *image_data_raw; /* 3 * image_width * image_height bytes */ + u_char *image_data_enh; /* 3 * image_width * image_height bytes */ + + GdkGC *gc_selection; + GdkGC *gc_selection_maximum; + int selection_drag; + int selection_drag_edge; + int selection_xpos; + int selection_ypos; + int selection_xedge; + int selection_yedge; + + Tselection selection; /* selected area to scan */ + Tselection previous_selection; /* previous ... */ + Tselection selection_maximum; /* maximum selection size (photocopy) */ + Tselection previous_selection_maximum; /* previous ... */ + + Batch_selection *batch_selection; + + GtkWidget *top; /* top-level widget */ + GtkWidget *hruler; + GtkWidget *vruler; + GtkWidget *viewport; + GtkWidget *window; /* the preview window */ + GtkWidget *start; /* the start button */ + GtkWidget *cancel; /* the cancel button */ + + GtkWidget *button_box; /* hbox for the following buttons */ + GtkWidget *pipette_white; /* pipette white button */ + GtkWidget *pipette_gray; /* pipette gray button */ + GtkWidget *pipette_black; /* pipette black button */ + GtkWidget *zoom_not; /* zoom not button */ + GtkWidget *zoom_out; /* zoom out button */ + GtkWidget *zoom_in; /* zoom in button */ + GtkWidget *zoom_undo; /* zoom undo button */ + GtkWidget *preset_area_option_menu; /* menu for selection of preview area */ +} +Preview; + +/* ------------------------------------------------------------------------------------------------------ */ + +extern Preview *preview_new (GSGDialog *dialog); /* Create a new preview based on the info in DIALOG. */ + +extern void preview_gamma_correction(Preview *p, /* Do gamma correction on preview data */ + int gamma_red[], int gamma_green[], int gamma_blue[], + int gamma_red_hist[], int gamma_green_hist[], int gamma_blue_hist[]); + +extern void preview_update_surface(Preview *p, int surface_changed); /* params changed: update preview */ + +extern void preview_scan(Preview *p); /* Acquire a preview image and display it. */ + +extern void preview_destroy(Preview *p); /* Destroy a preview. */ + +extern void preview_calculate_histogram(Preview *p, /* calculate histogram */ + SANE_Int *count_raw, SANE_Int *count_raw_red, SANE_Int *count_raw_green, SANE_Int *count_raw_blue, + SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue); + +extern void preview_area_resize(GtkWidget *widget); /* redraw preview rulers */ +void preview_set_maximum_output_size(Preview *p, float width, float height); /* set maximum outut size */ + +/* ------------------------------------------------------------------------------------------------------ */ + +#endif /* preview_h */ diff --git a/frontend/xsane-rc-io.c b/frontend/xsane-rc-io.c new file mode 100644 index 0000000..520e97e --- /dev/null +++ b/frontend/xsane-rc-io.c @@ -0,0 +1,903 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-rc-io.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ---------------------------------------------------------------------------------------------------------------- */ + +#ifdef _AIX +# include <lalloca.h> /* MUST come first for AIX! */ +#endif +#include <sane/config.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sane/sane.h> +#include <sane/config.h> +#include <ctype.h> +#include <unistd.h> + +#ifdef HAVE_LIBC_H +# include <libc.h> /* NeXTStep/OpenStep */ +#endif + +#include <sane/sane.h> +#include "xsane-rc-io.h" + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_space(Wire *w, size_t howmuch) +{ + size_t nbytes, left_over; + int fd = w->io.fd; + ssize_t nread, nwritten; + + if (w->buffer.curr + howmuch > w->buffer.end) + { + switch (w->direction) + { + case WIRE_ENCODE: + nbytes = w->buffer.curr - w->buffer.start; + w->buffer.curr = w->buffer.start; + while (nbytes > 0) + { + nwritten = (*w->io.write) (fd, w->buffer.curr, nbytes); + if (nwritten < 0) + { + w->status = errno; + return; + } + w->buffer.curr += nwritten; + nbytes -= nwritten; + } + + w->buffer.curr = w->buffer.start; + w->buffer.end = w->buffer.start + w->buffer.size; + break; + + case WIRE_DECODE: + left_over = w->buffer.end - w->buffer.curr; + if (left_over) + { + memcpy(w->buffer.start, w->buffer.curr, left_over); + } + w->buffer.curr = w->buffer.start; + w->buffer.end = w->buffer.start + left_over; + + do + { + nread = (*w->io.read) (fd, w->buffer.end, w->buffer.size - left_over); + if (nread <= 0) + { + if (nread == 0) + { +/* errno = EINVAL; */ + errno = XSANE_EOF; + } + w->status = errno; + return; + } + left_over += nread; + w->buffer.end += nread; + } while (left_over < howmuch); + break; + + case WIRE_FREE: + break; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +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) +{ + SANE_Word len; + char *val; + int i; + + if (w->direction == WIRE_FREE) + { + free(*v); + return; + } + + if (w->direction == WIRE_ENCODE) + { + len = *len_ptr; + } + + xsane_rc_io_w_word(w, &len); + + if (w->direction == WIRE_DECODE) + { + *len_ptr = len; + if (len) + { + *v = malloc(len * element_size); + + if (*v == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + else + { + *v = 0; + } + } + + val = *v; + + for (i = 0; i < len; ++i) + { + (*w_element) (w, val); + val += element_size; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_ptr(Wire *w, void **v, WireCodecFunc w_value, size_t value_size) +{ + SANE_Word is_null; + + if (w->direction == WIRE_FREE) + { + if (*v) + { + free(*v); + } + return; + } + + if (w->direction == WIRE_ENCODE) + { + is_null = (*v == 0); + } + + xsane_rc_io_w_word(w, &is_null); + + if (!is_null) + { + if (w->direction == WIRE_DECODE) + { + *v = malloc(value_size); + + if (*v == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + (*w_value) (w, *v); + } + else if (w->direction == WIRE_DECODE) + { + *v = 0; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_status(Wire *w, SANE_Status *v) +{ + SANE_Word word = *v; + + xsane_rc_io_w_word(w, &word); + if (w->direction == WIRE_DECODE) + { + *v = word; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_bool(Wire *w, SANE_Bool *v) +{ + SANE_Word word = *v; + + xsane_rc_io_w_word(w, &word); + if (w->direction == WIRE_DECODE) + { + *v = word; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_constraint_type(Wire *w, SANE_Constraint_Type *v) +{ + SANE_Word word = *v; + + xsane_rc_io_w_word(w, &word); + if (w->direction == WIRE_DECODE) + *v = word; +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_value_type(Wire *w, SANE_Value_Type *v) +{ + SANE_Word word = *v; + + xsane_rc_io_w_word(w, &word); + if (w->direction == WIRE_DECODE) + *v = word; +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_unit(Wire *w, SANE_Unit *v) +{ + SANE_Word word = *v; + + xsane_rc_io_w_word(w, &word); + if (w->direction == WIRE_DECODE) + { + *v = word; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_action(Wire *w, SANE_Action *v) +{ + SANE_Word word = *v; + + xsane_rc_io_w_word(w, &word); + if (w->direction == WIRE_DECODE) + { + *v = word; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_frame(Wire *w, SANE_Frame *v) +{ + SANE_Word word = *v; + + xsane_rc_io_w_word(w, &word); + if (w->direction == WIRE_DECODE) + { + *v = word; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_range(Wire *w, SANE_Range *v) +{ + xsane_rc_io_w_word(w, &v->min); + xsane_rc_io_w_word(w, &v->max); + xsane_rc_io_w_word(w, &v->quant); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_device(Wire *w, SANE_Device *v) +{ + xsane_rc_io_w_string(w, (SANE_String *) &v->name); + xsane_rc_io_w_string(w, (SANE_String *) &v->vendor); + xsane_rc_io_w_string(w, (SANE_String *) &v->model); + xsane_rc_io_w_string(w, (SANE_String *) &v->type); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_device_ptr(Wire *w, SANE_Device **v) +{ + xsane_rc_io_w_ptr(w, (void **) v, (WireCodecFunc) xsane_rc_io_w_device, sizeof (**v)); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_option_descriptor(Wire *w, SANE_Option_Descriptor *v) +{ + SANE_Word len; + + xsane_rc_io_w_string(w, (SANE_String *) &v->name); + xsane_rc_io_w_string(w, (SANE_String *) &v->title); + xsane_rc_io_w_string(w, (SANE_String *) &v->desc); + xsane_rc_io_w_value_type(w, &v->type); + xsane_rc_io_w_unit(w, &v->unit); + xsane_rc_io_w_word(w, &v->size); + xsane_rc_io_w_word(w, &v->cap); + xsane_rc_io_w_constraint_type(w, &v->constraint_type); + + switch (v->constraint_type) + { + case SANE_CONSTRAINT_NONE: + break; + + case SANE_CONSTRAINT_RANGE: + xsane_rc_io_w_ptr(w, (void **) &v->constraint.range, (WireCodecFunc) xsane_rc_io_w_range, sizeof (SANE_Range)); + break; + + case SANE_CONSTRAINT_WORD_LIST: + if (w->direction == WIRE_ENCODE) + 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)); + break; + + case SANE_CONSTRAINT_STRING_LIST: + if (w->direction == WIRE_ENCODE) + { + 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)); + break; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_option_descriptor_ptr(Wire *w, SANE_Option_Descriptor **v) +{ + xsane_rc_io_w_ptr(w, (void **) v, (WireCodecFunc) xsane_rc_io_w_option_descriptor, sizeof (**v)); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_parameters(Wire *w, SANE_Parameters *v) +{ + xsane_rc_io_w_frame(w, &v->format); + xsane_rc_io_w_bool(w, &v->last_frame); + xsane_rc_io_w_word(w, &v->bytes_per_line); + xsane_rc_io_w_word(w, &v->pixels_per_line); + xsane_rc_io_w_word(w, &v->lines); + xsane_rc_io_w_word(w, &v->depth); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_flush(Wire *w) +{ + w->status = 0; + + if (w->direction == WIRE_ENCODE) + { + xsane_rc_io_w_space(w, w->buffer.size + 1); + } + else if (w->direction == WIRE_DECODE) + { + w->buffer.curr = w->buffer.end = w->buffer.start; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_set_dir(Wire *w, WireDirection dir) +{ + xsane_rc_io_w_flush(w); + w->direction = dir; + xsane_rc_io_w_flush(w); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_call(Wire *w, SANE_Word procnum, WireCodecFunc w_arg, void *arg, WireCodecFunc w_reply, void *reply) +{ + w->status = 0; + xsane_rc_io_w_set_dir(w, WIRE_ENCODE); + + xsane_rc_io_w_word(w, &procnum); + (*w_arg) (w, arg); + + if (w->status == 0) + { + xsane_rc_io_w_set_dir(w, WIRE_DECODE); + (*w_reply) (w, reply); + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_reply(Wire *w, WireCodecFunc w_reply, void *reply) +{ + w->status = 0; + xsane_rc_io_w_set_dir(w, WIRE_ENCODE); + (*w_reply) (w, reply); + xsane_rc_io_w_flush(w); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_free(Wire *w, WireCodecFunc w_reply, void *reply) +{ + WireDirection saved_dir = w->direction; + + w->direction = WIRE_FREE; + (*w_reply) (w, reply); + w->direction = saved_dir; +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_init(Wire *w) +{ + w->status = 0; + w->direction = WIRE_ENCODE; + w->buffer.size = 8192; + w->buffer.start = malloc(w->buffer.size); + + if (w->buffer.start == 0) /* Malloc failed, so return an error. */ + { + w->status = ENOMEM; + } + + w->buffer.curr = w->buffer.start; + w->buffer.end = w->buffer.start + w->buffer.size; +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +static const char *hexdigit = "0123456789abcdef"; + +/* ---------------------------------------------------------------------------------------------------------------- */ + +static void xsane_rc_io_skip_ws(Wire *w) +{ + while (1) + { + xsane_rc_io_w_space(w, 1); + + if (w->status != 0) + { + return; + } + + if (!isspace(*w->buffer.curr)) + { + return; + } + + ++w->buffer.curr; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_skip_newline(Wire *w) +{ + while (*w->buffer.curr != 10) + { + xsane_rc_io_w_space(w, 1); + + if (w->status != 0) + { + return; + } + ++w->buffer.curr; + } + ++w->buffer.curr; +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +static unsigned xsane_rc_io_get_digit(Wire *w) +{ + unsigned digit; + + xsane_rc_io_w_space(w, 1); + digit = tolower(*w->buffer.curr++) - '0'; + + if (digit > 9) + { + digit -= 'a' - ('9' + 1); + } + + if (digit > 0xf) + { + w->status = EINVAL; + return 0; + } + return digit; +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +static SANE_Byte xsane_rc_io_get_byte(Wire *w) +{ + return xsane_rc_io_get_digit(w) << 4 | xsane_rc_io_get_digit(w); +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_byte(Wire *w, SANE_Byte *v) +{ + SANE_Byte *b = v; + + switch (w->direction) + { + case WIRE_ENCODE: + xsane_rc_io_w_space(w, 3); + *w->buffer.curr++ = hexdigit[(*b >> 4) & 0x0f]; + *w->buffer.curr++ = hexdigit[(*b >> 0) & 0x0f]; + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + xsane_rc_io_skip_ws(w); + *b = xsane_rc_io_get_byte(w); + break; + + case WIRE_FREE: + break; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_char(Wire *w, SANE_Char *v) +{ + SANE_Char *c = v; + + switch (w->direction) + { + case WIRE_ENCODE: + xsane_rc_io_w_space(w, 5); + *w->buffer.curr++ = '\''; + + if (*c == '\'' || *c == '\\') + { + *w->buffer.curr++ = '\\'; + } + + *w->buffer.curr++ = *c; + *w->buffer.curr++ = '\''; + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + xsane_rc_io_w_space(w, 4); + if (*w->buffer.curr++ != '\'') + { + w->status = EINVAL; + return; + } + *c = *w->buffer.curr++; + + if (*c == '\\') + { + xsane_rc_io_w_space(w, 2); + *c = *w->buffer.curr++; + } + + if (*w->buffer.curr++ != '\'') + { + w->status = EINVAL; + return; + } + break; + + case WIRE_FREE: + break; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_string(Wire *w, SANE_String *s) +{ + size_t len, alloced_len; + char * str, ch; + int done; + + switch (w->direction) + { + case WIRE_ENCODE: + if (*s) + { + xsane_rc_io_w_space(w, 1); + *w->buffer.curr++ = '"'; + str = *s; + while ((ch = *str++)) + { + xsane_rc_io_w_space(w, 2); + if (ch == '"' || ch == '\\') + { + *w->buffer.curr++ = '\\'; + } + *w->buffer.curr++ = ch; + } + *w->buffer.curr++ = '"'; + } + else + { + xsane_rc_io_w_space(w, 5); + *w->buffer.curr++ = '('; + *w->buffer.curr++ = 'n'; + *w->buffer.curr++ = 'i'; + *w->buffer.curr++ = 'l'; + *w->buffer.curr++ = ')'; + } + + xsane_rc_io_w_space(w, 1); + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + xsane_rc_io_skip_ws(w); + xsane_rc_io_w_space(w, 1); + + if (w->status != 0) + { + *s = 0; /* make sure pointer does not point to an invalid address */ + return; + } + + ch = *w->buffer.curr++; + if (ch == '"') + { + alloced_len = len = 0; + str = 0; + done = 0; + + do + { + xsane_rc_io_w_space(w, 1); + + if (w->status != 0) + { + return; + } + + ch = *w->buffer.curr++; + if (ch == '"') + { + done = 1; + } + + if (ch == '\\') + { + xsane_rc_io_w_space(w, 1); + ch = *w->buffer.curr++; + } + + if (len >= alloced_len) + { + alloced_len += 1024; + if (!str) + { + str = malloc(alloced_len); + } + else + { + str = realloc(str, alloced_len); + } + + if (str == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + str[len++] = ch; + } + while(!done); + + str[len - 1] = '\0'; + *s = realloc(str, len); + + if (*s == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + else if (ch == '(') + { + *s = 0; /* make sure pointer does not point to an invalid address */ + xsane_rc_io_w_space(w, 4); + if ( *w->buffer.curr++ != 'n' + || *w->buffer.curr++ != 'i' + || *w->buffer.curr++ != 'l' + || *w->buffer.curr++ != ')') + { + w->status = EINVAL; + return; + } + } + else + { + w->status = EINVAL; + *s = 0; /* make sure pointer does not point to an invalid address */ + return; + } + break; + + case WIRE_FREE: + if (*s) + { + free(*s); + } + break; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_io_w_word(Wire *w, SANE_Word *v) +{ + SANE_Word val, *word = v; + int i, is_negative = 0; + char buf[16]; + + switch (w->direction) + { + case WIRE_ENCODE: + val = *word; + i = sizeof(buf) - 1; + + if (val < 0) + { + is_negative = 1; + val = -val; + } + + do + { + buf[i--] = '0' + (val % 10); + val /= 10; + } + while (val); + + if (is_negative) + { + buf[i--] = '-'; + } + + xsane_rc_io_w_space(w, sizeof(buf) - i); + memcpy(w->buffer.curr, buf + i + 1, sizeof(buf) - i - 1); + w->buffer.curr += sizeof(buf) - i - 1; + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + xsane_rc_io_skip_ws(w); + val = 0; + xsane_rc_io_w_space(w, 1); + if (*w->buffer.curr == '-') + { + is_negative = 1; + ++w->buffer.curr; + } + + while (1) + { + xsane_rc_io_w_space(w, 1); + + if (w->status != 0) + { + return; + } + + if (!isdigit (*w->buffer.curr)) + { + break; + } + + val = 10*val + (*w->buffer.curr++ - '0'); + } + *word = is_negative ? -val : val; + break; + + case WIRE_FREE: + break; + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +#define PFIELD(p,offset,type) (*((type *)(((char *)(p)) + (offset)))) + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_pref_string(Wire *w, void *p, long offset) +{ + SANE_String string; + + if (w->direction == WIRE_ENCODE) + { + string = PFIELD(p, offset, char *); + } + + xsane_rc_io_w_string(w, &string); + + if (w->direction == WIRE_DECODE) + { + if (w->status == 0) + { + const char **field; + + field = &PFIELD(p, offset, const char *); + if (*field) + { + free((char *) *field); + } + *field = string ? strdup (string) : 0; + } + xsane_rc_io_w_free(w, (WireCodecFunc) xsane_rc_io_w_string, &string); + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_pref_double(Wire *w, void *p, long offset) +{ + SANE_Word word; + + if (w->direction == WIRE_ENCODE) + { + word = SANE_FIX(PFIELD (p, offset, double)); + } + + xsane_rc_io_w_word (w, &word); + + if (w->direction == WIRE_DECODE) + { + if (w->status == 0) + { + PFIELD(p, offset, double) = SANE_UNFIX (word); + } + xsane_rc_io_w_free(w, (WireCodecFunc) xsane_rc_io_w_word, &word); + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ + +void xsane_rc_pref_int(Wire *w, void *p, long offset) +{ + SANE_Word word; + + if (w->direction == WIRE_ENCODE) + { + word = PFIELD(p, offset, int); + } + + xsane_rc_io_w_word (w, &word); + + if (w->direction == WIRE_DECODE) + { + if (w->status == 0) + { + PFIELD(p, offset, int) = word; + } + xsane_rc_io_w_free(w, (WireCodecFunc) xsane_rc_io_w_word, &word); + } +} + +/* ---------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-rc-io.h b/frontend/xsane-rc-io.h new file mode 100644 index 0000000..6fd5680 --- /dev/null +++ b/frontend/xsane-rc-io.h @@ -0,0 +1,123 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-rc-io.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ---------------------------------------------------------------------------------------------------------------- */ + +#ifndef xsane_rc_io_h +#define xsane_rc_io_h + +#include <sys/types.h> + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#define XSANE_EOF -1 + +/* ---------------------------------------------------------------------------------------------------------------- */ + +typedef enum + { + WIRE_ENCODE = 0, + WIRE_DECODE, + WIRE_FREE + } +WireDirection; + +/* ---------------------------------------------------------------------------------------------------------------- */ + +struct Wire; + +/* ---------------------------------------------------------------------------------------------------------------- */ + +typedef void (*WireCodecFunc) (struct Wire *w, void *val_ptr); +typedef ssize_t (*WireReadFunc) (int fd, void * buf, size_t len); +typedef ssize_t (*WireWriteFunc) (int fd, const void * buf, size_t len); + +/* ---------------------------------------------------------------------------------------------------------------- */ + +typedef struct Wire + { + int version; /* protocol version in use */ + WireDirection direction; + int status; + struct + { + WireCodecFunc w_byte; + WireCodecFunc w_char; + WireCodecFunc w_word; + WireCodecFunc w_string; + } + codec; + struct + { + size_t size; + char *curr; + char *start; + char *end; + } + buffer; + struct + { + int fd; + WireReadFunc read; + WireWriteFunc write; + } + io; + } +Wire; + +/* ---------------------------------------------------------------------------------------------------------------- */ + +extern void xsane_rc_io_w_init(Wire *w); +extern void xsane_rc_io_w_space(Wire *w, size_t howmuch); +extern void xsane_rc_io_w_skip_newline(Wire *w); +extern void xsane_rc_io_w_void(Wire *w); +extern void xsane_rc_io_w_byte(Wire *w, SANE_Byte *v); +extern void xsane_rc_io_w_char(Wire *w, SANE_Char *v); +extern void xsane_rc_io_w_word(Wire *w, SANE_Word *v); +extern void xsane_rc_io_w_string(Wire *w, SANE_String *v); +extern void xsane_rc_io_w_status(Wire *w, SANE_Status *v); +extern void xsane_rc_io_w_constraint_type(Wire *w, SANE_Constraint_Type *v); +extern void xsane_rc_io_w_value_type(Wire *w, SANE_Value_Type *v); +extern void xsane_rc_io_w_unit(Wire *w, SANE_Unit *v); +extern void xsane_rc_io_w_action(Wire *w, SANE_Action *v); +extern void xsane_rc_io_w_frame(Wire *w, SANE_Frame *v); +extern void xsane_rc_io_w_range(Wire *w, SANE_Range *v); +extern void xsane_rc_io_w_range_ptr(Wire *w, SANE_Range **v); +extern void xsane_rc_io_w_device(Wire *w, SANE_Device *v); +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_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); +extern void xsane_rc_io_w_reply(Wire *w, WireCodecFunc w_reply, void *reply); +extern void xsane_rc_io_w_free(Wire *w, WireCodecFunc w_reply, void *reply); + +extern void xsane_rc_pref_string(Wire *w, void *p, long offset); +extern void xsane_rc_pref_double(Wire *w, void *p, long offset); +extern void xsane_rc_pref_int(Wire *w, void *p, long offset); + +/* ---------------------------------------------------------------------------------------------------------------- */ + +#endif /* xsane_rc_io_wire_h */ diff --git a/frontend/xsane-save.c b/frontend/xsane-save.c new file mode 100644 index 0000000..d9ac69a --- /dev/null +++ b/frontend/xsane-save.c @@ -0,0 +1,975 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-save.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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-preview.h" +#include "xsane-back-gtk.h" +#include "xsane-front-gtk.h" +#include "xsane-text.h" + +#ifdef HAVE_LIBJPEG +#include <jpeglib.h> +#endif + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ +#include <png.h> +#include <zlib.h> +#endif +#endif + +#ifdef HAVE_LIBTIFF +#include <tiffio.h> +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int cancel_save; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_cancel_save() +{ + cancel_save = 1; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_convert_text_to_filename(char **text) +{ + 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); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_increase_counter_in_filename(char *filename, int skip) +{ + char *position_point; + char *position_counter; + char counter; + FILE *testfile; + + while (1) + { + position_point = strrchr(filename, '.'); + if (position_point) + { + position_counter = position_point-1; + } + else + { + position_counter = filename + strlen(filename) - 1; + } + + if (!( (*position_counter >= '0') && (*position_counter <='9') )) + { + break; /* no counter found */ + } + + while ( (position_counter > filename) && (*position_counter >= '0') && (*position_counter <='9') ) + { + counter = ++(*position_counter); + if (counter != ':') + { + break; + } + *position_counter = '0'; + position_counter--; + } + + if (!( (*position_counter >= '0') && (*position_counter <='9') )) /* overflow */ + { + xsane_back_gtk_warning(WARN_COUNTER_OVERFLOW, FALSE); + break; /* last available number ("999") */ + } + + if (skip) /* test if filename already used */ + { + testfile = fopen(filename, "r"); + if (testfile) /* filename used: skip */ + { + fclose(testfile); + } + else + { + break; /* filename not used, ok */ + } + } + else /* do not test if filename already used */ + { + break; /* filename ok */ + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_save_ps_create_header(FILE *outfile, int color, int bits, int pixel_width, int pixel_height, + int left, int bottom, float width, float height, + int paperwidth, int paperheight, int rotate) +{ + int degree, position_left, position_bottom, box_left, box_bottom, box_right, box_top; + + if (rotate) /* roatet with 90 degrees - eg for landscape mode */ + { + degree = 90; + position_left = left; + position_bottom = bottom - paperwidth; + box_left = paperwidth - bottom - height * 72.0; + box_bottom = left; + box_right = (int) (box_left + height * 72.0); + box_top = (int) (box_bottom + width * 72.0); + } + else /* do not rotate, eg for portrait mode */ + { + degree = 0; + position_left = left; + position_bottom = bottom; + box_left = left; + box_bottom = bottom; + box_right = (int) (box_left + width * 72.0); + box_top = (int) (box_bottom + height * 72.0); + } + + fprintf(outfile, "%%!PS-Adobe-2.0 EPSF-2.0\n"); + fprintf(outfile, "%%%%Creator: xsane version %s (sane %d.%d)\n", VERSION, + SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), + SANE_VERSION_MINOR(xsane.sane_backend_versioncode)); + fprintf(outfile, "%%%%BoundingBox: %d %d %d %d\n", box_left, box_bottom, box_right, box_top); + fprintf(outfile, "%%\n"); + fprintf(outfile, "/origstate save def\n"); + fprintf(outfile, "20 dict begin\n"); + + if (bits == 1) + { + fprintf(outfile, "/pix %d string def\n", (pixel_width+7)/8); + fprintf(outfile, "/grays %d string def\n", pixel_width); + fprintf(outfile, "/npixels 0 def\n"); + fprintf(outfile, "/rgbindx 0 def\n"); + } + else + { + fprintf(outfile, "/pix %d string def\n", pixel_width); + } + + + fprintf(outfile, "%d rotate\n", degree); + fprintf(outfile, "%d %d translate\n", position_left, position_bottom); + fprintf(outfile, "%f %f scale\n", width * 72.0, height * 72.0); + fprintf(outfile, "%d %d %d\n", pixel_width, pixel_height, bits); + fprintf(outfile, "[%d %d %d %d %d %d]\n", pixel_width, 0, 0, -pixel_height, 0 , pixel_height); + fprintf(outfile, "{currentfile pix readhexstring pop}\n"); + + if (color) + { + fprintf(outfile, "false 3 colorimage\n"); + fprintf(outfile, "\n"); + } + else + { + fprintf(outfile, "image\n"); + fprintf(outfile, "\n"); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_save_ps_bw(FILE *outfile, FILE *imagefile, int pixel_width, int pixel_height) +{ + int x, y, count; + int bytes_per_line = (pixel_width+7)/8; + + cancel_save = 0; + + count = 0; + for (y = 0; y < pixel_height; y++) + { + for (x = 0; x < bytes_per_line; x++) + { + fprintf(outfile, "%02x", (fgetc(imagefile) ^ 255)); + if (++count >= 40) + { + fprintf(outfile, "\n"); + count = 0; + } + } + fprintf(outfile, "\n"); + count = 0; + xsane_progress_update(xsane.progress, (float)y/pixel_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + if (cancel_save) + { + break; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_save_ps_gray(FILE *outfile, FILE *imagefile, int pixel_width, int pixel_height) +{ + int x, y, count; + + cancel_save = 0; + + count = 0; + for (y=0; y<pixel_height; y++) + { + for (x=0; x<pixel_width; x++) + { + fprintf(outfile, "%02x", fgetc(imagefile)); + if (++count >=40) + { + fprintf(outfile, "\n"); + count = 0; + } + } + fprintf(outfile, "\n"); + count = 0; + xsane_progress_update(xsane.progress, (float)y/pixel_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + if (cancel_save) + { + break; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_save_ps_color(FILE *outfile, FILE *imagefile, int pixel_width, int pixel_height) +{ + int x, y, count; + + cancel_save = 0; + + count = 0; + for (y=0; y<pixel_height; y++) + { + for (x=0; x<pixel_width; x++) + { + fprintf(outfile, "%02x", fgetc(imagefile)); + fprintf(outfile, "%02x", fgetc(imagefile)); + fprintf(outfile, "%02x", fgetc(imagefile)); + if (++count >=10) + { + fprintf(outfile, "\n"); + count = 0; + } + } + fprintf(outfile, "\n"); + count = 0; + + xsane_progress_update(xsane.progress, (float)y/pixel_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + if (cancel_save) + { + break; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_ps(FILE *outfile, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int left, int bottom, + float width, float height, + int paperheight, int paperwidth, int rotate) +{ + xsane_save_ps_create_header(outfile, color, bits, pixel_width, pixel_height, + left, bottom, width, height, paperheight, paperwidth, rotate); + + if (color == 0) /* lineart, halftone, grayscale */ + { + if (bits == 1) /* lineart, halftone */ + { + xsane_save_ps_bw(outfile, imagefile, pixel_width, pixel_height); + } + else /* grayscale */ + { + xsane_save_ps_gray(outfile, imagefile, pixel_width, pixel_height); + } + } + else /* color */ + { + xsane_save_ps_color(outfile, imagefile, pixel_width, pixel_height); + } + + fprintf(outfile, "\n"); + fprintf(outfile, "showpage\n"); + fprintf(outfile, "end\n"); + fprintf(outfile, "origstate restore\n"); + fprintf(outfile, "\n"); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBJPEG +void xsane_save_jpeg(FILE *outfile, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int quality) +{ + char *data; + char buf[256]; + int x,y; + int components = 1; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPROW row_pointer[1]; + + cancel_save = 0; + + if (color) + { + components = 3; + } + + data = malloc(pixel_width * components); + + if (!data) + { + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return; + } + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, outfile); + cinfo.image_width = pixel_width; + cinfo.image_height = pixel_height; + cinfo.input_components = components; + if (color) + { + cinfo.in_color_space = JCS_RGB; + } + else + { + cinfo.in_color_space = JCS_GRAYSCALE; + } + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + for (y=0; y<pixel_height; y++) + { + xsane_progress_update(xsane.progress, (float)y/pixel_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (bits == 1) + { + int byte = 0; + int mask = 128; + + for (x = 0; x < pixel_width; x++) + { + + if ( (x % 8) == 0) + { + byte = fgetc(imagefile); + mask = 128; + } + + if (byte & mask) + { + data[x] = 0; + } + else + { + data[x] = 255; + } + mask >>= 1; + } + } + else + { + fread(data, components, pixel_width, imagefile); + } + row_pointer[0] = data; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + if (cancel_save) + { + break; + } + } + + jpeg_finish_compress(&cinfo); + free(data); +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBTIFF +void xsane_save_tiff(const char *outfilename, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int compression, int quality) +{ + TIFF *tiffile; + char *data; + char buf[256]; + int y, w; + int components; + + cancel_save = 0; + + if (color) + { + components = 3; + } + else + { + components = 1; + } + + tiffile = TIFFOpen(outfilename, "w"); + if (!tiffile) + { + snprintf(buf, sizeof(buf), "%s %s %s\n",ERR_DURING_SAVE, ERR_OPEN_FAILED, outfilename); + xsane_back_gtk_error(buf, TRUE); + return; + } + + data = malloc(pixel_width * components); + + if (!data) + { + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); + xsane_back_gtk_error(buf, TRUE); + return; + } + + TIFFSetField(tiffile, TIFFTAG_IMAGEWIDTH, pixel_width); + TIFFSetField(tiffile, TIFFTAG_IMAGELENGTH, pixel_height); + TIFFSetField(tiffile, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tiffile, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tiffile, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tiffile, TIFFTAG_COMPRESSION, compression); + TIFFSetField(tiffile, TIFFTAG_SAMPLESPERPIXEL, components); + TIFFSetField(tiffile, TIFFTAG_SOFTWARE, "xsane"); +#if 0 + TIFFSetField(tiffile, TIFFTAG_DATATIME, "0.0.1900,0:0:00"); + TIFFSetField(tiffile, TIFFTAG_XRESOLUTION, 100); + TIFFSetField(tiffile, TIFFTAG_YRESOLUTION, 100); +#endif + + if (compression == COMPRESSION_JPEG) + { + TIFFSetField(tiffile, TIFFTAG_JPEGQUALITY, quality); + } + + if (color) + { + TIFFSetField(tiffile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + } + else + { + if (bits == 1) /* lineart */ + { + TIFFSetField(tiffile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); + } + else /* grayscale */ + { + TIFFSetField(tiffile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + } + } + + TIFFSetField(tiffile, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tiffile, -1)); + + w = TIFFScanlineSize(tiffile); + + for (y = 0; y < pixel_height; y++) + { + xsane_progress_update(xsane.progress, (float) y / pixel_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + fread(data, 1, w, imagefile); + + TIFFWriteScanline(tiffile, data, y, 0); + + if (cancel_save) + { + break; + } + } + + TIFFClose(tiffile); + free(data); +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ +void xsane_save_png(FILE *outfile, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int compression) +{ + png_structp png_ptr; + png_infop png_info_ptr; + png_bytep row_ptr; + png_color_8 sig_bit; + char *data; + char buf[256]; + int colortype, components, byte_width; + int y; + + 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_LIBTIFF); + xsane_back_gtk_error(buf, TRUE); + return; + } + + 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; + } + + 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; + } + + byte_width = pixel_width; + + if (color == 4) /* RGBA */ + { + components = 4; + colortype = PNG_COLOR_TYPE_RGB_ALPHA; + } + else if (color) /* 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, pixel_width, pixel_height, bits, + colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + if (color >=3) + { + sig_bit.red = bits; + sig_bit.green = bits; + sig_bit.blue = bits; + + if (color ==4) + { + sig_bit.alpha = bits; + } + + } + else + { + sig_bit.gray = bits; + + if (bits == 1) + { + byte_width = pixel_width/8; + png_set_invert_mono(png_ptr); + } + } + + 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); + + data = malloc(pixel_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; + } + + for (y = 0; y < pixel_height; y++) + { + xsane_progress_update(xsane.progress, (float) y / pixel_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); + if (cancel_save) + { + break; + } + } + + free(data); + png_write_end(png_ptr, png_info_ptr); + png_destroy_write_struct(&png_ptr, (png_infopp) 0); + +} +#endif +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ +void xsane_save_png_16(FILE *outfile, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int compression) +{ + 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 */ + char *data; + char buf[256]; + int colortype, components; + int x,y; + guint16 val; + + 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; + } + + 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; + } + + 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; + } + + if (color == 4) /* RGBA */ + { + components = 4; + colortype = PNG_COLOR_TYPE_RGB_ALPHA; + } + else if (color) /* 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, pixel_width, pixel_height, 16, + colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + sig_bit.red = bits; + sig_bit.green = bits; + sig_bit.blue = bits; + sig_bit.alpha = bits; + sig_bit.gray = bits; + + 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(pixel_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; + } + + for (y = 0; y < pixel_height; y++) + { + xsane_progress_update(xsane.progress, (float)y/pixel_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + for (x = 0; x < pixel_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); +} +#endif +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_pnm_16_gray(FILE *outfile, FILE *imagefile, int bits, int pixel_width, int pixel_height) +{ + int x,y; + guint16 val; + int count = 0; + + cancel_save = 0; + + /* write pgm ascii > 8 bpp */ + fprintf(outfile, "P2\n# SANE data follows\n%d %d\n65535\n", pixel_width, pixel_height); + + for (y=0; y<pixel_height; y++) + { + for (x=0; x<pixel_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"); + count = 0; + + xsane_progress_update(xsane.progress, (float)y/pixel_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + if (cancel_save) + { + break; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_pnm_16_color(FILE *outfile, FILE *imagefile, int bits, int pixel_width, int pixel_height) +{ + int x,y; + guint16 val; + int count = 0; + + cancel_save = 0; + + /* write ppm ascii > 8 bpp */ + fprintf(outfile, "P3\n# SANE data follows\n%d %d\n65535\n", pixel_width, pixel_height); + + for (y=0; y<pixel_height; y++) + { + for (x=0; x<pixel_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"); + count = 0; + + xsane_progress_update(xsane.progress, (float)y/pixel_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + if (cancel_save) + { + break; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_pnm_16(FILE *outfile, FILE *imagefile, int color, int bits, int pixel_width, int pixel_height) +{ + if (color) + { + xsane_save_pnm_16_color(outfile, imagefile, bits, pixel_width, pixel_height); + } + else + { + xsane_save_pnm_16_gray(outfile, imagefile, bits, pixel_width, pixel_height); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-save.h b/frontend/xsane-save.h new file mode 100644 index 0000000..7ac856c --- /dev/null +++ b/frontend/xsane-save.h @@ -0,0 +1,79 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-save.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_cancel_save(); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_convert_text_to_filename(char **filename); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + + +void xsane_increase_counter_in_filename(char *filename, int skip); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_ps(FILE *outfile, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int left, int bottom, + float width, float height, + int paperwidth, int paperheight, int landscape); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_jpeg(FILE *outfile, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int quality); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_tiff(const char *outfilename, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int compression, int quality); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_png(FILE *outfile, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int compression); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_png_16(FILE *outfile, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height, + int compression); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_save_pnm_16(FILE *outfile, FILE *imagefile, + int color, int bits, + int pixel_width, int pixel_height); + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-scan.c b/frontend/xsane-scan.c new file mode 100644 index 0000000..d66ab28 --- /dev/null +++ b/frontend/xsane-scan.c @@ -0,0 +1,2369 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-scan.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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 "xsane-preferences.h" +#include "xsane-preview.h" +#include "xsane-save.h" +#include "xsane-text.h" +#include "xsane-gamma.h" +#include "xsane-setup.h" + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ +#include <png.h> +#include <zlib.h> +#endif +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBGIMP_GIMP_H + +#include <libgimp/gimp.h> + +static void xsane_gimp_query(void); +static void xsane_gimp_run(char *name, int nparams, GParam * param, int *nreturn_vals, GParam ** return_vals); + +GPlugInInfo PLUG_IN_INFO = +{ + NULL, /* init_proc */ + NULL, /* quit_proc */ + xsane_gimp_query, /* query_proc */ + xsane_gimp_run, /* run_proc */ +}; + +#endif /* HAVE_LIBGIMP_GIMP_H */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* forward declarations: */ + +static int xsane_generate_dummy_filename(); +#ifdef HAVE_LIBGIMP_GIMP_H +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); +static void xsane_gimp_advance(void); +#endif +static void xsane_read_image_data(gpointer data, gint source, GdkInputCondition cond); +static RETSIGTYPE xsane_sigpipe_handler(int signal); +static int xsane_test_multi_scan(void); +void xsane_scan_done(SANE_Status status); +void xsane_cancel(void); +static void xsane_start_scan(void); +void xsane_scan_dialog(GtkWidget * widget, gpointer call_data); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_generate_dummy_filename() +{ + /* returns TRUE if file is a temporary file */ + + if (xsane.dummy_filename) + { + free(xsane.dummy_filename); + } + + if ( (xsane.xsane_mode == XSANE_COPY) || (xsane.xsane_mode == XSANE_FAX) || /* we have to do a conversion */ + ( (xsane.xsane_mode == XSANE_SCAN) && (xsane.xsane_output_format != XSANE_PNM) && + (xsane.xsane_output_format != XSANE_RAW16) && (xsane.xsane_output_format != XSANE_RGBA) ) ) + { + char filename[PATH_MAX]; + + xsane_back_gtk_make_path(sizeof(filename), filename, 0, 0, "conversion-", dialog->dev_name, ".ppm", XSANE_PATH_TMP); + xsane.dummy_filename = strdup(filename); + return TRUE; + } + else /* no conversion following, save directly to the selected filename */ + { + xsane.dummy_filename = strdup(xsane.output_filename); + return FALSE; + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBGIMP_GIMP_H +static int xsane_decode_devname(const char *encoded_devname, int n, char *buf) +{ + char *dst, *limit; + const char *src; + char ch, val; + + 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; + + 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 GParamDef args[] = + { + {PARAM_INT32, "run_mode", "Interactive, non-interactive"}, + }; + static GParamDef *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; + + snprintf(name, sizeof(name), "%s", 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", */ + PROC_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) + { + fprintf(stderr, "\n\n" + "%s %s:\n" + " %s\n" + " %s %d\n" + " %s %d\n" + "%s\n\n", + 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(&devlist, SANE_FALSE); + + for (i = 0; devlist[i]; ++i) + { + snprintf(name, sizeof(name), "%s-", prog_name); + if (xsane_encode_devname(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; devlist[i]->name[j]; ++j) + { + if (devlist[i]->name[j] == '/') + mpath[len++] = '\''; + else + mpath[len++] = 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, + "RGB, GRAY", + PROC_EXTENSION, + nargs, nreturn_vals, + args, return_vals); + } + sane_exit(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_gimp_run(char *name, int nparams, GParam * param, int *nreturn_vals, GParam ** return_vals) +{ + static GParam values[2]; + GRunModeType run_mode; + char devname[1024]; + char *args[2]; + int nargs; + + run_mode = param[0].data.d_int32; + xsane.mode = XSANE_GIMP_EXTENSION; + + *nreturn_vals = 1; + *return_vals = values; + + values[0].type = PARAM_STATUS; + values[0].data.d_status = STATUS_CALLING_ERROR; + + nargs = 0; + args[nargs++] = "xsane"; + + seldev = -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 RUN_INTERACTIVE: + xsane_interface(nargs, args); + values[0].data.d_status = STATUS_SUCCESS; + break; + + case RUN_NONINTERACTIVE: + /* Make sure all the arguments are there! */ + break; + + case RUN_WITH_LAST_VALS: + /* Possibly retrieve data */ + break; + + default: + break; + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void null_print_func(gchar *msg) +{ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_gimp_advance(void) +{ + if (++xsane.x >= xsane.param.pixels_per_line) + { + int tile_height = gimp_tile_height(); + + xsane.x = 0; + ++xsane.y; + if (xsane.y % tile_height == 0) + { + gimp_pixel_rgn_set_rect(&xsane.region, xsane.tile, 0, xsane.y - tile_height, xsane.param.pixels_per_line, tile_height); + if (xsane.param.format >= SANE_FRAME_RED && xsane.param.format <= SANE_FRAME_BLUE) + { + int height; + + xsane.tile_offset %= 3; + + if (!xsane.first_frame) /* get the data for the existing tile: */ + { + height = tile_height; + + if (xsane.y + height >= xsane.param.lines) + { + height = xsane.param.lines - xsane.y; + } + + gimp_pixel_rgn_get_rect(&xsane.region, xsane.tile, 0, xsane.y, xsane.param.pixels_per_line, height); + } + } + else + { + xsane.tile_offset = 0; + } + } + } +} + +#endif /* HAVE_LIBGIMP_GIMP_H */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_read_image_data(gpointer data, gint source, GdkInputCondition cond) +{ + SANE_Handle dev = xsane_back_gtk_dialog_get_device (dialog); + SANE_Status status; + SANE_Int len; + int i; + char buf[255]; + + if ( (xsane.param.depth == 1) || (xsane.param.depth == 8) ) + { + static unsigned char buf8[32768]; + + while (1) + { + status = sane_read(dev, (SANE_Byte *) buf8, sizeof(buf8), &len); + if (status == SANE_STATUS_EOF) + { + if (!xsane.param.last_frame) + { + xsane_start_scan(); + break; /* leave while loop */ + } + + xsane_scan_done(SANE_STATUS_EOF); /* image complete, stop scanning */ + return; + } + + if (status != SANE_STATUS_GOOD) + { + xsane_scan_done(status); /* status = return of sane_read */ + snprintf(buf, sizeof(buf), "%s %s.", ERR_DURING_READ, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, TRUE); + return; + } + + if (!len) + { + break; /* out of data for now, leave while loop */ + } + + xsane.bytes_read += len; + xsane_progress_update(xsane.progress, xsane.bytes_read / (gfloat) xsane.num_bytes); + + if (xsane.input_tag < 0) + { + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + } + + switch (xsane.param.format) + { + case SANE_FRAME_GRAY: + if (xsane.mode == XSANE_STANDALONE) + { + int i; + char val; + + if ((!xsane.scanner_gamma_gray) && (xsane.param.depth > 1)) + { + for (i=0; i < len; ++i) + { + val = xsane.gamma_data[(int) buf8[i]]; + fwrite(&val, 1, 1, xsane.out); + } + } + else + { + fwrite(buf8, 1, len, xsane.out); + } + } +#ifdef HAVE_LIBGIMP_GIMP_H + else /* GIMP MODE GRAY 8 bit */ + { + switch (xsane.param.depth) + { + case 1: + for (i = 0; i < len; ++i) + { + u_char mask; + int j; + + mask = buf8[i]; + for (j = 7; j >= 0; --j) + { + u_char gl = (mask & (1 << j)) ? 0x00 : 0xff; + xsane.tile[xsane.tile_offset++] = gl; + xsane_gimp_advance(); + if (xsane.x == 0) + { + break; + } + } + } + break; + + case 8: + if (!xsane.scanner_gamma_gray) + { + for (i = 0; i < len; ++i) + { + xsane.tile[xsane.tile_offset++] = xsane.gamma_data[(int) buf8[i]]; + xsane_gimp_advance(); + } + } + else + { + for (i = 0; i < len; ++i) + { + xsane.tile[xsane.tile_offset++] = buf8[i]; + xsane_gimp_advance(); + } + } + break; + } + } +#endif /* HAVE_LIBGIMP_GIMP_H */ + break; + + case SANE_FRAME_RGB: + if (xsane.mode == XSANE_STANDALONE) + { + int i; + char val; + + if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ + { + for (i=0; i < len; ++i) + { + if (dialog->pixelcolor == 0) + { + val = xsane.gamma_data_red[(int) buf8[i]]; + dialog->pixelcolor++; + } + else if (dialog->pixelcolor == 1) + { + val = xsane.gamma_data_green[(int) buf8[i]]; + dialog->pixelcolor++; + } + else + { + val = xsane.gamma_data_blue[(int) buf8[i]]; + dialog->pixelcolor = 0; + } + fwrite(&val, 1, 1, xsane.out); + } + } + else /* gamma correction has been done by scanner */ + { + fwrite(buf8, 1, len, xsane.out); + } + } +#ifdef HAVE_LIBGIMP_GIMP_H + else /* GIMP MODE RGB 8 bit */ + { + switch (xsane.param.depth) + { + case 1: + if (xsane.param.format == SANE_FRAME_RGB) + { + goto bad_depth; + } + for (i = 0; i < len; ++i) + { + u_char mask; + int j; + + mask = buf8[i]; + for (j = 0; j < 8; ++j) + { + u_char gl = (mask & 1) ? 0xff : 0x00; + mask >>= 1; + xsane.tile[xsane.tile_offset++] = gl; + xsane_gimp_advance(); + if (xsane.x == 0) + break; + } + } + break; + + case 8: + if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ + { + for (i = 0; i < len; ++i) + { + if (xsane.tile_offset % 3 == 0) + { + xsane.tile[xsane.tile_offset++] = xsane.gamma_data_red[(int) buf8[i]]; + } + else if (xsane.tile_offset % 3 == 1) + { + xsane.tile[xsane.tile_offset++] = xsane.gamma_data_green[(int) buf8[i]]; + } + else + { + xsane.tile[xsane.tile_offset++] = xsane.gamma_data_blue[(int) buf8[i]]; + } + + if (xsane.tile_offset % 3 == 0) + { + xsane_gimp_advance(); + } + } + } + else /* gamma correction by scanner */ + { + for (i = 0; i < len; ++i) + { + xsane.tile[xsane.tile_offset++] = buf8[i]; + if (xsane.tile_offset % 3 == 0) + { + xsane_gimp_advance(); + } + } + } + break; + + default: + goto bad_depth; + break; + } + } +#endif /* HAVE_LIBGIMP_GIMP_H */ + break; + + case SANE_FRAME_RED: + case SANE_FRAME_GREEN: + case SANE_FRAME_BLUE: + if (xsane.mode == XSANE_STANDALONE) + { + if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ + { + char val; + SANE_Int *gamma; + + if (xsane.param.format == SANE_FRAME_RED) + { + gamma = xsane.gamma_data_red; + } + else if (xsane.param.format == SANE_FRAME_GREEN) + { + gamma = xsane.gamma_data_green; + } + else + { + gamma = xsane.gamma_data_blue; + } + + for (i = 0; i < len; ++i) + { + val = gamma[(int) buf8[i]]; + fwrite(&val, 1, 1, xsane.out); + fseek(xsane.out, 2, SEEK_CUR); + } + } + else /* gamma correction by scanner */ + { + for (i = 0; i < len; ++i) + { + fwrite(&buf8[i], 1, 1, xsane.out); + fseek(xsane.out, 2, SEEK_CUR); + } + } + } +#ifdef HAVE_LIBGIMP_GIMP_H + else /* GIMP MODE RED, GREEN, BLUE (3PASS) 8 bit */ + { + switch (xsane.param.depth) + { + case 1: + for (i = 0; i < len; ++i) + { + u_char mask; + int j; + + mask = buf8[i]; + for (j = 0; j < 8; ++j) + { + u_char gl = (mask & 1) ? 0xff : 0x00; + mask >>= 1; + xsane.tile[xsane.tile_offset] = gl; + xsane.tile_offset += 3; + xsane_gimp_advance(); + if (xsane.x == 0) + { + break; + } + } + } + break; + + case 8: + if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ + { + SANE_Int *gamma; + + if (xsane.param.format == SANE_FRAME_RED) + { + gamma = xsane.gamma_data_red; + } + else if (xsane.param.format == SANE_FRAME_GREEN) + { + gamma = xsane.gamma_data_green; + } + else + { + gamma = xsane.gamma_data_blue; + } + + for (i = 0; i < len; ++i) + { + xsane.tile[xsane.tile_offset] = gamma[(int) buf8[i]]; + xsane.tile_offset += 3; + xsane_gimp_advance(); + } + } + else /* gamma correction by scanner */ + { + for (i = 0; i < len; ++i) + { + xsane.tile[xsane.tile_offset] = buf8[i]; + xsane.tile_offset += 3; + xsane_gimp_advance(); + } + } + break; + + default: + goto bad_depth; + break; + } + } +#endif /* HAVE_LIBGIMP_GIMP_H */ + break; + +#ifdef SUPPORT_RGBA + case SANE_FRAME_RGBA: /* Scanning including Infrared channel */ + if (xsane.mode == XSANE_STANDALONE) + { + int i; + char val; + + if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ + { + for (i=0; i < len; ++i) + { + if (dialog->pixelcolor == 0) + { + val = xsane.gamma_data_red[(int) buf8[i]]; + dialog->pixelcolor++; + } + else if (dialog->pixelcolor == 1) + { + val = xsane.gamma_data_green[(int) buf8[i]]; + dialog->pixelcolor++; + } + else if (dialog->pixelcolor == 2) + { + val = xsane.gamma_data_blue[(int) buf8[i]]; + dialog->pixelcolor++; + } + else + { + val = buf8[i]; /* no gamma table for infrared channel */ + dialog->pixelcolor = 0; + } + fwrite(&val, 1, 1, xsane.out); + } + } + else /* gamma correction has been done by scanner */ + { + fwrite(buf8, 1, len, xsane.out); + } + } +#ifdef HAVE_LIBGIMP_GIMP_H + else /* GIMP MODE RGBA 8 bit */ + { + int i; + + + switch (xsane.param.depth) + { + case 8: + if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ + { + for (i=0; i < len; ++i) + { + if (xsane.tile_offset % 4 == 0) + { + xsane.tile[xsane.tile_offset++] = xsane.gamma_data_red[(int) buf8[i]]; + } + else if (xsane.tile_offset % 4 == 1) + { + xsane.tile[xsane.tile_offset++] = xsane.gamma_data_green[(int) buf8[i]]; + } + else if (xsane.tile_offset % 4 == 2) + { + xsane.tile[xsane.tile_offset++] = xsane.gamma_data_blue[(int) buf8[i]]; + } + else + { + xsane.tile[xsane.tile_offset++] = buf8[i]; /* no gamma table for infrared channel */ + } + + if (xsane.tile_offset % 4 == 0) + { + xsane_gimp_advance(); + } + } + } + else /* gamma correction has been done by scanner */ + { + for (i = 0; i < len; ++i) + { + xsane.tile[xsane.tile_offset++] = buf8[i]; + if (xsane.tile_offset % 4 == 0) + { + xsane_gimp_advance(); + } + } + } + break; + + default: + goto bad_depth; + break; + } + } +#endif /* HAVE_LIBGIMP_GIMP_H */ + break; +#endif + + default: + xsane_scan_done(-1); /* -1 = error */ + fprintf(stderr, "xsane_read_image_data: %s %d\n", ERR_BAD_FRAME_FORMAT, xsane.param.format); + return; + break; + } + } + } + else if ( xsane.param.depth == 16 ) + { + static guint16 buf16[32768]; + char buf[255]; + char last = 0; + int offset = 0; + + while (1) + { + if (offset) /* if we have had an odd number of bytes */ + { + buf16[0] = last; + status = sane_read(dev, (SANE_Byte *) (buf16 + 1), sizeof(buf16) - 1, &len); + if (len) + { + len++; + } + } + else /* last read we had an even number of bytes */ + { + status = sane_read(dev, (SANE_Byte *) buf16, sizeof(buf16), &len); + } + + if (len % 2) /* odd number of bytes */ + { + len--; + last = buf16[len]; + offset = 1; + } + else /* even number of bytes */ + { + offset = 0; + } + + if (status == SANE_STATUS_EOF) + { + if (!xsane.param.last_frame) + { + xsane_start_scan(); + break; /* leave while loop */ + } + + xsane_scan_done(SANE_STATUS_EOF); /* image complete, stop scanning */ + return; + } + + if (status != SANE_STATUS_GOOD) + { + xsane_scan_done(status); /* status = return of sane_read */ + snprintf(buf, sizeof(buf), "%s %s.", ERR_DURING_READ, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, TRUE); + return; + } + + if (!len) /* nothing read */ + { + break; /* out of data for now, leave while loop */ + } + + xsane.bytes_read += len; + xsane_progress_update(xsane.progress, xsane.bytes_read / (gfloat) xsane.num_bytes); + + if (xsane.input_tag < 0) + { + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + } + + switch (xsane.param.format) + { + case SANE_FRAME_GRAY: + if (xsane.mode == XSANE_STANDALONE) + { + int i; + guint16 val; + + if (!xsane.scanner_gamma_gray) /* gamma correction by xsane */ + { + for (i=0; i < len/2; ++i) + { + val = xsane.gamma_data[buf16[i]]; + fwrite(&val, 2, 1, xsane.out); + } + } + else /* gamma correction by scanner */ + { + fwrite(buf16, 2, len/2, xsane.out); + } + } + break; + + case SANE_FRAME_RGB: + if (xsane.mode == XSANE_STANDALONE) + { + int i; + guint16 val; + + if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ + { + for (i=0; i < len/2; ++i) + { + if (dialog->pixelcolor == 0) + { + val = xsane.gamma_data_red[buf16[i]]; + dialog->pixelcolor++; + } + else if (dialog->pixelcolor == 1) + { + val = xsane.gamma_data_green[buf16[i]]; + dialog->pixelcolor++; + } + else + { + val = xsane.gamma_data_blue[buf16[i]]; + dialog->pixelcolor = 0; + } + fwrite(&val, 2, 1, xsane.out); + } + } + else /* gamma correction by scanner */ + { + fwrite(buf16, 2, len/2, xsane.out); + } + } + break; + + case SANE_FRAME_RED: + case SANE_FRAME_GREEN: + case SANE_FRAME_BLUE: + if (xsane.mode == XSANE_STANDALONE) + { + for (i = 0; i < len/2; ++i) + { + fwrite(buf16 + i*2, 2, 1, xsane.out); + fseek(xsane.out, 4, SEEK_CUR); + } + } + break; + +#ifdef SUPPORT_RGBA + case SANE_FRAME_RGBA: + if (xsane.mode == XSANE_STANDALONE) + { + int i; + guint16 val; + + if (!xsane.scanner_gamma_color) + { + for (i=0; i < len/2; ++i) + { + if (dialog->pixelcolor == 0) + { + val = xsane.gamma_data_red[buf16[i]]; + dialog->pixelcolor++; + } + else if (dialog->pixelcolor == 1) + { + val = xsane.gamma_data_green[buf16[i]]; + dialog->pixelcolor++; + } + else if (dialog->pixelcolor == 2) + { + val = xsane.gamma_data_blue[buf16[i]]; + dialog->pixelcolor++; + } + else + { + val = buf16[i]; /* no gamma table for infrared channel */ + dialog->pixelcolor = 0; + } + fwrite(&val, 2, 1, xsane.out); + } + } + else + { + fwrite(buf16, 2, len/2, xsane.out); + } + } + break; +#endif + + default: + xsane_scan_done(-1); /* -1 = error */ + fprintf(stderr, "xsane_read_image_data: %s %d\n", ERR_BAD_FRAME_FORMAT, xsane.param.format); + return; + break; + } + } + } + else + { + xsane_scan_done(-1); /* -1 = error */ + snprintf(buf, sizeof(buf), "%s %d.", ERR_BAD_DEPTH, xsane.param.depth); + xsane_back_gtk_error(buf, TRUE); + return; + } + + return; + + /* ---------------------- */ + +#ifdef HAVE_LIBGIMP_GIMP_H +bad_depth: + + xsane_scan_done(-1); /* -1 = error */ + snprintf(buf, sizeof(buf), "%s %d.", ERR_BAD_DEPTH, xsane.param.depth); + xsane_back_gtk_error(buf, TRUE); + return; +#endif +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static RETSIGTYPE xsane_sigpipe_handler(int signal) +/* this is to catch a broken pipe while writing to printercommand */ +{ + xsane_cancel_save(0); + xsane.broken_pipe = 1; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_test_multi_scan(void) +{ + char *set; + SANE_Status status; + const SANE_Option_Descriptor *opt; + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.scansource); + if (opt) + { + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + if (opt->constraint_type == SANE_CONSTRAINT_STRING_LIST) + { + set = malloc(opt->size); + status = sane_control_option(dialog->dev, dialog->well_known.scansource, SANE_ACTION_GET_VALUE, set, 0); + + if (status == SANE_STATUS_GOOD) + { + if (!strcmp(set, SANE_NAME_DOCUMENT_FEEDER)) + { + return TRUE; + } + } + free(set); + } + } + } + +#if 0 /* this is planned for the next sane-standard */ + if (xsane.param.bitfield & XSANE_PARAM_STATUS_MORE_IMAGES) + { + return TRUE; + } +#endif + + return FALSE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_scan_done(SANE_Status status) +{ + if (xsane.input_tag >= 0) + { + gdk_input_remove(xsane.input_tag); + xsane.input_tag = -1; + } + + if (xsane.progress) /* remove progressbar */ + { + xsane_progress_free(xsane.progress); + xsane.progress = 0; + } + + while(gtk_events_pending()) /* let gtk remove the progress bar and update everything that needs it */ + { + gtk_main_iteration(); + } + + + /* we have to free the gamma tables if we used software gamma correction */ + + if (xsane.gamma_data) + { + free(xsane.gamma_data); + xsane.gamma_data = 0; + } + + if (xsane.gamma_data_red) + { + free(xsane.gamma_data_red); + free(xsane.gamma_data_green); + free(xsane.gamma_data_blue); + + xsane.gamma_data_red = 0; + xsane.gamma_data_green = 0; + xsane.gamma_data_blue = 0; + } + + if (xsane.out) /* close file - this is dummy_file but if there is no conversion it is the wanted file */ + { + fclose(xsane.out); + xsane.out = 0; + } + + if ( (status == SANE_STATUS_GOOD) || (status == SANE_STATUS_EOF) ) /* no error, do conversion etc. */ + { + if (xsane.mode == XSANE_STANDALONE) + { + if ( (xsane.xsane_mode == XSANE_SCAN) && (xsane.xsane_output_format != XSANE_PNM) && + (xsane.xsane_output_format != XSANE_RAW16) && (xsane.xsane_output_format != XSANE_RGBA) ) + { + FILE *outfile; + FILE *infile; + char buf[256]; + + /* open progressbar */ + snprintf(buf, sizeof(buf), PROGRESS_SAVING); + xsane.progress = xsane_progress_new(PROGRESS_CONVERTING_DATA, buf, (GtkSignalFunc) xsane_cancel_save, 0); + xsane_progress_update(xsane.progress, 0); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + infile = fopen(xsane.dummy_filename, "r"); + if (infile != 0) + { + fseek(infile, xsane.header_size, SEEK_SET); + +#ifdef HAVE_LIBTIFF + if (xsane.xsane_output_format == XSANE_TIFF) /* routines that want to have filename for saving */ + { + if (xsane.param.depth != 1) + { + remove(xsane.output_filename); + umask(preferences.image_umask); /* define image file permissions */ + xsane_save_tiff(xsane.output_filename, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, + xsane.param.lines, preferences.tiff_compression_nr, preferences.jpeg_quality); + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + } + else + { + remove(xsane.output_filename); + umask(preferences.image_umask); /* define image file permissions */ + xsane_save_tiff(xsane.output_filename, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, + xsane.param.lines, preferences.tiff_compression_1_nr, preferences.jpeg_quality); + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + } + } + else /* routines that want to have filedescriptor for saving */ +#endif + { + remove(xsane.output_filename); + umask(preferences.image_umask); /* define image file permissions */ + outfile = fopen(xsane.output_filename, "w"); + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + + if (outfile != 0) + { + switch(xsane.xsane_output_format) + { +#ifdef HAVE_LIBJPEG + case XSANE_JPEG: + xsane_save_jpeg(outfile, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, + xsane.param.lines, preferences.jpeg_quality); + break; +#endif + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ + case XSANE_PNG: + if (xsane.param.depth <= 8) + { + xsane_save_png(outfile, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, + xsane.param.lines, preferences.png_compression); + } + else + { + xsane_save_png_16(outfile, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, + xsane.param.lines, preferences.png_compression); + } + break; +#endif +#endif + + case XSANE_PNM16: + xsane_save_pnm_16(outfile, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, + xsane.param.lines); + break; + + case XSANE_PS: /* save postscript, use original size */ + { + float imagewidth = xsane.param.pixels_per_line/xsane.resolution_x; /* width in inch */ + float imageheight = xsane.param.lines/xsane.resolution_y; /* height in inch */ + + if (preferences.psrotate) /* rotate: landscape */ + { + xsane_save_ps(outfile, infile, + xsane.xsane_color /* gray, color */, + xsane.param.depth /* bits */, + xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ + (preferences.printer[preferences.printernr]->bottomoffset + + preferences.printer[preferences.printernr]->height) * 36.0/MM_PER_INCH - imagewidth * 36.0, /* left edge */ + (preferences.printer[preferences.printernr]->leftoffset + + preferences.printer[preferences.printernr]->width) * 36.0/MM_PER_INCH - imageheight * 36.0, /* bottom edge */ + imagewidth, imageheight, + (preferences.printer[preferences.printernr]->leftoffset + + preferences.printer[preferences.printernr]->width ) * 72.0/MM_PER_INCH, /* paperwidth */ + (preferences.printer[preferences.printernr]->bottomoffset + + preferences.printer[preferences.printernr]->height) * 72.0/MM_PER_INCH, /* paperheight */ + 1 /* landscape */); + } + else /* do not rotate: portrait */ + { + xsane_save_ps(outfile, infile, + xsane.xsane_color /* gray, color */, + xsane.param.depth /* bits */, + xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ + (preferences.printer[preferences.printernr]->leftoffset + + preferences.printer[preferences.printernr]->width) * 36.0/MM_PER_INCH - imagewidth * 36.0, + (preferences.printer[preferences.printernr]->bottomoffset + + preferences.printer[preferences.printernr]->height) * 36.0/MM_PER_INCH - imageheight * 36.0, + imagewidth, imageheight, + (preferences.printer[preferences.printernr]->leftoffset + + preferences.printer[preferences.printernr]->width ) * 72.0/MM_PER_INCH, /* paperwidth */ + (preferences.printer[preferences.printernr]->bottomoffset + + preferences.printer[preferences.printernr]->height) * 72.0/MM_PER_INCH, /* paperheight */ + 0 /* portrait */); + } + } + break; + + + default: + snprintf(buf, sizeof(buf),"%s", ERR_UNKNOWN_SAVING_FORMAT); + xsane_back_gtk_error(buf, TRUE); + break; + } + fclose(outfile); + } + else + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.output_filename, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + } + } + fclose(infile); + remove(xsane.dummy_filename); + } + else + { + char buf[256]; + snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.output_filename, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + } + xsane_progress_free(xsane.progress); + xsane.progress = 0; + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + } + else if (xsane.xsane_mode == XSANE_COPY) + { + FILE *outfile; + FILE *infile; + char buf[256]; + + xsane_update_int(xsane.copy_number_entry, &xsane.copy_number); /* get number of copies */ + if (xsane.copy_number < 1) + { + xsane.copy_number = 1; + } + + /* open progressbar */ + snprintf(buf, sizeof(buf), PROGRESS_CONVERTING_PS); + xsane.progress = xsane_progress_new(PROGRESS_CONVERTING_DATA, buf, (GtkSignalFunc) xsane_cancel_save, 0); + xsane_progress_update(xsane.progress, 0); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + xsane.broken_pipe = 0; + infile = fopen(xsane.dummy_filename, "r"); + + snprintf(buf, sizeof(buf), "%s %s%d", preferences.printer[preferences.printernr]->command, + preferences.printer[preferences.printernr]->copy_number_option, + xsane.copy_number); + outfile = popen(buf, "w"); +/* outfile = popen(preferences.printer[preferences.printernr]->command, "w"); */ + if ((outfile != 0) && (infile != 0)) /* copy mode, use zoom size */ + { + struct SIGACTION act; + float imagewidth = xsane.param.pixels_per_line/(float)preferences.printer[preferences.printernr]->resolution; /* width in inch */ + float imageheight = xsane.param.lines/(float)preferences.printer[preferences.printernr]->resolution; /* height in inch */ + + memset (&act, 0, sizeof (act)); /* define broken pipe handler */ + act.sa_handler = xsane_sigpipe_handler; + sigaction (SIGPIPE, &act, 0); + + + fseek(infile, xsane.header_size, SEEK_SET); + + if (preferences.psrotate) /* rotate: landscape */ + { + xsane_save_ps(outfile, infile, + xsane.xsane_color /* gray, color */, + xsane.param.depth /* bits */, + xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ + (preferences.printer[preferences.printernr]->bottomoffset + + preferences.printer[preferences.printernr]->height) * 36.0/MM_PER_INCH - imagewidth * 36.0, /* left edge */ + (preferences.printer[preferences.printernr]->leftoffset + + preferences.printer[preferences.printernr]->width) * 36.0/MM_PER_INCH - imageheight * 36.0, /* bottom edge */ + imagewidth, imageheight, + (preferences.printer[preferences.printernr]->leftoffset + + preferences.printer[preferences.printernr]->width ) * 72.0/MM_PER_INCH, /* paperwidth */ + (preferences.printer[preferences.printernr]->bottomoffset + + preferences.printer[preferences.printernr]->height) * 72.0/MM_PER_INCH, /* paperheight */ + 1 /* landscape */); + } + else /* do not rotate: portrait */ + { + xsane_save_ps(outfile, infile, + xsane.xsane_color /* gray, color */, + xsane.param.depth /* bits */, + xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ + (preferences.printer[preferences.printernr]->leftoffset + + preferences.printer[preferences.printernr]->width) * 36.0/MM_PER_INCH - imagewidth * 36.0, /* left edge */ + (preferences.printer[preferences.printernr]->bottomoffset + + preferences.printer[preferences.printernr]->height) * 36.0/MM_PER_INCH - imageheight * 36.0, /* bottom edge */ + imagewidth, imageheight, + (preferences.printer[preferences.printernr]->leftoffset + + preferences.printer[preferences.printernr]->width ) * 72.0/MM_PER_INCH, /* paperwidth */ + (preferences.printer[preferences.printernr]->bottomoffset + + preferences.printer[preferences.printernr]->height) * 72.0/MM_PER_INCH, /* paperheight */ + 0 /* portrait */); + } + } + else + { + char buf[256]; + + if (!infile) + { + snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.output_filename, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + } + else if (!outfile) + { + xsane_back_gtk_error(ERR_FAILED_PRINTER_PIPE, TRUE); + } + } + + if (xsane.broken_pipe) + { + snprintf(buf, sizeof(buf), "%s \"%s\"", ERR_FAILED_EXEC_PRINTER_CMD, preferences.printer[preferences.printernr]->command); + xsane_back_gtk_error(buf, TRUE); + } + + xsane_progress_free(xsane.progress); + xsane.progress = 0; + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (infile) + { + fclose(infile); + remove(xsane.dummy_filename); + } + + if (outfile) + { + pclose(outfile); + } + } + else if (xsane.xsane_mode == XSANE_FAX) + { + FILE *outfile; + FILE *infile; + char buf[256]; + + /* open progressbar */ + snprintf(buf, sizeof(buf), PROGRESS_SAVING_FAX); + xsane.progress = xsane_progress_new(PROGRESS_CONVERTING_DATA, buf, (GtkSignalFunc) xsane_cancel_save, 0); + xsane_progress_update(xsane.progress, 0); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + infile = fopen(xsane.dummy_filename, "r"); + if (infile != 0) + { + fseek(infile, xsane.header_size, SEEK_SET); + + umask(preferences.image_umask); /* define image file permissions */ + outfile = fopen(xsane.fax_filename, "w"); + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + if (outfile != 0) + { + float imagewidth, imageheight; + + imagewidth = xsane.param.pixels_per_line/xsane.resolution_x; /* width in inch */ + imageheight = xsane.param.lines/xsane.resolution_y; /* height in inch */ + +/* disabled ( 0 * ...) in the moment */ + if (0 * preferences.psrotate) /* rotate: landscape */ + { + xsane_save_ps(outfile, infile, + xsane.xsane_color /* gray, color */, + xsane.param.depth /* bits */, + xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ + (preferences.fax_bottomoffset + preferences.fax_height) * 36.0/MM_PER_INCH - imagewidth * 36.0, /* left edge */ + (preferences.fax_leftoffset + preferences.fax_width) * 36.0/MM_PER_INCH - imageheight * 36.0, /* bottom edge */ + imagewidth, imageheight, + (preferences.fax_leftoffset + preferences.fax_width ) * 72.0/MM_PER_INCH, /* paperwidth */ + (preferences.fax_bottomoffset + preferences.fax_height) * 72.0/MM_PER_INCH, /* paperheight */ + 1 /* landscape */); + } + else /* do not rotate: portrait */ + { + xsane_save_ps(outfile, infile, + xsane.xsane_color /* gray, color */, + xsane.param.depth /* bits */, + xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ + (preferences.fax_leftoffset + preferences.fax_width) * 36.0/MM_PER_INCH - imagewidth * 36.0, + (preferences.fax_bottomoffset + preferences.fax_height) * 36.0/MM_PER_INCH - imageheight * 36.0, + imagewidth, imageheight, + (preferences.fax_leftoffset + preferences.fax_width ) * 72.0/MM_PER_INCH, /* paperwidth */ + (preferences.fax_bottomoffset + preferences.fax_height) * 72.0/MM_PER_INCH, /* paperheight */ + 0 /* portrait */); + } + fclose(outfile); + } + else + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.fax_filename, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + } + + fclose(infile); + remove(xsane.dummy_filename); + } + else + { + char buf[256]; + snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.fax_filename, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + } + xsane_progress_free(xsane.progress); + xsane.progress = 0; + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + } + } +#ifdef HAVE_LIBGIMP_GIMP_H + else + { + int remaining; + + /* GIMP mode */ + if (xsane.y > xsane.param.lines) + { + xsane.y = xsane.param.lines; + } + + remaining = xsane.y % gimp_tile_height(); + if (remaining) + { + gimp_pixel_rgn_set_rect(&xsane.region, xsane.tile, 0, xsane.y - remaining, xsane.param.pixels_per_line, remaining); + } + gimp_drawable_flush(xsane.drawable); + gimp_display_new(xsane.image_ID); + gimp_drawable_detach(xsane.drawable); + free(xsane.tile); + xsane.tile = 0; + } +#endif /* HAVE_LIBGIMP_GIMP_H */ + + xsane.header_size = 0; + + if ( (preferences.increase_filename_counter) && (xsane.xsane_mode == XSANE_SCAN) && (xsane.mode == XSANE_STANDALONE) ) + { + xsane_increase_counter_in_filename(preferences.filename, preferences.skip_existing_numbers); + gtk_entry_set_text(GTK_ENTRY(xsane.outputfilename_entry), (char *) preferences.filename); + } + else if (xsane.xsane_mode == XSANE_FAX) + { + GtkWidget *list_item; + char *page; + char *extension; + + page = strdup(strrchr(xsane.fax_filename,'/')+1); + extension = strrchr(page, '.'); + if (extension) + { + *extension = 0; + } + list_item = gtk_list_item_new_with_label(page); + gtk_object_set_data(GTK_OBJECT(list_item), "list_item_data", strdup(page)); + gtk_container_add(GTK_CONTAINER(xsane.fax_list), list_item); + gtk_widget_show(list_item); + + xsane_increase_counter_in_filename(xsane.fax_filename, preferences.skip_existing_numbers); + xsane_fax_project_save(); + free(page); + } + } + else /* an error occured, remove the dummy_file */ + { + if (xsane.dummy_filename) /* remove corrupt file */ + { + remove(xsane.dummy_filename); + } + } + + free(xsane.dummy_filename); /* no dummy_filename, needed if an error occurs */ + xsane.dummy_filename = 0; + + if (xsane.output_filename) + { + free(xsane.output_filename); + xsane.output_filename = 0; + } + + if ( ( (status == SANE_STATUS_GOOD) || (status == SANE_STATUS_EOF) ) && (xsane_test_multi_scan()) ) + { + /* multi scan (eg ADF): scan again */ + /* stopped when: */ + /* a) xsane_test_multi_scan returns false */ + /* b) sane_start returns SANE_STATUS_NO_DOCS */ + /* c) an error occurs */ + + gtk_signal_emit_by_name(xsane.start_button, "clicked"); /* press START button */ + } + else /* last scan: update histogram */ + { + xsane_set_sensitivity(TRUE); /* reactivate buttons etc */ + sane_cancel(xsane_back_gtk_dialog_get_device(dialog)); /* stop scanning */ + xsane_update_histogram(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_cancel(void) +{ + sane_cancel(xsane_back_gtk_dialog_get_device(dialog)); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_start_scan(void) +{ + SANE_Status status; + SANE_Handle dev = xsane_back_gtk_dialog_get_device(dialog); + const char *frame_type = 0; + char buf[256]; + int fd; + + xsane_clear_histogram(&xsane.histogram_raw); + xsane_clear_histogram(&xsane.histogram_enh); + xsane_set_sensitivity(FALSE); + +#ifdef HAVE_LIBGIMP_GIMP_H + if (xsane.mode == XSANE_GIMP_EXTENSION && xsane.tile) + { + int height, remaining; + + /* write the last tile of the frame to the GIMP region: */ + + if (xsane.y > xsane.param.lines) /* sanity check */ + { + xsane.y = xsane.param.lines; + } + + remaining = xsane.y % gimp_tile_height(); + if (remaining) + { + gimp_pixel_rgn_set_rect(&xsane.region, xsane.tile, 0, xsane.y - remaining, xsane.param.pixels_per_line, remaining); + } + + /* initialize the tile with the first tile of the GIMP region: */ + + height = gimp_tile_height(); + if (height >= xsane.param.lines) + { + height = xsane.param.lines; + } + gimp_pixel_rgn_get_rect(&xsane.region, xsane.tile, 0, 0, xsane.param.pixels_per_line, height); + } +#endif /* HAVE_LIBGIMP_GIMP_H */ + + xsane.x = xsane.y = 0; + + status = sane_start(dev); + + if (status == SANE_STATUS_NO_DOCS) /* ADF out of docs */ + { + xsane_scan_done(status); /* ok, stop multi image scan */ + return; + } + else if (status != SANE_STATUS_GOOD) /* error */ + { + xsane_scan_done(status); + snprintf(buf, sizeof(buf), "%s %s", ERR_FAILED_START_SCANNER, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, TRUE); + return; + } + + status = sane_get_parameters(dev, &xsane.param); + if (status != SANE_STATUS_GOOD) + { + xsane_scan_done(status); + snprintf(buf, sizeof(buf), "%s %s", ERR_FAILED_GET_PARAMS, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, TRUE); + return; + } + + xsane.num_bytes = xsane.param.lines * xsane.param.bytes_per_line; + xsane.bytes_read = 0; + + switch (xsane.param.format) + { + case SANE_FRAME_RGB: frame_type = "RGB"; break; + case SANE_FRAME_RED: frame_type = "red"; break; + case SANE_FRAME_GREEN: frame_type = "green"; break; + case SANE_FRAME_BLUE: frame_type = "blue"; break; + case SANE_FRAME_GRAY: frame_type = "gray"; break; +#ifdef SUPPORT_RGBA + case SANE_FRAME_RGBA: frame_type = "RGBA"; break; +#endif + default: frame_type = "unknown"; break; + } + + if (xsane.mode == XSANE_STANDALONE) + { /* We are running in standalone mode */ + if (xsane_generate_dummy_filename()) /* create filename the scanned data is saved to */ + { + /* temporary file */ + umask(0177); /* creare temporary file with "-rw-------" permissions */ + } + else + { + /* no temporary file */ + umask(preferences.image_umask); /* define image file permissions */ + } + + if (!xsane.header_size) /* first pass of multi pass scan */ + { + remove(xsane.dummy_filename); /* remove existing file */ + xsane.out = fopen(xsane.dummy_filename, "w"); + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + + if (!xsane.out) /* error while opening the dummy_file for writing */ + { + xsane_scan_done(-1); /* -1 = error */ + snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.output_filename, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + return; + } + + switch (xsane.param.format) + { + case SANE_FRAME_RGB: + case SANE_FRAME_RED: + case SANE_FRAME_GREEN: + case SANE_FRAME_BLUE: + switch (xsane.param.depth) + { + case 8: /* color 8 bit mode, write ppm header */ + fprintf(xsane.out, "P6\n# SANE data follows\n%d %d\n255\n", xsane.param.pixels_per_line, xsane.param.lines); + break; + + default: /* color, but not 8 bit mode, write as raw data because this is not defined in pnm */ + fprintf(xsane.out, "SANE_RGB_RAW\n%d %d\n65535\n", xsane.param.pixels_per_line, xsane.param.lines); + break; + } + break; + + case SANE_FRAME_GRAY: + switch (xsane.param.depth) + { + case 1: /* 1 bit lineart mode, write pbm header */ + fprintf(xsane.out, "P4\n# SANE data follows\n%d %d\n", xsane.param.pixels_per_line, xsane.param.lines); + break; + + case 8: /* 8 bit grayscale mode, write pgm header */ + fprintf(xsane.out, "P5\n# SANE data follows\n%d %d\n255\n", xsane.param.pixels_per_line, xsane.param.lines); + break; + + default: /* grayscale mode but not 1 or 8 bit, write as raw data because this is not defined in pnm */ + fprintf(xsane.out, "SANE_GRAYSCALE_RAW\n%d %d\n65535\n", xsane.param.pixels_per_line, xsane.param.lines); + break; + } + break; + +#ifdef SUPPORT_RGBA + case SANE_FRAME_RGBA: + switch (xsane.param.depth) + { + case 8: /* 8 bit RGBA mode */ + fprintf(xsane.out, "SANE_RGBA\n%d %d\n255\n", xsane.param.pixels_per_line, xsane.param.lines); + break; + + default: /* 16 bit RGBA mode */ + fprintf(xsane.out, "SANE_RGBA\n%d %d\n65535\n", xsane.param.pixels_per_line, xsane.param.lines); + break; + } + break; +#endif + + default: + /* unknown file format, do not write header */ + break; + } + fflush(xsane.out); + xsane.header_size = ftell(xsane.out); + } + + if (xsane.param.format >= SANE_FRAME_RED && xsane.param.format <= SANE_FRAME_BLUE) + { + fseek(xsane.out, xsane.header_size + xsane.param.format - SANE_FRAME_RED, SEEK_SET); + } + + if (xsane.xsane_mode == XSANE_SCAN) + { + snprintf(buf, sizeof(buf), PROGRESS_RECEIVING_SCAN, _(frame_type), xsane.output_filename); + } + else if (xsane.xsane_mode == XSANE_COPY) + { + snprintf(buf, sizeof(buf), PROGRESS_RECEIVING_COPY, _(frame_type)); + } + else if (xsane.xsane_mode == XSANE_FAX) + { + snprintf(buf, sizeof(buf), PROGRESS_RECEIVING_FAX, _(frame_type)); + } + } +#ifdef HAVE_LIBGIMP_GIMP_H + else + { + size_t tile_size; + + /* We are running under the GIMP */ + + xsane.tile_offset = 0; + tile_size = xsane.param.pixels_per_line * gimp_tile_height(); + + switch(xsane.param.format) + { + case SANE_FRAME_RGB: + case SANE_FRAME_RED: + case SANE_FRAME_BLUE: + case SANE_FRAME_GREEN: + tile_size *= 3; /* 24 bits/pixel RGB */ + break; +#ifdef SUPPORT_RGBA + case SANE_FRAME_RGBA: + tile_size *= 4; /* 32 bits/pixel RGBA */ + break; +#endif + default: + break; + } + + if (xsane.tile) + { + xsane.first_frame = 0; + } + else + { + GImageType image_type = RGB; + GDrawableType drawable_type = RGB_IMAGE; + gint32 layer_ID; + + if (xsane.param.format == SANE_FRAME_GRAY) + { + image_type = GRAY; + drawable_type = GRAY_IMAGE; + } +#ifdef SUPPORT_RGBA + else if (xsane.param.format == SANE_FRAME_RGBA) + { + image_type = RGB; + drawable_type = RGBA_IMAGE; /* interpret infrared as alpha */ + } +#endif + + + xsane.image_ID = gimp_image_new(xsane.param.pixels_per_line, xsane.param.lines, image_type); + +/* the following is supported since gimp-1.1.? */ +#ifdef GIMP_HAVE_RESOLUTION_INFO + if (xsane.resolution_x > 0) + { + gimp_image_set_resolution(xsane.image_ID, xsane.resolution_x ,xsane.resolution_y); + } +/* gimp_image_set_unit(xsane.image_ID, unit?); */ +#endif + + layer_ID = gimp_layer_new(xsane.image_ID, "Background", + xsane.param.pixels_per_line, + xsane.param.lines, + drawable_type, 100, NORMAL_MODE); + gimp_image_add_layer(xsane.image_ID, layer_ID, 0); + + xsane.drawable = gimp_drawable_get(layer_ID); + gimp_pixel_rgn_init(&xsane.region, xsane.drawable, 0, 0, + xsane.drawable->width, + xsane.drawable->height, TRUE, FALSE); + xsane.tile = g_new(guchar, tile_size); + xsane.first_frame = 1; + } + + if (xsane.param.format >= SANE_FRAME_RED && xsane.param.format <= SANE_FRAME_BLUE) + { + xsane.tile_offset = xsane.param.format - SANE_FRAME_RED; + } + + snprintf(buf, sizeof(buf), PROGRESS_RECEIVING_GIMP, _(frame_type)); + } +#endif /* HAVE_LIBGIMP_GIMP_H */ + + dialog->pixelcolor = 0; + + if (xsane.progress) + { + xsane_progress_free(xsane.progress); + } + xsane.progress = xsane_progress_new(PROGRESS_SCANNING, buf, (GtkSignalFunc) xsane_cancel, 0); + + xsane.input_tag = -1; + + if (sane_set_io_mode(dev, SANE_TRUE) == SANE_STATUS_GOOD && sane_get_select_fd(dev, &fd) == SANE_STATUS_GOOD) + { + xsane.input_tag = gdk_input_add(fd, GDK_INPUT_READ, xsane_read_image_data, 0); + } + else + { + xsane_read_image_data(0, -1, GDK_INPUT_READ); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* Invoked when the scan button is pressed */ +/* or by scan_done if automatic document feeder is selected */ +void xsane_scan_dialog(GtkWidget * widget, gpointer call_data) +{ + char buf[256]; + + sane_get_parameters(dialog->dev, &xsane.param); /* update xsane.param */ + + if (xsane.output_filename) + { + free(xsane.output_filename); + xsane.output_filename = 0; + } + + if (xsane.filetype) + { + char buffer[256]; + + snprintf(buffer, sizeof(buffer), "%s%s", preferences.filename, xsane.filetype); + xsane.output_filename = strdup(buffer); + } + else + { + xsane.output_filename = strdup(preferences.filename); + } + + if (xsane.mode == XSANE_STANDALONE) /* We are running in standalone mode */ + { + char *extension; + + if ( (xsane.xsane_mode == XSANE_SCAN) && (preferences.overwrite_warning) ) /* test if filename already used */ + { + FILE *testfile; + + testfile = fopen(xsane.output_filename, "r"); + if (testfile) /* filename used: skip */ + { + char buf[256]; + + fclose(testfile); + snprintf(buf, sizeof(buf), "File %s already exists\n", xsane.output_filename); + if (xsane_back_gtk_decision(ERR_HEADER_WARNING, (gchar **) warning_xpm, buf, BUTTON_OVERWRITE, BUTTON_CANCEL, TRUE /* wait */) == FALSE) + { + return; + } + } + } + + + extension = strrchr(xsane.output_filename, '.'); + if (extension) + { + extension++; /* skip "." */ + } + + xsane.xsane_output_format = XSANE_UNKNOWN; + + if (xsane.param.depth <= 8) + { + if (extension) + { + if ( (!strcasecmp(extension, "pnm")) || (!strcasecmp(extension, "ppm")) || + (!strcasecmp(extension, "pgm")) || (!strcasecmp(extension, "pbm")) ) + { + xsane.xsane_output_format = XSANE_PNM; + } +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ + else if (!strcasecmp(extension, "png")) + { + xsane.xsane_output_format = XSANE_PNG; + } +#endif +#endif +#ifdef HAVE_LIBJPEG + else if ( (!strcasecmp(extension, "jpg")) || (!strcasecmp(extension, "jpeg")) ) + { + xsane.xsane_output_format = XSANE_JPEG; + } +#endif + else if (!strcasecmp(extension, "ps")) + { + xsane.xsane_output_format = XSANE_PS; + } +#ifdef HAVE_LIBTIFF + else if ( (!strcasecmp(extension, "tif")) || (!strcasecmp(extension, "tiff")) ) + { + xsane.xsane_output_format = XSANE_TIFF; + } +#endif +#ifdef SUPPORT_RGBA + else if (!strcasecmp(extension, "rgba")) + { + xsane.xsane_output_format = XSANE_RGBA; + } +#endif + } + } + else /* depth >8 bpp */ + { + if (extension) + { + if (!strcasecmp(extension, "raw")) + { + xsane.xsane_output_format = XSANE_RAW16; + } + else if ( (!strcasecmp(extension, "pnm")) || (!strcasecmp(extension, "ppm")) || + (!strcasecmp(extension, "pgm")) || (!strcasecmp(extension, "pbm")) ) + { + xsane.xsane_output_format = XSANE_PNM16; + } +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ + else if (!strcasecmp(extension, "png")) + { + xsane.xsane_output_format = XSANE_PNG; + } +#endif +#endif +#ifdef SUPPORT_RGBA + else if (!strcasecmp(extension, "rgba")) + { + xsane.xsane_output_format = XSANE_RGBA; + } +#endif + } + } + + if (xsane.xsane_mode == XSANE_SCAN) + { + if (xsane.xsane_output_format == XSANE_UNKNOWN) + { + if (extension) + { + snprintf(buf, sizeof(buf), "Unsupported %d-bit output format: %s", xsane.param.depth, extension); + } + else + { + snprintf(buf, sizeof(buf), "%s", ERR_NO_OUTPUT_FORMAT); + } + xsane_back_gtk_error(buf, TRUE); + return; + } +#ifdef SUPPORT_RGBA + else if ((xsane.xsane_output_format == XSANE_RGBA) && (xsane.param.format != SANE_FRAME_RGBA)) + { + snprintf(buf, sizeof(buf), "No RGBA data format !!!"); /* user selected output format RGBA, scanner uses other format */ + xsane_back_gtk_error(buf, TRUE); + return; + } +#endif + } +#ifdef SUPPORT_RGBA + else if (xsane.param.format == SANE_FRAME_RGBA) /* no scanmode but format=rgba */ + { + snprintf(buf, sizeof(buf), "Special format RGBA only supported in scan mode !!!"); + xsane_back_gtk_error(buf, TRUE); + return; + } +#endif + +#ifdef SUPPORT_RGBA + if (xsane.param.format == SANE_FRAME_RGBA) + { + if ( (xsane.xsane_output_format != XSANE_RGBA) && (xsane.xsane_output_format != XSANE_PNG) ) + { + snprintf(buf, sizeof(buf), "Image data of type SANE_FRAME_RGBA\ncan only be saved in rgba or png format"); + xsane_back_gtk_error(buf, TRUE); + return; + } + } +#endif + + if (xsane.xsane_mode == XSANE_FAX) + { + mkdir(preferences.fax_project, 7*64 + 0*8 + 0); + } + } +#ifdef HAVE_LIBGIMP_GIMP_H + else /* We are running in gimp mode */ + { + if ((xsane.param.depth != 1) && (xsane.param.depth != 8)) /* not support bit depth ? */ + { + snprintf(buf, sizeof(buf), "%s %d.", ERR_GIMP_BAD_DEPTH, xsane.param.depth); + xsane_back_gtk_error(buf, TRUE); + return; + } + } +#endif + + if (xsane.dummy_filename) /* no dummy filename defined - necessary if an error occurs */ + { + free(xsane.dummy_filename); + xsane.dummy_filename = 0; + } + + if (xsane.param.depth > 1) /* if depth > 1 use gamma correction */ + { + int size; + int gamma_gray_size, gamma_red_size, gamma_green_size, gamma_blue_size; + int gamma_gray_max, gamma_red_max, gamma_green_max, gamma_blue_max; + const SANE_Option_Descriptor *opt; + + size = (int) pow(2, xsane.param.depth); + gamma_gray_size = size; + gamma_red_size = size; + gamma_green_size = size; + gamma_blue_size = size; + + size--; + gamma_gray_max = size; + gamma_red_max = size; + gamma_green_max = size; + gamma_blue_max = size; + + if (xsane.scanner_gamma_gray) /* gamma table for gray available */ + { + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector); + gamma_gray_size = opt->size / sizeof(opt->type); + gamma_gray_max = opt->constraint.range->max; + } + + if (xsane.scanner_gamma_color) /* gamma table for red, green and blue available */ + { + double gamma_red, gamma_green, gamma_blue; + + /* ok, scanner color gamma function is supported, so we do all conversions about that */ + /* we do not need any gamma tables while scanning, so we can free them after sending */ + /* the data to the scanner */ + + /* if also gray gamma function is supported, set this to 1.0 to get the right colors */ + if (xsane.scanner_gamma_gray) + { + xsane.gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int)); + xsane_create_gamma_curve(xsane.gamma_data, 0, 1.0, 0.0, 0.0, gamma_gray_size, gamma_gray_max); + xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector, xsane.gamma_data); + free(xsane.gamma_data); + xsane.gamma_data = 0; + } + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector_r); + gamma_red_size = opt->size / sizeof(opt->type); + gamma_red_max = opt->constraint.range->max; + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector_g); + gamma_green_size = opt->size / sizeof(opt->type); + gamma_green_max = opt->constraint.range->max; + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector_b); + gamma_blue_size = opt->size / sizeof(opt->type); + gamma_blue_max = opt->constraint.range->max; + + xsane.gamma_data_red = malloc(gamma_red_size * sizeof(SANE_Int)); + xsane.gamma_data_green = malloc(gamma_green_size * sizeof(SANE_Int)); + xsane.gamma_data_blue = malloc(gamma_blue_size * sizeof(SANE_Int)); + + if (xsane.xsane_mode == XSANE_COPY) + { + gamma_red = xsane.gamma * xsane.gamma_red * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_red; + gamma_green = xsane.gamma * xsane.gamma_green * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_green; + gamma_blue = xsane.gamma * xsane.gamma_blue * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_blue; + } + else + { + gamma_red = xsane.gamma * xsane.gamma_red; + gamma_green = xsane.gamma * xsane.gamma_green; + gamma_blue = xsane.gamma * xsane.gamma_blue; + } + + xsane_create_gamma_curve(xsane.gamma_data_red, xsane.negative, + gamma_red, + xsane.brightness + xsane.brightness_red, + xsane.contrast + xsane.contrast_red, gamma_red_size, gamma_red_max); + + xsane_create_gamma_curve(xsane.gamma_data_green, xsane.negative, + gamma_green, + xsane.brightness + xsane.brightness_green, + xsane.contrast + xsane.contrast_green, gamma_green_size, gamma_green_max); + + xsane_create_gamma_curve(xsane.gamma_data_blue, xsane.negative, + gamma_blue, + xsane.brightness + xsane.brightness_blue, + xsane.contrast + xsane.contrast_blue , gamma_blue_size, gamma_blue_max); + + xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector_r, xsane.gamma_data_red); + xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector_g, xsane.gamma_data_green); + xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector_b, xsane.gamma_data_blue); + + free(xsane.gamma_data_red); + free(xsane.gamma_data_green); + free(xsane.gamma_data_blue); + + xsane.gamma_data_red = 0; + xsane.gamma_data_green = 0; + xsane.gamma_data_blue = 0; + } + else if (xsane.scanner_gamma_gray) /* only scanner gray gamma function available */ + { + double gamma; + /* ok, the scanner only supports gray gamma function */ + /* if we are doing a grayscale scan everyting is ok, */ + /* for a color scan the software has to do the gamma correction set by the component slider */ + + if (xsane.xsane_mode == XSANE_COPY) + { + gamma = xsane.gamma * preferences.printer[preferences.printernr]->gamma; + } + else + { + gamma = xsane.gamma; + } + + xsane.gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int)); + xsane_create_gamma_curve(xsane.gamma_data, xsane.negative, + gamma, xsane.brightness, xsane.contrast, + gamma_gray_size, gamma_gray_max); + + xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector, xsane.gamma_data); + free(xsane.gamma_data); + xsane.gamma_data = 0; + + if (xsane.xsane_color) /* ok, we are doing a colorscan */ + { + /* we have to create color gamma table for software conversion */ + /* but we only have to use color slider values, because gray slider value */ + /* is used by scanner gray gamma */ + + double gamma_red, gamma_green, gamma_blue; + + xsane.gamma_data_red = malloc(gamma_red_size * sizeof(SANE_Int)); + xsane.gamma_data_green = malloc(gamma_green_size * sizeof(SANE_Int)); + xsane.gamma_data_blue = malloc(gamma_blue_size * sizeof(SANE_Int)); + + if (xsane.xsane_mode == XSANE_COPY) + { + gamma_red = xsane.gamma_red * preferences.printer[preferences.printernr]->gamma_red; + gamma_green = xsane.gamma_green * preferences.printer[preferences.printernr]->gamma_green; + gamma_blue = xsane.gamma_blue * preferences.printer[preferences.printernr]->gamma_blue; + } + else + { + gamma_red = xsane.gamma_red; + gamma_green = xsane.gamma_green; + gamma_blue = xsane.gamma_blue; + } + + xsane_create_gamma_curve(xsane.gamma_data_red, 0, + gamma_red, xsane.brightness_red, xsane.contrast_red, + gamma_red_size, gamma_red_max); + + xsane_create_gamma_curve(xsane.gamma_data_green, 0, + gamma_green, xsane.brightness_green, xsane.contrast_green, + gamma_green_size, gamma_green_max); + + xsane_create_gamma_curve(xsane.gamma_data_blue, 0, + gamma_blue, xsane.brightness_blue, xsane.contrast_blue, + gamma_blue_size, gamma_blue_max); + + /* gamma tables are freed after scan */ + } + + } + else /* scanner does not support any gamma correction */ + { + /* ok, we have to do it on our own */ + + if (xsane.xsane_color == 0) /* no color scan */ + { + double gamma; + + if (xsane.xsane_mode == XSANE_COPY) + { + gamma = xsane.gamma * preferences.printer[preferences.printernr]->gamma; + } + else + { + gamma = xsane.gamma; + } + + xsane.gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int)); + xsane_create_gamma_curve(xsane.gamma_data, xsane.negative, + gamma, xsane.brightness, xsane.contrast, + gamma_gray_size, gamma_gray_max); + + /* gamma table is freed after scan */ + } + else /* color scan */ + { + double gamma_red, gamma_green, gamma_blue; + /* ok, we have to combin gray and color slider values */ + + xsane.gamma_data_red = malloc(gamma_red_size * sizeof(SANE_Int)); + xsane.gamma_data_green = malloc(gamma_green_size * sizeof(SANE_Int)); + xsane.gamma_data_blue = malloc(gamma_blue_size * sizeof(SANE_Int)); + + if (xsane.xsane_mode == XSANE_COPY) + { + gamma_red = xsane.gamma * xsane.gamma_red * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_red; + gamma_green = xsane.gamma * xsane.gamma_green * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_green; + gamma_blue = xsane.gamma * xsane.gamma_blue * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_blue; + } + else + { + gamma_red = xsane.gamma * xsane.gamma_red; + gamma_green = xsane.gamma * xsane.gamma_green; + gamma_blue = xsane.gamma * xsane.gamma_blue; + } + + xsane_create_gamma_curve(xsane.gamma_data_red, xsane.negative, + gamma_red, + xsane.brightness + xsane.brightness_red, + xsane.contrast + xsane.contrast_red, gamma_red_size, gamma_red_max); + + xsane_create_gamma_curve(xsane.gamma_data_green, xsane.negative, + gamma_green, + xsane.brightness + xsane.brightness_green, + xsane.contrast + xsane.contrast_green, gamma_green_size, gamma_green_max); + + xsane_create_gamma_curve(xsane.gamma_data_blue, xsane.negative, + gamma_blue, + xsane.brightness + xsane.brightness_blue, + xsane.contrast + xsane.contrast_blue , gamma_blue_size, gamma_blue_max); + + /* gamma tables are freed after scan */ + } + + } + } + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + xsane_start_scan(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + diff --git a/frontend/xsane-scan.h b/frontend/xsane-scan.h new file mode 100644 index 0000000..75c5ff8 --- /dev/null +++ b/frontend/xsane-scan.h @@ -0,0 +1,35 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-scan.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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 "sane/config.h" +#include <sane/sane.h> + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +extern void null_print_func(gchar *msg); +extern void xsane_scan_done(SANE_Status status); +extern void xsane_cancel(void); +extern void xsane_scan_dialog(GtkWidget * widget, gpointer call_data); + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-setup.c b/frontend/xsane-setup.c new file mode 100644 index 0000000..637ea91 --- /dev/null +++ b/frontend/xsane-setup.c @@ -0,0 +1,1565 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-setup.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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 "xsane-preferences.h" +#include "xsane-preview.h" +#include "xsane-save.h" +#include "xsane-text.h" +#include "xsane-gamma.h" + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ +#include <png.h> +#include <zlib.h> +#endif +#endif + +#ifdef HAVE_LIBTIFF +#include <tiff.h> +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#define XSANE_GTK_NAME_IMAGE_PERMISSIONS "gtk_toggle_button_image_permissions" +#define XSANE_GTK_NAME_DIRECTORY_PERMISSIONS "gtk_toggle_button_directory_permissions" + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +struct XsaneSetup xsane_setup; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* forward declarations: */ + +void xsane_new_printer(void); +void xsane_update_int(GtkWidget *widget, int *val); + +static void xsane_update_bool(GtkWidget *widget, int *val); +static void xsane_update_scale(GtkWidget *widget, double *val); +static void xsane_update_double(GtkWidget *widget, double *val); +static void xsane_setup_printer_update(void); +static void xsane_setup_printer_callback(GtkWidget *widget, gpointer data); +static void xsane_setup_printer_menu_build(GtkWidget *option_menu); +static void xsane_setup_printer_apply_changes(GtkWidget *widget, gpointer data); +static void xsane_setup_printer_new(GtkWidget *widget, gpointer data); +static void xsane_setup_printer_delete(GtkWidget *widget, gpointer data); +static void xsane_setup_display_apply_changes(GtkWidget *widget, gpointer data); +static void xsane_setup_saving_apply_changes(GtkWidget *widget, gpointer data); +static void xsane_setup_fax_apply_changes(GtkWidget *widget, gpointer data); +static void xsane_setup_options_ok_callback(GtkWidget *widget, gpointer data); + +void xsane_setup_dialog(GtkWidget *widget, gpointer data); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_new_printer(void) +{ + preferences.printernr = preferences.printerdefinitions++; + + preferences.printer[preferences.printernr] = calloc(sizeof(Preferences_printer_t), 1); + + preferences.printer[preferences.printernr]->name = strdup(PRINTERNAME); + preferences.printer[preferences.printernr]->command = strdup(PRINTERCOMMAND); + preferences.printer[preferences.printernr]->copy_number_option = strdup(PRINTERCOPYNUMBEROPTION); + preferences.printer[preferences.printernr]->resolution = 300; + preferences.printer[preferences.printernr]->width = 203.2; + preferences.printer[preferences.printernr]->height = 294.6; + preferences.printer[preferences.printernr]->leftoffset = 3.5; + preferences.printer[preferences.printernr]->bottomoffset = 3.5; + preferences.printer[preferences.printernr]->gamma = 1.0; + preferences.printer[preferences.printernr]->gamma_red = 1.0; + preferences.printer[preferences.printernr]->gamma_green = 1.0; + preferences.printer[preferences.printernr]->gamma_blue = 1.0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_update_int(GtkWidget *widget, int *val) +{ + char *start, *end; + int v; + + start = gtk_entry_get_text(GTK_ENTRY(widget)); + if (!start) + return; + + v = (int) strtol(start, &end, 10); + if (end > start && v > 0) + { + *val = v; + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_update_bool(GtkWidget *widget, int *val) +{ + *val = (GTK_TOGGLE_BUTTON(widget)->active != 0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_update_scale(GtkWidget *widget, double *val) +{ + *val = GTK_ADJUSTMENT(widget)->value; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_update_double(GtkWidget *widget, double *val) +{ + char *start, *end; + double v; + + start = gtk_entry_get_text(GTK_ENTRY(widget)); + if (!start) + return; + + v = strtod(start, &end); + if (end > start && v > 0.0) + { + *val = v; + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_printer_update() +{ + char buf[256]; + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_name_entry), + (char *) preferences.printer[preferences.printernr]->name); + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_command_entry), + (char *) preferences.printer[preferences.printernr]->command); + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_copy_number_option_entry), + (char *) preferences.printer[preferences.printernr]->copy_number_option); + + snprintf(buf, sizeof(buf), "%d", preferences.printer[preferences.printernr]->resolution); + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_resolution_entry), buf); + snprintf(buf, sizeof(buf), "%3.2f", preferences.printer[preferences.printernr]->width); + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_width_entry), buf); + snprintf(buf, sizeof(buf), "%3.2f", preferences.printer[preferences.printernr]->height); + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_height_entry), buf); + snprintf(buf, sizeof(buf), "%3.2f", preferences.printer[preferences.printernr]->leftoffset); + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_leftoffset_entry), buf); + snprintf(buf, sizeof(buf), "%3.2f", preferences.printer[preferences.printernr]->bottomoffset); + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_bottomoffset_entry), buf); + snprintf(buf, sizeof(buf), "%1.2f", preferences.printer[preferences.printernr]->gamma); + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_gamma_entry), buf); + snprintf(buf, sizeof(buf), "%1.2f", preferences.printer[preferences.printernr]->gamma_red); + gtk_entry_set_text(GTK_ENTRY(xsane_setup.printer_gamma_red_entry), buf); + snprintf(buf, sizeof(buf), "%1.2f", preferences.printer[preferences.printernr]->gamma_green); + 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); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_printer_callback(GtkWidget *widget, gpointer data) +{ + preferences.printernr = (int) data; + xsane_setup_printer_update(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_printer_menu_build(GtkWidget *option_menu) +{ + GtkWidget *printer_menu, *printer_item; + int i; + + printer_menu = gtk_menu_new(); + + for (i=0; i < preferences.printerdefinitions; i++) + { + printer_item = gtk_menu_item_new_with_label(preferences.printer[i]->name); + gtk_container_add(GTK_CONTAINER(printer_menu), printer_item); + gtk_signal_connect(GTK_OBJECT(printer_item), "activate", (GtkSignalFunc) xsane_setup_printer_callback, (void *) i); + gtk_widget_show(printer_item); + } + + gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), printer_menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), preferences.printernr); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_printer_apply_changes(GtkWidget *widget, gpointer data) +{ + GtkWidget *option_menu = (GtkWidget *) data; + + if (preferences.printer[preferences.printernr]->name) + { + free((void *) preferences.printer[preferences.printernr]->name); + } + preferences.printer[preferences.printernr]->name = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.printer_name_entry))); + + if (preferences.printer[preferences.printernr]->command) + { + free((void *) preferences.printer[preferences.printernr]->command); + } + preferences.printer[preferences.printernr]->command = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.printer_command_entry))); + + if (preferences.printer[preferences.printernr]->copy_number_option) + { + free((void *) preferences.printer[preferences.printernr]->copy_number_option); + } + preferences.printer[preferences.printernr]->copy_number_option = + strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.printer_copy_number_option_entry))); + + xsane_update_int(xsane_setup.printer_resolution_entry, &preferences.printer[preferences.printernr]->resolution); + + xsane_update_double(xsane_setup.printer_width_entry, &preferences.printer[preferences.printernr]->width); + xsane_update_double(xsane_setup.printer_height_entry, &preferences.printer[preferences.printernr]->height); + xsane_update_double(xsane_setup.printer_leftoffset_entry, &preferences.printer[preferences.printernr]->leftoffset); + xsane_update_double(xsane_setup.printer_bottomoffset_entry, &preferences.printer[preferences.printernr]->bottomoffset); + + xsane_update_double(xsane_setup.printer_gamma_entry, &preferences.printer[preferences.printernr]->gamma); + xsane_update_double(xsane_setup.printer_gamma_red_entry, &preferences.printer[preferences.printernr]->gamma_red); + 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); + + if (option_menu) + { + xsane_setup_printer_menu_build(option_menu); + } + + xsane_define_maximum_output_size(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_printer_new(GtkWidget *widget, gpointer data) +{ + GtkWidget *option_menu = (GtkWidget *) data; + + xsane_new_printer(); + xsane_setup_printer_update(); + + xsane_setup_printer_menu_build(option_menu); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_printer_delete(GtkWidget *widget, gpointer data) +{ + GtkWidget *option_menu = (GtkWidget *) data; + int i; + + preferences.printerdefinitions--; + + i = preferences.printernr; + while (i < preferences.printerdefinitions) + { + memcpy(preferences.printer[i], preferences.printer[i+1], sizeof(Preferences_printer_t)); + i++; + } + + if (preferences.printernr >= preferences.printerdefinitions) + { + preferences.printernr--; + } + + if (preferences.printerdefinitions == 0) + { + xsane_new_printer(); + preferences.printernr = 0; + } + + xsane_setup_printer_update(); + + xsane_setup_printer_menu_build(option_menu); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBTIFF +static void xsane_setup_tiff_compression_callback(GtkWidget *widget, gpointer data) +{ + xsane_setup.tiff_compression_nr = (int) data; +} + +/* -------------------------------------- */ + +static void xsane_setup_tiff_compression_1_callback(GtkWidget *widget, gpointer data) +{ + xsane_setup.tiff_compression_1_nr = (int) data; +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_display_apply_changes(GtkWidget *widget, gpointer data) +{ + xsane_update_bool(xsane_setup.main_window_fixed_button, &preferences.main_window_fixed); + xsane_update_bool(xsane_setup.preview_preserve_button, &preferences.preserve_preview); + xsane_update_bool(xsane_setup.preview_own_cmap_button, &preferences.preview_own_cmap); + + xsane_update_double(xsane_setup.preview_gamma_entry, &preferences.preview_gamma); + xsane_update_double(xsane_setup.preview_gamma_red_entry, &preferences.preview_gamma_red); + xsane_update_double(xsane_setup.preview_gamma_green_entry, &preferences.preview_gamma_green); + xsane_update_double(xsane_setup.preview_gamma_blue_entry, &preferences.preview_gamma_blue); + + preferences.doc_viewer = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.doc_viewer_entry))); + + xsane_update_gamma(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_saving_apply_changes(GtkWidget *widget, gpointer data) +{ +#ifdef HAVE_LIBJPEG + xsane_update_scale(xsane_setup.jpeg_image_quality_scale, &preferences.jpeg_quality); +#else +#ifdef HAVE_LIBTIFF + xsane_update_scale(xsane_setup.jpeg_image_quality_scale, &preferences.jpeg_quality); +#endif +#endif + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ + xsane_update_scale(xsane_setup.pnm_image_compression_scale, &preferences.png_compression); +#endif +#endif + +#ifdef HAVE_LIBTIFF + preferences.tiff_compression_nr = xsane_setup.tiff_compression_nr; + preferences.tiff_compression_1_nr = xsane_setup.tiff_compression_1_nr; +#endif + + xsane_update_bool(xsane_setup.overwrite_warning_button, &preferences.overwrite_warning); + xsane_update_bool(xsane_setup.increase_filename_counter_button, &preferences.increase_filename_counter); + xsane_update_bool(xsane_setup.skip_existing_numbers_button, &preferences.skip_existing_numbers); + preferences.image_umask = 0777 - xsane_setup.image_permissions; + preferences.directory_umask = 0777 - xsane_setup.directory_permissions; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_fax_apply_changes(GtkWidget *widget, gpointer data) +{ + if (preferences.fax_command) + { + free((void *) preferences.fax_command); + } + preferences.fax_command = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.fax_command_entry))); + preferences.fax_receiver_option = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.fax_receiver_option_entry))); + preferences.fax_postscript_option = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.fax_postscript_option_entry))); + preferences.fax_normal_option = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.fax_normal_option_entry))); + preferences.fax_fine_option = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.fax_fine_option_entry))); + preferences.fax_viewer = strdup(gtk_entry_get_text(GTK_ENTRY(xsane_setup.fax_viewer_entry))); + + xsane_update_double(xsane_setup.fax_leftoffset_entry, &preferences.fax_leftoffset); + xsane_update_double(xsane_setup.fax_bottomoffset_entry, &preferences.fax_bottomoffset); + xsane_update_double(xsane_setup.fax_width_entry, &preferences.fax_width); + xsane_update_double(xsane_setup.fax_height_entry, &preferences.fax_height); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_setup_options_ok_callback(GtkWidget *widget, gpointer data) +{ + xsane_setup_printer_apply_changes(0, 0); + xsane_setup_display_apply_changes(0, 0); + xsane_setup_saving_apply_changes(0, 0); + xsane_setup_fax_apply_changes(0, 0); + + xsane_pref_save(); + + gtk_widget_destroy((GtkWidget *)data); /* => xsane_destroy_setup_dialog_callback */ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_destroy_setup_dialog_callback(GtkWidget *widget, gpointer data) +{ + xsane_set_sensitivity(TRUE); + xsane_back_gtk_refresh_dialog(dialog); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_close_setup_dialog_callback(GtkWidget *widget, gpointer data) +{ + gtk_widget_destroy((GtkWidget *)data); /* => xsane_destroy_setup_dialog_callback */ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_permission_toggled(GtkWidget *widget, gpointer data) +{ + int mask = (int) data; + int *permission = 0; + gchar *name = gtk_widget_get_name(widget); + + if (!strcmp(name, XSANE_GTK_NAME_IMAGE_PERMISSIONS)) + { + permission = &xsane_setup.image_permissions; + } + else if (!strcmp(name, XSANE_GTK_NAME_DIRECTORY_PERMISSIONS)) + { + permission = &xsane_setup.directory_permissions; + } + + if (permission) + { + if (GTK_TOGGLE_BUTTON(widget)->active) /* set bit */ + { + *permission = *permission | mask; + } + else /* erase bit */ + { + *permission = *permission & (0777-mask); + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_permission_box(GtkWidget *parent, gchar *name, gchar *description, int *permission, + int header, int x_sensitivity, int user_sensitivity) +{ + GtkWidget *hbox, *button, *label, *hspace; + + + if (header) + { + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 2); + + label = gtk_label_new("user"); + gtk_widget_set_usize(label, 75, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + label = gtk_label_new("group"); + gtk_widget_set_usize(label, 75, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + label = gtk_label_new("all"); + gtk_widget_set_usize(label, 75, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + gtk_widget_show(hbox); + } + + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 2); + + button = gtk_toggle_button_new_with_label("r"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 256 ); + gtk_widget_set_usize(button, 21, 0); + gtk_widget_set_name(button, name); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 256); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_widget_show(button); + gtk_widget_set_sensitive(button, user_sensitivity); + + button = gtk_toggle_button_new_with_label("w"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 128 ); + gtk_widget_set_usize(button, 21, 0); + gtk_widget_set_name(button, name); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 128); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_widget_show(button); + gtk_widget_set_sensitive(button, user_sensitivity); + + button = gtk_toggle_button_new_with_label("x"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 64 ); + gtk_widget_set_usize(button, 21, 0); + gtk_widget_set_name(button, name); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 64); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_widget_show(button); + gtk_widget_set_sensitive(button, x_sensitivity & user_sensitivity); + + + + hspace = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), hspace, FALSE, FALSE, 6); + gtk_widget_show(hspace); + + + + button = gtk_toggle_button_new_with_label("r"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 32 ); + gtk_widget_set_usize(button, 21, 0); + gtk_widget_set_name(button, name); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 32); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_widget_show(button); + + button = gtk_toggle_button_new_with_label("w"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 16 ); + gtk_widget_set_usize(button, 21, 0); + gtk_widget_set_name(button, name); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 16); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_widget_show(button); + + button = gtk_toggle_button_new_with_label("x"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 8 ); + gtk_widget_set_usize(button, 21, 0); + gtk_widget_set_name(button, name); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 8); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_widget_show(button); + gtk_widget_set_sensitive(button, x_sensitivity); + + + + hspace = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), hspace, FALSE, FALSE, 6); + gtk_widget_show(hspace); + + + + button = gtk_toggle_button_new_with_label("r"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 4 ); + gtk_widget_set_usize(button, 21, 0); + gtk_widget_set_name(button, name); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 4); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_widget_show(button); + + button = gtk_toggle_button_new_with_label("w"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 2 ); + gtk_widget_set_usize(button, 21, 0); + gtk_widget_set_name(button, name); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 2); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_widget_show(button); + + button = gtk_toggle_button_new_with_label("x"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *permission & 1 ); + gtk_widget_set_usize(button, 21, 0); + gtk_widget_set_name(button, name); + gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_permission_toggled, (void *) 1); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_widget_show(button); + gtk_widget_set_sensitive(button, x_sensitivity); + + + + hspace = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), hspace, FALSE, FALSE, 5); + gtk_widget_show(hspace); + + + + label = gtk_label_new(description); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + gtk_widget_show(hbox); + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_setup_dialog(GtkWidget *widget, gpointer data) +{ + GtkWidget *setup_dialog, *setup_vbox, *vbox, *hbox, *button, *label, *text, *frame, *notebook; + GtkWidget *printer_option_menu; + char buf[64]; + +#ifdef HAVE_LIBTIFF + GtkWidget *tiff_compression_option_menu, *tiff_compression_menu, *tiff_compression_item; + int i, select = 1; + + typedef struct tiff_compression_t + { + char *name; + int number; + } tiff_compression; + +#define TIFF_COMPRESSION_NUMBER 3 +#define TIFF_COMPRESSION1_NUMBER 6 + + tiff_compression tiff_compression_strings[TIFF_COMPRESSION_NUMBER]; + tiff_compression tiff_compression1_strings[TIFF_COMPRESSION1_NUMBER]; + + tiff_compression_strings[0].name = MENU_ITEM_TIFF_COMP_NONE; + tiff_compression_strings[0].number = COMPRESSION_NONE; + tiff_compression_strings[1].name = MENU_ITEM_TIFF_COMP_JPEG; + tiff_compression_strings[1].number = COMPRESSION_JPEG; + tiff_compression_strings[2].name = MENU_ITEM_TIFF_COMP_PACKBITS; + tiff_compression_strings[2].number = COMPRESSION_PACKBITS; + + tiff_compression1_strings[0].name = MENU_ITEM_TIFF_COMP_NONE; + tiff_compression1_strings[0].number = COMPRESSION_NONE; + tiff_compression1_strings[1].name = MENU_ITEM_TIFF_COMP_CCITTRLE; + tiff_compression1_strings[1].number = COMPRESSION_CCITTRLE; + tiff_compression1_strings[2].name = MENU_ITEM_TIFF_COMP_CCITFAX3; + tiff_compression1_strings[2].number = COMPRESSION_CCITTFAX3; + tiff_compression1_strings[3].name = MENU_ITEM_TIFF_COMP_CCITFAX4; + tiff_compression1_strings[3].number = COMPRESSION_CCITTFAX4; + tiff_compression1_strings[4].name = MENU_ITEM_TIFF_COMP_JPEG; + tiff_compression1_strings[4].number = COMPRESSION_JPEG; + tiff_compression1_strings[5].name = MENU_ITEM_TIFF_COMP_PACKBITS; + tiff_compression1_strings[5].number = COMPRESSION_PACKBITS; + +#endif /* HAVE_LIBTIFF */ + + xsane_set_sensitivity(FALSE); + + setup_dialog = gtk_dialog_new(); + snprintf(buf, sizeof(buf), "%s %s", prog_name, WINDOW_SETUP); + gtk_window_set_title(GTK_WINDOW(setup_dialog), buf); + gtk_signal_connect(GTK_OBJECT(setup_dialog), "destroy", (GtkSignalFunc) xsane_destroy_setup_dialog_callback, setup_dialog); + xsane_set_window_icon(setup_dialog, 0); + + setup_vbox = GTK_DIALOG(setup_dialog)->vbox; + + notebook = gtk_notebook_new(); + gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP); + gtk_box_pack_start(GTK_BOX(setup_vbox), notebook, FALSE, FALSE, 0); + gtk_widget_show(notebook); + + + + + /* Printer options notebook page */ + + setup_vbox = gtk_vbox_new(FALSE, 5); + + label = gtk_label_new(NOTEBOOK_COPY_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), 4); + 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); + + + + 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(TEXT_SETUP_PRINTER_SEL); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + printer_option_menu = gtk_option_menu_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, printer_option_menu, DESC_PRINTER_SETUP); + gtk_box_pack_end(GTK_BOX(hbox), printer_option_menu, FALSE, FALSE, 2); + gtk_widget_show(printer_option_menu); + gtk_widget_show(hbox); + + xsane_setup_printer_menu_build(printer_option_menu); + + /* printername : */ + + 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_NAME); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_NAME); + gtk_widget_set_usize(text, 250, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.printer[preferences.printernr]->name); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_name_entry = text; + + /* printcommand : */ + + 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_CMD); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_COMMAND); + gtk_widget_set_usize(text, 250, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.printer[preferences.printernr]->command); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_command_entry = text; + + /* copy number option : */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_COPY_NR_OPT); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_COPY_NUMBER_OPTION); + gtk_widget_set_usize(text, 250, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.printer[preferences.printernr]->copy_number_option); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_copy_number_option_entry = text; + + /* printerresolution : */ + + 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_RES); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_RESOLUTION); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%d", preferences.printer[preferences.printernr]->resolution); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_resolution_entry = text; + + + xsane_separator_new(vbox, 2); + + + /* printer width: */ + + 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_WIDTH); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_WIDTH); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%3.2f", preferences.printer[preferences.printernr]->width); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_width_entry = text; + + /* printer height: */ + + 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_HEIGHT); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_HEIGHT); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%3.2f", preferences.printer[preferences.printernr]->height); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_height_entry = text; + + /* printer left offset : */ + + 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_LEFT); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_LEFTOFFSET); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%3.2f", preferences.printer[preferences.printernr]->leftoffset); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_leftoffset_entry = text; + + /* printer bottom offset : */ + + 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_BOTTOM); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_BOTTOMOFFSET); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%3.2f", preferences.printer[preferences.printernr]->bottomoffset); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_bottomoffset_entry = text; + + + xsane_separator_new(vbox, 2); + + + /* printer gamma: */ + + 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_GAMMA); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_GAMMA); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%1.2f", preferences.printer[preferences.printernr]->gamma); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_gamma_entry = text; + + /* printer gamma red: */ + + 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_GAMMA_RED); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_GAMMA_RED); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%1.2f", preferences.printer[preferences.printernr]->gamma_red); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_gamma_red_entry = text; + + /* printer gamma green: */ + + 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_GAMMA_GREEN); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_GAMMA_GREEN); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%1.2f", preferences.printer[preferences.printernr]->gamma_green); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_gamma_green_entry = text; + + /* printer gamma blue: */ + + 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_GAMMA_BLUE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PRINTER_GAMMA_BLUE); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%1.2f", preferences.printer[preferences.printernr]->gamma_blue); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.printer_gamma_blue_entry = text; + + + xsane_separator_new(vbox, 4); + + /* "apply" "add printer" "delete printer" */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + button = gtk_button_new_with_label(BUTTON_APPLY); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_printer_apply_changes, printer_option_menu); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + button = gtk_button_new_with_label(BUTTON_ADD_PRINTER); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_printer_new, printer_option_menu); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + button = gtk_button_new_with_label(BUTTON_DELETE_PRINTER); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_printer_delete, printer_option_menu); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + gtk_widget_show(hbox); + + + + + /* Saving options notebook page */ + + setup_vbox = gtk_vbox_new(FALSE, 5); + + label = gtk_label_new(NOTEBOOK_SAVING_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), 4); + 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); + + xsane_setup.image_permissions = 0777-preferences.image_umask; + xsane_permission_box(vbox, XSANE_GTK_NAME_IMAGE_PERMISSIONS, "Image-file permissions", &xsane_setup.image_permissions, + TRUE /* header */, FALSE /* x sens */, FALSE /* user sens */); + + xsane_setup.directory_permissions = 0777-preferences.directory_umask; + xsane_permission_box(vbox, XSANE_GTK_NAME_DIRECTORY_PERMISSIONS, "Directory permissions", &xsane_setup.directory_permissions, + FALSE /* header */, TRUE /* x sens */, FALSE /* user sens */); + + xsane_separator_new(vbox, 4); + + + /* overwrite warning */ + 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_OVERWRITE_WARNING); + xsane_back_gtk_set_tooltip(dialog->tooltips, button, DESC_OVERWRITE_WARNING); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.overwrite_warning); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); + gtk_widget_show(button); + gtk_widget_show(hbox); + xsane_setup.overwrite_warning_button = button; + + /* increase filename counter */ + 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_INCREASE_COUNTER); + xsane_back_gtk_set_tooltip(dialog->tooltips, button, DESC_INCREASE_COUNTER); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.increase_filename_counter); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); + gtk_widget_show(button); + gtk_widget_show(hbox); + xsane_setup.increase_filename_counter_button = button; + + /* increase filename counter */ + 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_SKIP_EXISTING_NRS); + xsane_back_gtk_set_tooltip(dialog->tooltips, button, DESC_SKIP_EXISTING); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.skip_existing_numbers); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); + gtk_widget_show(button); + gtk_widget_show(hbox); + xsane_setup.skip_existing_numbers_button = button; + +#ifdef HAVE_LIBJPEG + xsane_separator_new(vbox, 4); +#else +#ifdef HAVE_LIBTIFF + xsane_separator_new(vbox, 4); +#else +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ + xsane_separator_new(vbox, 4); +#endif +#endif +#endif +#endif + +#ifdef HAVE_LIBJPEG + xsane_scale_new(GTK_BOX(vbox), TEXT_SETUP_JPEG_QUALITY, DESC_JPEG_QUALITY, 0.0, 100.0, 1.0, 1.0, 0.0, 0, + &preferences.jpeg_quality, (GtkObject **) &xsane_setup.jpeg_image_quality_scale, 0, TRUE); +#else +#ifdef HAVE_LIBTIFF + xsane_scale_new(GTK_BOX(vbox), TEXT_SETUP_JPEG_QUALITY, DESC_JPEG_QUALITY, 0.0, 100.0, 1.0, 1.0, 0.0, 0, + &preferences.jpeg_quality, (GtkObject **) &xsane_setup.jpeg_image_quality_scale, 0, TRUE); +#endif +#endif + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ + xsane_scale_new(GTK_BOX(vbox), TEXT_SETUP_PNG_COMPRESSION, DESC_PNG_COMPRESSION, 0.0, Z_BEST_COMPRESSION, 1.0, 1.0, 0.0, 0, + &preferences.png_compression, (GtkObject **) &xsane_setup.pnm_image_compression_scale, 0, TRUE); +#endif +#endif + +#ifdef HAVE_LIBTIFF + /* TIFF MULTI BIT IMAGES COMPRESSION */ + + 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(TEXT_SETUP_TIFF_COMPRESSION); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + tiff_compression_option_menu = gtk_option_menu_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, tiff_compression_option_menu, DESC_TIFF_COMPRESSION); + gtk_box_pack_end(GTK_BOX(hbox), tiff_compression_option_menu, FALSE, FALSE, 2); + gtk_widget_show(tiff_compression_option_menu); + gtk_widget_show(hbox); + + tiff_compression_menu = gtk_menu_new(); + + for (i=1; i <= TIFF_COMPRESSION_NUMBER; i++) + { + tiff_compression_item = gtk_menu_item_new_with_label(tiff_compression_strings[i-1].name); + gtk_container_add(GTK_CONTAINER(tiff_compression_menu), tiff_compression_item); + gtk_signal_connect(GTK_OBJECT(tiff_compression_item), "activate", + (GtkSignalFunc) xsane_setup_tiff_compression_callback, (void *) tiff_compression_strings[i-1].number); + gtk_widget_show(tiff_compression_item); + if (tiff_compression_strings[i-1].number == preferences.tiff_compression_nr) + { + select = i-1; + } + } + + + gtk_option_menu_set_menu(GTK_OPTION_MENU(tiff_compression_option_menu), tiff_compression_menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(tiff_compression_option_menu), select); + xsane_setup.tiff_compression_nr = preferences.tiff_compression_nr; + + + /* TIFF ONE BIT IMAGES COMPRESSION */ + + 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(TEXT_SETUP_TIFF_COMPRESSION_1); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + tiff_compression_option_menu = gtk_option_menu_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, tiff_compression_option_menu, DESC_TIFF_COMPRESSION_1); + gtk_box_pack_end(GTK_BOX(hbox), tiff_compression_option_menu, FALSE, FALSE, 2); + gtk_widget_show(tiff_compression_option_menu); + gtk_widget_show(hbox); + + tiff_compression_menu = gtk_menu_new(); + + for (i=1; i <= TIFF_COMPRESSION1_NUMBER; i++) + { + tiff_compression_item = gtk_menu_item_new_with_label(tiff_compression1_strings[i-1].name); + gtk_container_add(GTK_CONTAINER(tiff_compression_menu), tiff_compression_item); + gtk_signal_connect(GTK_OBJECT(tiff_compression_item), "activate", + (GtkSignalFunc) xsane_setup_tiff_compression_1_callback, (void *) tiff_compression1_strings[i-1].number); + gtk_widget_show(tiff_compression_item); + if (tiff_compression1_strings[i-1].number == preferences.tiff_compression_1_nr) + { + select = i-1; + } + } + + gtk_option_menu_set_menu(GTK_OPTION_MENU(tiff_compression_option_menu), tiff_compression_menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(tiff_compression_option_menu), select); + + xsane_setup.tiff_compression_1_nr = preferences.tiff_compression_1_nr; + +#endif + + 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); + + button = gtk_button_new_with_label(BUTTON_APPLY); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_saving_apply_changes, 0); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + gtk_widget_show(hbox); + + + + + + /* Display options notebook page */ + + setup_vbox = gtk_vbox_new(FALSE, 5); + + label = gtk_label_new(NOTEBOOK_DISPLAY_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), 4); + 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); + + /* main window fixed: */ + + 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_WINDOW_FIXED); + xsane_back_gtk_set_tooltip(dialog->tooltips, button, DESC_MAIN_WINDOW_FIXED); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.main_window_fixed); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); + gtk_widget_show(button); + gtk_widget_show(hbox); + xsane_setup.main_window_fixed_button = button; + + + /* preserve preview image: */ + + 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_PRESERVE_PRVIEW); + xsane_back_gtk_set_tooltip(dialog->tooltips, button, DESC_PREVIEW_PRESERVE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.preserve_preview); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); + gtk_widget_show(button); + gtk_widget_show(hbox); + xsane_setup.preview_preserve_button = button; + + + /* private colormap: */ + + 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_PRIVATE_COLORMAP); + xsane_back_gtk_set_tooltip(dialog->tooltips, button, DESC_PREVIEW_COLORMAP); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), preferences.preview_own_cmap); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 2); + gtk_widget_show(button); + gtk_widget_show(hbox); + xsane_setup.preview_own_cmap_button = button; + + + xsane_separator_new(vbox, 2); + + + /* preview gamma correction value: */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show(hbox); + + label = gtk_label_new(TEXT_SETUP_PREVIEW_GAMMA); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + snprintf(buf, sizeof(buf), "%1.2f", preferences.preview_gamma); + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PREVIEW_GAMMA); + gtk_widget_set_usize(text, 50, 0); + gtk_entry_set_text(GTK_ENTRY(text), buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + xsane_setup.preview_gamma_entry = text; + + /* red preview gamma correction value: */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show(hbox); + + label = gtk_label_new(TEXT_SETUP_PREVIEW_GAMMA_RED); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + snprintf(buf, sizeof(buf), "%1.2f", preferences.preview_gamma_red); + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PREVIEW_GAMMA_RED); + gtk_widget_set_usize(text, 50, 0); + gtk_entry_set_text(GTK_ENTRY(text), buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + xsane_setup.preview_gamma_red_entry = text; + + /* green preview gamma correction value: */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show(hbox); + + label = gtk_label_new(TEXT_SETUP_PREVIEW_GAMMA_GREEN); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + snprintf(buf, sizeof(buf), "%1.2f", preferences.preview_gamma_green); + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PREVIEW_GAMMA_GREEN); + gtk_widget_set_usize(text, 50, 0); + gtk_entry_set_text(GTK_ENTRY(text), buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + xsane_setup.preview_gamma_green_entry = text; + + /* blue preview gamma correction value: */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show(hbox); + + label = gtk_label_new(TEXT_SETUP_PREVIEW_GAMMA_BLUE); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + snprintf(buf, sizeof(buf), "%1.2f", preferences.preview_gamma_blue); + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_PREVIEW_GAMMA_BLUE); + gtk_widget_set_usize(text, 50, 0); + gtk_entry_set_text(GTK_ENTRY(text), buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + xsane_setup.preview_gamma_blue_entry = text; + + + xsane_separator_new(vbox, 2); + + + /* docviewer */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_HELPFILE_VIEWER); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_DOC_VIEWER); + gtk_widget_set_usize(text, 250, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.doc_viewer); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.doc_viewer_entry = text; + + + 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); + + button = gtk_button_new_with_label(BUTTON_APPLY); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_display_apply_changes, 0); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + gtk_widget_show(hbox); + + + + + /* Fax options notebook page */ + + setup_vbox = gtk_vbox_new(FALSE, 5); + + label = gtk_label_new(NOTEBOOK_FAX_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), 4); + 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); + + /* faxcommand : */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_COMMAND); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_COMMAND); + gtk_widget_set_usize(text, 250, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.fax_command); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_command_entry = text; + + + /* fax receiver option: */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_RECEIVER_OPTION); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_RECEIVER_OPT); + gtk_widget_set_usize(text, 50, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.fax_receiver_option); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_receiver_option_entry = text; + + +/* fax postscript option: */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_POSTSCRIPT_OPT); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_POSTSCRIPT_OPT); + gtk_widget_set_usize(text, 50, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.fax_postscript_option); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_postscript_option_entry = text; + + + /* fax normal mode option : */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_NORMAL_MODE_OPT); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_NORMAL_OPT); + gtk_widget_set_usize(text, 50, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.fax_normal_option); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_normal_option_entry = text; + + + /* fax fine mode option : */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_FINE_MODE_OPT); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_FINE_OPT); + gtk_widget_set_usize(text, 50, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.fax_fine_option); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_fine_option_entry = text; + + + xsane_separator_new(vbox, 2); + + + /* faxviewer */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_VIEWER); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_VIEWER); + gtk_widget_set_usize(text, 250, 0); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.fax_viewer); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_viewer_entry = text; + + + xsane_separator_new(vbox, 4); + + /* fax width: */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_WIDTH); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_WIDTH); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%3.2f", preferences.fax_width); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_width_entry = text; + + /* fax height: */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_HEIGHT); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_HEIGHT); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%3.2f", preferences.fax_height); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_height_entry = text; + + /* fax left offset : */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_LEFT); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_LEFTOFFSET); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%3.2f", preferences.fax_leftoffset); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_leftoffset_entry = text; + + /* fax bottom offset : */ + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + label = gtk_label_new(TEXT_SETUP_FAX_BOTTOM); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); + gtk_widget_show(label); + + text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAX_BOTTOMOFFSET); + gtk_widget_set_usize(text, 50, 0); + snprintf(buf, sizeof(buf), "%3.2f", preferences.fax_bottomoffset); + gtk_entry_set_text(GTK_ENTRY(text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), text, FALSE, FALSE, 2); + gtk_widget_show(text); + gtk_widget_show(hbox); + xsane_setup.fax_bottomoffset_entry = text; + + 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); + + button = gtk_button_new_with_label(BUTTON_APPLY); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_setup_fax_apply_changes, 0); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + gtk_widget_show(hbox); + + + + + /* fill in action area: */ + hbox = GTK_DIALOG(setup_dialog)->action_area; + + button = gtk_button_new_with_label(BUTTON_OK); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_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); + + button = gtk_button_new_with_label(BUTTON_CANCEL); + gtk_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_show(button); + + gtk_widget_show(setup_dialog); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-setup.h b/frontend/xsane-setup.h new file mode 100644 index 0000000..411faa8 --- /dev/null +++ b/frontend/xsane-setup.h @@ -0,0 +1,33 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-setup.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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 <sane/sane.h> + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +extern void xsane_new_printer(void); +extern void xsane_update_int(GtkWidget *widget, int *val); +extern void xsane_setup_dialog(GtkWidget *widget, gpointer data); + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane-style.rc b/frontend/xsane-style.rc new file mode 100644 index 0000000..de6662d --- /dev/null +++ b/frontend/xsane-style.rc @@ -0,0 +1,34 @@ +# style <name> [= <name>] +# { +# <option> +# } +# +# widget <widget_set> style <style_name> +# widget_class <widget_class_set> style <style_name> +# accelerator <widget_name> <accelerator> + +style "progressbar" +{ + bg[PRELIGHT] = { 22500, 53280, 22500 } # green +} + +style "curve" +{ + fg[NORMAL] = { 58000, 0, 0 } # red +} + +style "font" +{ + font = "-*-helvetica-medium-r-*-*-10-*-*-*-*-*-*-*" +} + +style "fixed font" +{ + font = "-misc-fixed-medium-r-semicondensed--13-*-*-*-*-*-*-*" +} + +widget "*GtkCurve" style "curve" +widget "*GtkProgressBar" style "progressbar" +# widget "*" style "font" +widget "*GtkRadioButton*" style "fixed font" + diff --git a/frontend/xsane-text.h b/frontend/xsane-text.h new file mode 100644 index 0000000..5cc3367 --- /dev/null +++ b/frontend/xsane-text.h @@ -0,0 +1,417 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane-text.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ------------------------------------------------------------------------ */ + +#ifndef XSANE_TEXT_H +#define XSANE_TEXT_H + +#define XSANE_STRSTATUS(status) _(sane_strstatus(status)) +#define _BGT(text) dgettext(xsane.backend, text) + +#define WINDOW_ABOUT _("About") +#define WINDOW_AUTHORIZE _("authorization") +#define WINDOW_INFO _("info") +#define WINDOW_BATCH_SCAN _("batch scan") +#define WINDOW_FAX_PROJECT _("fax project") +#define WINDOW_FAX_RENAME _("rename fax page") +#define WINDOW_SETUP _("setup") +#define WINDOW_HISTOGRAM _("Histogram") +#define WINDOW_STANDARD_OPTIONS _("Standard options") +#define WINDOW_ADVANCED_OPTIONS _("Advanced options") +#define WINDOW_DEVICE_SELECTION _("device selection") +#define WINDOW_PREVIEW _("Preview") +#define WINDOW_OUTPUT_FILENAME _("output filename") +#define WINDOW_SAVE_SETTINGS _("save device settings") +#define WINDOW_LOAD_SETTINGS _("load device settings") + +#define MENU_FILE _("File") +#define MENU_PREFERENCES _("Preferences") +#define MENU_VIEW _("View") +#define MENU_HELP _("Help") + +#define MENU_ITEM_ABOUT _("About") +#define MENU_ITEM_INFO _("Info") +#define MENU_ITEM_EXIT _("Exit") + +#define FRAME_RAW_IMAGE _("Raw image") +#define FRAME_ENHANCED_IMAGE _("Enhanced image") + +#define BUTTON_START _("Start") +#define BUTTON_OK _("Ok") +#define BUTTON_APPLY _("Apply") +#define BUTTON_CANCEL _("Cancel") +#define BUTTON_CLOSE _("Close") +#define BUTTON_OVERWRITE _("Overwrite") +#define BUTTON_ADD_AREA _("Add area") +#define BUTTON_DELETE _("Delete") +#define BUTTON_SHOW _("Show") +#define BUTTON_RENAME _("Rename") +#define BUTTON_CREATE_PROJECT _("Create project") +#define BUTTON_SEND_PROJECT _("Send project") +#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 RADIO_BUTTON_FINE_MODE _("Fine mode") +#define RADIO_BUTTON_OVERWRITE_WARNING _("Overwrite warning") +#define RADIO_BUTTON_INCREASE_COUNTER _("Increase filename counter") +#define RADIO_BUTTON_SKIP_EXISTING_NRS _("Skip existing numbers") +#define RADIO_BUTTON_WINDOW_FIXED _("Main window size fixed") +#define RADIO_BUTTON_PRESERVE_PRVIEW _("Preserve preview image") +#define RADIO_BUTTON_PRIVATE_COLORMAP _("Use private colormap") + +#define TEXT_AVAILABLE_DEVICES _("Available devices:") +#define TEXT_XSANE_OPTIONS _("XSane options") +#define TEXT_XSANE_MODE _("XSane mode") +#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_AUTHORIZATION_REQ _("Authorization required for") +#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_GIMP_VERSION _("compiled with GIMP-") +#define TEXT_UNKNOWN _("unknown") +#define TEXT_EMAIL _("Email:") +#define TEXT_FILE _("File:") + +#define TEXT_INFO_BOX _("0x0: 0KB") + +#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_RES _("Resolution (dpi):") +#define TEXT_SETUP_PRINTER_WIDTH _("Width [mm]:") +#define TEXT_SETUP_PRINTER_HEIGHT _("Height [mm]:") +#define TEXT_SETUP_PRINTER_LEFT _("Left offset [mm]:") +#define TEXT_SETUP_PRINTER_BOTTOM _("Bottom offset [mm]:") +#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_JPEG_QUALITY _("JPEG image quality") +#define TEXT_SETUP_PNG_COMPRESSION _("PNG image compression") +#define TEXT_SETUP_TIFF_COMPRESSION _("TIFF multi bit image compression") +#define TEXT_SETUP_TIFF_COMPRESSION_1 _("TIFF lineart image compression") +#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_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_VIEWER _("Viewer (Postscript):") +#define TEXT_SETUP_FAX_WIDTH _("Width [mm]:") +#define TEXT_SETUP_FAX_HEIGHT _("Height [mm]:") +#define TEXT_SETUP_FAX_LEFT _("Left offset [mm]:") +#define TEXT_SETUP_FAX_BOTTOM _("Bottom offset [mm]:") + +#define NOTEBOOK_COPY_OPTIONS _("Copy options") +#define NOTEBOOK_SAVING_OPTIONS _("Saving options") +#define NOTEBOOK_DISPLAY_OPTIONS _("Display options") +#define NOTEBOOK_FAX_OPTIONS _("Fax options") + +#define MENU_ITEM_SCAN _("Scan") +#define MENU_ITEM_COPY _("Copy") +#define MENU_ITEM_FAX _("Fax") + +#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_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_SAVE_DEVICE_SETTINGS _("Save device settings") +#define MENU_ITEM_LOAD_DEVICE_SETTINGS _("Load device settings") + +#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_TIFF_COMP_NONE _("no compression") +#define MENU_ITEM_TIFF_COMP_CCITTRLE _("CCITT 1D Huffman compression") +#define MENU_ITEM_TIFF_COMP_CCITFAX3 _("CCITT Group 3 Fax compression") +#define MENU_ITEM_TIFF_COMP_CCITFAX4 _("CCITT Group 4 Fax compression") +#define MENU_ITEM_TIFF_COMP_JPEG _("JPEG DCT compression") +#define MENU_ITEM_TIFF_COMP_PACKBITS _("pack bits") + +#define MENU_ITEM_FILETYPE_JPEG _(".jpeg") +#define MENU_ITEM_FILETYPE_PNG _(".png") +#define MENU_ITEM_FILETYPE_PNM _(".pnm") +#define MENU_ITEM_FILETYPE_PS _(".ps") +#define MENU_ITEM_FILETYPE_RAW _(".raw") +#define MENU_ITEM_FILETYPE_TIFF _(".tiff") +#define MENU_ITEM_FILETYPE_BY_EXT _("by ext") + +#define PROGRESS_SAVING _("Saving image") +#define PROGRESS_SAVING_FAX _("Saving fax image") +#define PROGRESS_CONVERTING_DATA _("Converting data....") +#define PROGRESS_CONVERTING_PS _("Converting to postscript") +#define PROGRESS_SCANNING _("Scanning") +#define PROGRESS_RECEIVING_SCAN _("Receiving %s data for `%s'...") +#define PROGRESS_RECEIVING_COPY _("Receiving %s data for photocopy ...") +#define PROGRESS_RECEIVING_FAX _("Receiving %s data for fax ...") +#define PROGRESS_RECEIVING_GIMP _("Receiving %s data for GIMP...") + + +#define DESC_XSANE_MODE _("Use XSane for SCANning, photoCOPYing, FAXing...") + +#define DESC_BROWSE_FILENAME _("Browse for image filename") +#define DESC_FILENAME _("Filename for scanned image") +#define DESC_FILETYPE _("Filename extension and type of image format") +#define DESC_FAXPROJECT _("Enter name of fax project") +#define DESC_FAXPAGENAME _("Enter new name for faxpage") +#define DESC_FAXRECEIVER _("Enter receiver phone number or address") + +#define DESC_PRINTER_SELECT _("Select printer definition") + +#define DESC_RESOLUTION _("Set scan resolution") +#define DESC_RESOLUTION_X _("Set scan resolution for x direction") +#define DESC_RESOLUTION_Y _("Set scan resolution for y direction") +#define DESC_ZOOM _("Set zoomfactor") +#define DESC_ZOOM_X _("Set zoomfactor for x direction") +#define DESC_ZOOM_Y _("Set zoomfactor for y direction") +#define DESC_COPY_NUMBER _("Set number of copies") + +#define DESC_NEGATIVE _("Negative: Invert colors for scanning negatives\n" \ + "e.g. swap black and white") + +#define DESC_GAMMA _("Set gamma value") +#define DESC_GAMMA_R _("Set gamma value for red component") +#define DESC_GAMMA_G _("Set gamma value for green component") +#define DESC_GAMMA_B _("Set gamma value for blue component") + +#define DESC_BRIGHTNESS _("Set brightness") +#define DESC_BRIGHTNESS_R _("Set brightness for red component") +#define DESC_BRIGHTNESS_G _("Set brightness for green component") +#define DESC_BRIGHTNESS_B _("Set brightness for blue component") + +#define DESC_CONTRAST _("Set contrast") +#define DESC_CONTRAST_R _("Set contrast for red component") +#define DESC_CONTRAST_G _("Set contrast for green component") +#define DESC_CONTRAST_B _("Set contrast for blue component") + +#define DESC_RGB_DEFAULT _("RGB default: Set enhancement values for red, green and blue to default values:\n" \ + " gamma = 1.0\n" \ + " brightness = 0\n" \ + " contrast = 0") + +#define DESC_ENH_AUTO _("Autoadjust gamma, brightness and contrast in dependance of selected area") +#define DESC_ENH_DEFAULT _("Set default enhancement values:\n" \ + "gamma = 1.0\n" \ + "brightness = 0\n" \ + "contrast = 0") +#define DESC_ENH_RESTORE _("Restore enhancement values from preferences") +#define DESC_ENH_STORE _("Store active enhancement values to preferences") + +#define DESC_HIST_INTENSITY _("Show histogram of intensity/gray") +#define DESC_HIST_RED _("Show histogram of red component") +#define DESC_HIST_GREEN _("Show histogram of green component") +#define DESC_HIST_BLUE _("Show histogram of blue component") +#define DESC_HIST_PIXEL _("Display histogram with lines instead of pixels") +#define DESC_HIST_LOG _("Show logarithm of pixelcount") + +#define DESC_PRINTER_SETUP _("Select definition to change") +#define DESC_PRINTER_NAME _("Define a name for the selection of this definition") +#define DESC_PRINTER_COMMAND _("Enter command to be executed in copy mode (e.g. \"lpr -\")") +#define DESC_COPY_NUMBER_OPTION _("Enter option for copy numbers") +#define DESC_PRINTER_RESOLUTION _("Resolution with which images are printed and saved in postscript") +#define DESC_PRINTER_WIDTH _("Width of printable area in mm") +#define DESC_PRINTER_HEIGHT _("Height of printable area in mm") +#define DESC_PRINTER_LEFTOFFSET _("Left offset from the edge of the paper to the printable area in mm") +#define DESC_PRINTER_BOTTOMOFFSET _("Bottom offset from the edge of the paper to the printable area in mm") +#define DESC_PRINTER_GAMMA _("Additional gamma value for photocopy") +#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_JPEG_QUALITY _("Quality in percent if image is saved as jpeg or tiff with jpeg compression") +#define DESC_PNG_COMPRESSION _("Compression if image is saved as png") +#define DESC_TIFF_COMPRESSION _("Compression type if multi bit image is saved as tiff") +#define DESC_TIFF_COMPRESSION_1 _("Compression type if lineart image is saved as tiff") +#define DESC_OVERWRITE_WARNING _("Warn before overwriting an existing file") +#define DESC_INCREASE_COUNTER _("If the filename is of the form \"name-001.ext\" " \ + "(where the number of digits is free) " \ + "the number is increased after a scan is finished") +#define DESC_SKIP_EXISTING _("If filename counter is automatically increased, used numbers are skipped") +#define DESC_MAIN_WINDOW_FIXED _("Use fixed main window size or scrolled, resizable main window") +#define DESC_PREVIEW_PRESERVE _("Preserve preview image for next program start") +#define DESC_PREVIEW_COLORMAP _("Use an own colormap for preview if display depth is 8 bpp") +#define DESC_PREVIEW_GAMMA _("Set gamma correction value for preview image") +#define DESC_PREVIEW_GAMMA_RED _("Set gamma correction value for red component of preview image") +#define DESC_PREVIEW_GAMMA_GREEN _("Set gamma correction value for green component of preview image") +#define DESC_PREVIEW_GAMMA_BLUE _("Set gamma correction value for blue component of preview image") +#define DESC_DOC_VIEWER _("Enter command to be executed to display helpfiles, must be a html-viewer!") + +#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") +#define DESC_FAX_NORMAL_OPT _("Enter option to specify normal mode (low resolution)") +#define DESC_FAX_FINE_OPT _("Enter option to specify fine mode (high resolution)") +#define DESC_FAX_VIEWER _("Enter command to be executed to view a fax") +#define DESC_FAX_FINE_MODE _("Use high vertical resolution (196 lpi instead of 98 lpi)") +#define DESC_FAX_WIDTH _("Width of printable area in mm") +#define DESC_FAX_HEIGHT _("Height of printable area in mm") +#define DESC_FAX_LEFTOFFSET _("Left offset from the edge of the paper to the printable area in mm") +#define DESC_FAX_BOTTOMOFFSET _("Bottom offset from the edge of the paper to the printable area in mm") + +#define DESC_PIPETTE_WHITE _("Pick white point") +#define DESC_PIPETTE_GRAY _("Pick gray point") +#define DESC_PIPETTE_BLACK _("Pick black point") + +#define DESC_ZOOM_FULL _("Use full scanarea") +#define DESC_ZOOM_OUT _("Zoom 20% out") +#define DESC_ZOOM_IN _("Zoom into selected area") +#define DESC_ZOOM_UNDO _("Undo last zoom") + +#define DESC_FULL_PREVIEW_AREA _("Select visible area") + + +#define ERR_HOME_DIR _("Failed to determine home directory:") +#define ERR_FILENAME_TOO_LONG _("Filename too long") +#define ERR_SET_OPTION _("Failed to set value of option") +#define ERR_GET_OPTION _("Failed to obtain value of option") +#define ERR_OPTION_COUNT _("Error obtaining option count") +#define ERR_DEVICE_OPEN_FAILED _("Failed to open device") +#define ERR_NO_DEVICES _("no devices available") +#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") +#define ERR_UNKNOWN_SAVING_FORMAT _("Unknown file format for saving") +#define ERR_OPEN_FAILED _("Failed to open") +#define ERR_FAILED_PRINTER_PIPE _("Failed to open pipe for executing printercommand") +#define ERR_FAILED_EXEC_PRINTER_CMD _("Failed to execute printercommand:") +#define ERR_FAILED_START_SCANNER _("Failed to start scanner:") +#define ERR_FAILED_GET_PARAMS _("Failed to get parameters:") +#define ERR_NO_OUTPUT_FORMAT _("No output format given") +#define ERR_NO_MEM _("out of memory") +#define ERR_LIBTIFF _("LIBTIFF reports error") +#define ERR_LIBPNG _("LIBPNG reports error") +#define ERR_UNKNOWN_TYPE _("unknown type") +#define ERR_UNKNOWN_CONSTRAINT_TYPE _("unknown constraint type") +#define ERR_FAILD_EXEC_DOC_VIEWER _("Failed to execute documentation viewer:") +#define ERR_FAILD_EXEC_FAX_VIEWER _("Failed to execute fax viewer:") +#define ERR_FAILED_EXEC_FAX_CMD _("Failed to execute faxcommand:") +#define ERR_BAD_FRAME_FORMAT _("bad frame format") +#define ERR_FAILED_SET_RESOLUTION _("unable to set resolution") + +#define ERR_ERROR _("error") +#define ERR_MAJOR_VERSION_NR_CONFLICT _("Sane major version number mismatch!") +#define ERR_XSANE_MAJOR_VERSION _("xsane major version =") +#define ERR_BACKEND_MAJOR_VERSION _("backend major version =") +#define ERR_PROGRAM_ABORTED _("*** PROGRAM ABORTED ***") + +#define ERR_FAILED_ALLOCATE_IMAGE _("Failed to allocate image memory:") +#define ERR_PREVIEW_BAD_DEPTH _("Preview cannot handle bit depth") +#define ERR_GIMP_SUPPORT_MISSING _("GIMP support missing") + +#define WARN_COUNTER_OVERFLOW _("Filename counter overflow") +#define WARN_NO_VALUE_CONSTRAINT _("warning: option has no value constraint") + +#define ERR_BUTTON_OK _("Ok") +#define ERR_HEADER_ERROR _("Error") +#define ERR_HEADER_WARNING _("Warning") + +#define ERR_FAILED_CREATE_FILE _("Failed to create file:") +#define ERR_LOAD_DEVICE_SETTINGS _("Error while loading device settings:") +#define ERR_NO_DRC_FILE _("is not a device-rc-file !!!") +#define ERR_NETSCAPE_EXECUTE_FAIL _("Failed to execute netscape!") +#define ERR_SENDFAX_RECEIVER_MISSING _("Send fax: no receiver defined") + +#define ERR_CREATED_FOR_DEVICE _("has been created for device") +#define ERR_USED_FOR_DEVICE _("you want to use it for device") +#define ERR_MAY_CAUSE_PROBLEMS _("this may cause problems!") + +#define TEXT_USAGE _("Usage:") +#define TEXT_USAGE_OPTIONS _("[OPTION]... [DEVICE]") +#define TEXT_HELP _(\ +"Start up graphical user interface to access SANE (Scanner Access Now Easy) devices.\n\ +\n\ +-h, --help display this help message and exit\n\ +-v, --version print version information\n\ +\n\ +-d, --device-settings file load device settings from file (without \".drc\")\n\ +\n\ +-s, --scan start with scan-mode active\n\ +-c, --copy start with copy-mode active\n\ +-f, --fax start with fax-mode active\n\ +-n, --no-mode-selection disable menu for xsane mode selection\n\ +\n\ +-F, --Fixed fixed main window size (overwrite preferences value)\n\ +-R, --Resizeable resizable, scrolled main window (overwrite preferences value)\n\ +\n\ +--display X11-display redirect output to X11-display\n\ +--no-xshm do not use shared memory images\n\ +--sync request a synchronous connection with the X11 server\ +") + +/* strings for gimp plugin */ + +#define XSANE_GIMP_INSTALL_BLURB _("Front-end to the SANE interface") +#define XSANE_GIMP_INSTALL_HELP _("This function provides access to scanners and other image acquisition devices through the SANE (Scanner Access Now Easy) interface.") + +/* Menu path must not be translated, this is done by the gimp. Only translate the text behind the last "/" */ +#define XSANE_GIMP_MENU_DIALOG _("<Toolbox>/File/Acquire/XSane: Device dialog...") +#define XSANE_GIMP_MENU _("<Toolbox>/File/Acquire/XSane: ") +#define XSANE_GIMP_MENU_DIALOG_OLD _("<Toolbox>/Xtns/XSane/Device dialog...") +#define XSANE_GIMP_MENU_OLD _("<Toolbox>/Xtns/XSane/") + +#endif diff --git a/frontend/xsane.c b/frontend/xsane.c new file mode 100644 index 0000000..6302168 --- /dev/null +++ b/frontend/xsane.c @@ -0,0 +1,4794 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane.c + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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 "xsane-preview.h" +#include "xsane-save.h" +#include "xsane-gamma.h" +#include "xsane-setup.h" +#include "xsane-scan.h" +#include "xsane-rc-io.h" +#include "xsane-device-preferences.h" +#include "xsane-preferences.h" +#include "xsane-icons.h" + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ +#include <png.h> +#include <zlib.h> +#endif +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +struct option long_options[] = +{ + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'v'}, + {"device-settings", required_argument, 0, 'd'}, + {"scan", no_argument, 0, 's'}, + {"copy", no_argument, 0, 'c'}, + {"no-mode-selection", no_argument, 0, 'n'}, + {"fax", no_argument, 0, 'f'}, + {"Fixed", no_argument, 0, 'F'}, + {"Resizeable", no_argument, 0, 'R'}, + {0, } +}; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +int xsane_back_gtk_message_dialog_active = 0; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +const char *prog_name = 0; +const char *device_text = 0; +GtkWidget *choose_device_dialog = 0; +GSGDialog *dialog = 0; +const SANE_Device **devlist = 0; +gint seldev = -1; /* The selected device */ +gint ndevs; /* The number of available devices */ +struct Xsane xsane; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +int xsane_scanmode_number[] = { XSANE_SCAN, XSANE_COPY, XSANE_FAX }; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#define XSANE_GTK_NAME_RESOLUTION "GtkMenuResolution" +#define XSANE_GTK_NAME_X_RESOLUTION "GtkMenuXResolution" +#define XSANE_GTK_NAME_Y_RESOLUTION "GtkMenuYResolution" + +#define XSANE_GTK_NAME_ZOOM "GtkMenuZoom" +#define XSANE_GTK_NAME_X_ZOOM "GtkMenuXZoom" +#define XSANE_GTK_NAME_Y_ZOOM "GtkMenuYZoom" + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* forward declarations: */ + +static int xsane_option_defined(char *string); +static int xsane_parse_options(char *options, char *argv[]); +static void xsane_update_param(GSGDialog *dialog, void *arg); +static void xsane_zoom_update(GtkAdjustment *adj_data, double *val); +static void xsane_resolution_scale_update(GtkAdjustment *adj_data, double *val); +static void xsane_gamma_changed(GtkAdjustment *adj_data, double *val); +static void xsane_modus_callback(GtkWidget *xsane_parent, int *num); +static void xsane_filetype_callback(GtkWidget *widget, gpointer data); +static void xsane_outputfilename_changed_callback(GtkWidget *widget, gpointer data); +static void xsane_browse_filename_callback(GtkWidget *widget, gpointer data); +static void xsane_outputfilename_new(GtkWidget *vbox); +static void xsane_faxreceiver_changed_callback(GtkWidget *widget, gpointer data); +static void xsane_faxproject_changed_callback(GtkWidget *widget, gpointer data); +static void xsane_fax_fine_mode_callback(GtkWidget * widget); +static void xsane_enhancement_rgb_default_callback(GtkWidget * widget); +static void xsane_enhancement_negative_callback(GtkWidget * widget); +static void xsane_auto_enhancement_callback(GtkWidget * widget); +static void xsane_show_standard_options_callback(GtkWidget * widget); +static void xsane_show_advanced_options_callback(GtkWidget * widget); +static void xsane_show_histogram_callback(GtkWidget * widget); +static void xsane_printer_callback(GtkWidget *widget, gpointer data); +static void xsane_update_preview(GSGDialog *dialog, void *arg); +void xsane_pref_save(void); +static void xsane_pref_restore(void); +static void xsane_quit(void); +static void xsane_exit(void); +static gint xsane_standard_option_win_delete(GtkWidget *widget, gpointer data); +static gint xsane_advanced_option_win_delete(GtkWidget *widget, gpointer data); +static gint xsane_scan_win_delete(GtkWidget *w, gpointer data); +static gint xsane_preview_window_destroyed(GtkWidget *widget, gpointer call_data); +static void xsane_show_preview_callback(GtkWidget * widget, gpointer call_data); +static GtkWidget *xsane_files_build_menu(void); +static void xsane_set_pref_unit_callback(GtkWidget *widget, gpointer data); +static void xsane_set_update_policy_callback(GtkWidget *widget, gpointer data); +static gint xsane_close_info_callback(GtkWidget *widget, gpointer data); +static void xsane_info_dialog(GtkWidget *widget, gpointer data); +static void xsane_about_dialog(GtkWidget *widget, gpointer data); +static SANE_Status xsane_get_area_value(int option, float *val, SANE_Int *unit); +#ifdef XSANE_TEST +static void xsane_batch_scan_delete_callback(GtkWidget *widget, gpointer list); +static void xsane_batch_scan_add_callback(GtkWidget *widget, gpointer list); +static void xsane_batch_scan_dialog(GtkWidget *widget, gpointer data); +#endif +static void xsane_fax_dialog(void); +static void xsane_fax_dialog_close(void); +static void xsane_fax_project_delete(void); +void xsane_fax_project_save(void); +static void xsane_fax_project_load(void); +static void xsane_fax_project_create(void); +static void xsane_pref_toggle_tooltips(GtkWidget *widget, gpointer data); +static void xsane_show_doc(GtkWidget *widget, gpointer data); +static void xsane_fax_entrys_swap(GtkWidget *list_item_1, GtkWidget *list_item_2); +static void xsane_fax_entry_move_up_callback(GtkWidget *widget, gpointer list); +static void xsane_fax_entry_move_down_callback(GtkWidget *widget, gpointer list); +static void xsane_fax_entry_rename_callback(GtkWidget *widget, gpointer list); +static void xsane_fax_entry_delete_callback(GtkWidget *widget, gpointer list); +static void xsane_fax_show_callback(GtkWidget *widget, gpointer data); +static void xsane_fax_send(void); +static GtkWidget *xsane_view_build_menu(void); +static GtkWidget *xsane_pref_build_menu(void); +static GtkWidget *xsane_help_build_menu(void); +static void xsane_device_dialog(void); +static void xsane_choose_dialog_ok_callback(void); +static void xsane_select_device_by_key_callback(GtkWidget * widget, gpointer data); +static void xsane_select_device_by_mouse_callback(GtkWidget * widget, GdkEventButton *event, gpointer data); +static gint32 xsane_choose_device(void); +static void xsane_usage(void); +static void xsane_init(int argc, char **argv); +void xsane_interface(int argc, char **argv); +int main(int argc, char ** argv); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_option_defined(char *string) +{ + if (string) + { + while (*string == ' ') /* skip spaces */ + { + string++; + } + if (*string != 0) + { + return 1; + } + } + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_parse_options(char *options, char *argv[]) +{ + int optpos = 0; + int bufpos = 0; + int arg = 0; + char buf[256]; + + while (options[optpos] != 0) + { + switch(options[optpos]) + { + case ' ': + buf[bufpos] = 0; + argv[arg++] = strdup(buf); + bufpos = 0; + optpos++; + break; + + case '\"': + optpos++; /* skip " */ + while ((options[optpos] != 0) && (options[optpos] != '\"')) + { + buf[bufpos++] = options[optpos++]; + } + optpos++; /* skip " */ + break; + + default: + buf[bufpos++] = options[optpos++]; + break; + } + } + buf[bufpos] = 0; + argv[arg++] = strdup(buf); + return arg; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* Update the info line with the latest size information and update histogram. */ +static void xsane_update_param(GSGDialog *dialog, void *arg) +{ + SANE_Parameters params; + gchar buf[200]; + + if (!xsane.info_label) + { + return; + } + + if (xsane.block_update_param) /* if we change more than one value, we only want to update all once */ + { + return; + } + + if (sane_get_parameters(xsane_back_gtk_dialog_get_device(dialog), ¶ms) == SANE_STATUS_GOOD) + { + float size = params.bytes_per_line * params.lines; + const char *unit = "B"; + + if (params.format >= SANE_FRAME_RED && params.format <= SANE_FRAME_BLUE) + { + size *= 3.0; + } + + if (size >= 1024.0 * 1024.0) + { + size /= 1024.0 * 1024.0; + unit = "MB"; + } + else if (size >= 1024.0) + { + size /= 1024.0; + unit = "KB"; + } + snprintf(buf, sizeof(buf), "(%d x %d): %5.1f %s", params.pixels_per_line, params.lines, size, unit); + + if (params.format == SANE_FRAME_GRAY) + { + xsane.xsane_color = 0; + } +#ifdef SUPPORT_RGBA + else if (params.format == SANE_FRAME_RGBA) + { + xsane.xsane_color = 4; + } +#endif + else /* RGB */ + { + xsane.xsane_color = 3; + } + } + else + { + snprintf(buf, sizeof(buf), TEXT_INVALID_PARAMS); + } + + gtk_label_set(GTK_LABEL(xsane.info_label), buf); + + + if (xsane.preview) + { + preview_update_surface(xsane.preview, 0); + } + + xsane_update_histogram(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_gamma_changed(GtkAdjustment *adj_data, double *val) +{ + *val = adj_data->value; + xsane_enhancement_by_gamma(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_modus_callback(GtkWidget *xsane_parent, int *num) +{ + + if (xsane.filetype) /* add extension to filename */ + { + char buffer[256]; + + snprintf(buffer, sizeof(buffer), "%s%s", preferences.filename, xsane.filetype); + free(preferences.filename); + free(xsane.filetype); + xsane.filetype = 0; + preferences.filename = strdup(buffer); + } + + xsane.xsane_mode = *num; + xsane_refresh_dialog(dialog); + + if (xsane.xsane_mode != XSANE_FAX) + { + xsane_fax_dialog_close(); + gtk_widget_set_sensitive(GTK_WIDGET(xsane.start_button), TRUE); + } + + xsane_define_maximum_output_size(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_filetype_callback(GtkWidget *widget, gpointer data) +{ + if (data) + { + char *extension, *filename; + + extension = strrchr(preferences.filename, '.'); + + if ((extension) && (extension != preferences.filename)) + { + if ( (!strcasecmp(extension, ".pnm")) || (!strcasecmp(extension, ".raw")) + || (!strcasecmp(extension, ".png")) || (!strcasecmp(extension, ".ps")) + || (!strcasecmp(extension, ".rgba")) + || (!strcasecmp(extension, ".tiff")) || (!strcasecmp(extension, ".tif")) + || (!strcasecmp(extension, ".jpg")) || (!strcasecmp(extension, ".jpeg")) + ) /* remove filetype extension */ + { + filename = preferences.filename; + *extension = 0; /* remove extension */ + preferences.filename = strdup(filename); /* filename without extension */ + free(filename); /* free unused memory */ + } + } + } + else if (xsane.filetype) + { + char buffer[256]; + + snprintf(buffer, sizeof(buffer), "%s%s", preferences.filename, xsane.filetype); + free(preferences.filename); + free(xsane.filetype); + xsane.filetype = 0; + preferences.filename = strdup(buffer); + } + + if (data) + { + xsane.filetype = strdup((char *) data); /* set extension for filename */ + } + + gtk_entry_set_text(GTK_ENTRY(xsane.outputfilename_entry), preferences.filename); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_outputfilename_changed_callback(GtkWidget *widget, gpointer data) +{ + if (preferences.filename) + { + free((void *) preferences.filename); + } + preferences.filename = strdup(gtk_entry_get_text(GTK_ENTRY(widget))); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ + +static void xsane_browse_filename_callback(GtkWidget *widget, gpointer data) +{ + char filename[1024]; + char windowname[256]; + + xsane_set_sensitivity(FALSE); + + if (xsane.filetype) /* set filetype to "by ext." */ + { + char buffer[256]; + + snprintf(buffer, sizeof(buffer), "%s%s", preferences.filename, xsane.filetype); + free(preferences.filename); + free(xsane.filetype); + xsane.filetype = 0; + preferences.filename = strdup(buffer); + } + + if (preferences.filename) /* make sure a correct filename is defined */ + { + strncpy(filename, preferences.filename, sizeof(filename)); + filename[sizeof(filename) - 1] = '\0'; + } + else /* no filename given, take standard filename */ + { + strcpy(filename, OUTFILENAME); + } + + snprintf(windowname, sizeof(windowname), "%s %s %s", prog_name, WINDOW_OUTPUT_FILENAME, device_text); + + umask(preferences.directory_umask); /* define new file permissions */ + xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, TRUE); + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + + gtk_entry_set_text(GTK_ENTRY(xsane.outputfilename_entry), filename); + + if (preferences.filename) + { + free((void *) preferences.filename); + } + + xsane_set_sensitivity(TRUE); + + preferences.filename = strdup(filename); + + gtk_option_menu_set_history(GTK_OPTION_MENU(xsane.filetype_option_menu), 0); /* set menu to "by ext" */ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_outputfilename_new(GtkWidget *vbox) +{ + GtkWidget *hbox; + GtkWidget *text; + GtkWidget *button; + GtkWidget *xsane_filetype_menu, *xsane_filetype_item; + + 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, 2); + + button = xsane_button_new_with_pixmap(hbox, file_xpm, DESC_BROWSE_FILENAME, (GtkSignalFunc) xsane_browse_filename_callback, 0); + + text = gtk_entry_new_with_max_length(255); + gtk_widget_set_usize(text, 80, 0); /* set minimum size */ + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FILENAME); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.filename); + gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 4); + gtk_signal_connect(GTK_OBJECT(text), "changed", (GtkSignalFunc) xsane_outputfilename_changed_callback, 0); + + xsane.outputfilename_entry = text; + + xsane_filetype_menu = gtk_menu_new(); + + xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_BY_EXT); + gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item); + gtk_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", + (GtkSignalFunc) xsane_filetype_callback, NULL); + gtk_widget_show(xsane_filetype_item); + +#ifdef HAVE_LIBJPEG + xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_JPEG); + gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item); + gtk_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", + (GtkSignalFunc) xsane_filetype_callback, MENU_ITEM_FILETYPE_JPEG); + gtk_widget_show(xsane_filetype_item); +#endif + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ + xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_PNG); + gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item); + gtk_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", + (GtkSignalFunc) xsane_filetype_callback, MENU_ITEM_FILETYPE_PNG); + gtk_widget_show(xsane_filetype_item); +#endif +#endif + + xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_PNM); + gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item); + gtk_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", + (GtkSignalFunc) xsane_filetype_callback, MENU_ITEM_FILETYPE_PNM); + gtk_widget_show(xsane_filetype_item); + + xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_PS); + gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item); + gtk_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", + (GtkSignalFunc) xsane_filetype_callback, MENU_ITEM_FILETYPE_PS); + gtk_widget_show(xsane_filetype_item); + + xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_RAW); + gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item); + gtk_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", + (GtkSignalFunc) xsane_filetype_callback, MENU_ITEM_FILETYPE_RAW); + gtk_widget_show(xsane_filetype_item); + +#ifdef HAVE_LIBTIFF + xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_TIFF); + gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item); + gtk_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", + (GtkSignalFunc) xsane_filetype_callback, MENU_ITEM_FILETYPE_TIFF); + gtk_widget_show(xsane_filetype_item); +#endif + + xsane.filetype_option_menu = gtk_option_menu_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, xsane.filetype_option_menu, DESC_FILETYPE); + gtk_box_pack_end(GTK_BOX(hbox), xsane.filetype_option_menu, FALSE, FALSE, 2); + gtk_option_menu_set_menu(GTK_OPTION_MENU(xsane.filetype_option_menu), xsane_filetype_menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(xsane.filetype_option_menu), 0); + gtk_widget_show(xsane.filetype_option_menu); + + gtk_widget_show(text); + gtk_widget_show(hbox); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_faxreceiver_changed_callback(GtkWidget *widget, gpointer data) +{ + if (xsane.fax_receiver) + { + free((void *) xsane.fax_receiver); + } + xsane.fax_receiver = strdup(gtk_entry_get_text(GTK_ENTRY(widget))); + + xsane_fax_project_save(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_faxproject_changed_callback(GtkWidget *widget, gpointer data) +{ + if (preferences.fax_project) + { + free((void *) preferences.fax_project); + } + preferences.fax_project = strdup(gtk_entry_get_text(GTK_ENTRY(widget))); + + xsane_fax_project_load(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_fine_mode_callback(GtkWidget * widget) +{ + xsane.fax_fine_mode = (GTK_TOGGLE_BUTTON(widget)->active != 0); + + if (xsane.fax_fine_mode) + { + xsane.resolution = 196; + xsane.resolution_x = 98; + xsane.resolution_y = 196; + } + else + { + xsane.resolution = 98; + xsane.resolution_x = 98; + xsane.resolution_y = 98; + } + + xsane_set_all_resolutions(); + + xsane_update_param(dialog, 0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_enhancement_rgb_default_callback(GtkWidget * widget) +{ + xsane.enhancement_rgb_default = (GTK_TOGGLE_BUTTON(widget)->active != 0); + + if (xsane.enhancement_rgb_default) + { + xsane.gamma_red = 1.0; + xsane.gamma_green = 1.0; + xsane.gamma_blue = 1.0; + + xsane.brightness_red = 0.0; + xsane.brightness_green = 0.0; + xsane.brightness_blue = 0.0; + + xsane.contrast_red = 0.0; + xsane.contrast_green = 0.0; + xsane.contrast_blue = 0.0; + + xsane.slider_red.value[0] = 0.0; + xsane.slider_red.value[1] = 50.0; + xsane.slider_red.value[2] = 100.0; + + xsane.slider_green.value[0] = 0.0; + xsane.slider_green.value[1] = 50.0; + xsane.slider_green.value[2] = 100.0; + + xsane.slider_blue.value[0] = 0.0; + xsane.slider_blue.value[1] = 50.0; + xsane.slider_blue.value[2] = 100.0; + } + else + { + xsane.slider_red.value[0] = xsane.slider_gray.value[0]; + xsane.slider_red.value[1] = xsane.slider_gray.value[1]; + xsane.slider_red.value[2] = xsane.slider_gray.value[2]; + + xsane.slider_green.value[0] = xsane.slider_gray.value[0]; + xsane.slider_green.value[1] = xsane.slider_gray.value[1]; + xsane.slider_green.value[2] = xsane.slider_gray.value[2]; + + xsane.slider_blue.value[0] = xsane.slider_gray.value[0]; + xsane.slider_blue.value[1] = xsane.slider_gray.value[1]; + xsane.slider_blue.value[2] = xsane.slider_gray.value[2]; + } + + xsane_update_sliders(); + xsane_update_gamma(); + xsane_refresh_dialog(dialog); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_enhancement_negative_callback(GtkWidget * widget) +{ + double v0; + + if (xsane.negative != (GTK_TOGGLE_BUTTON(widget)->active != 0)); + { + v0 = xsane.slider_gray.value[0]; + xsane.slider_gray.value[0] = 100.0 - xsane.slider_gray.value[2]; + xsane.slider_gray.value[1] = 100.0 - xsane.slider_gray.value[1]; + xsane.slider_gray.value[2] = 100.0 - v0; + + if (!xsane.enhancement_rgb_default) + { + v0 = xsane.slider_red.value[0]; + xsane.slider_red.value[0] = 100.0 - xsane.slider_red.value[2]; + xsane.slider_red.value[1] = 100.0 - xsane.slider_red.value[1]; + xsane.slider_red.value[2] = 100.0 - v0; + + v0 = xsane.slider_green.value[0]; + xsane.slider_green.value[0] = 100.0 - xsane.slider_green.value[2]; + xsane.slider_green.value[1] = 100.0 - xsane.slider_green.value[1]; + xsane.slider_green.value[2] = 100.0 - v0; + + v0 = xsane.slider_blue.value[0]; + xsane.slider_blue.value[0] = 100.0 - xsane.slider_blue.value[2]; + xsane.slider_blue.value[1] = 100.0 - xsane.slider_blue.value[1]; + xsane.slider_blue.value[2] = 100.0 - v0; + } + } + + xsane.negative = (GTK_TOGGLE_BUTTON(widget)->active != 0); + + xsane_update_sliders(); + xsane_enhancement_by_histogram(); + xsane_update_gamma(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_auto_enhancement_callback(GtkWidget * widget) +{ + xsane_calculate_histogram(); + + xsane.slider_gray.value[0] = xsane.auto_black; + xsane.slider_gray.value[1] = xsane.auto_gray; + xsane.slider_gray.value[2] = xsane.auto_white; + + if (xsane.enhancement_rgb_default) /* set same values for color components */ + { + xsane.slider_red.value[0] = xsane.auto_black; + xsane.slider_red.value[1] = xsane.auto_gray; + xsane.slider_red.value[2] = xsane.auto_white; + + xsane.slider_green.value[0] = xsane.auto_black; + xsane.slider_green.value[1] = xsane.auto_gray; + xsane.slider_green.value[2] = xsane.auto_white; + + xsane.slider_blue.value[0] = xsane.auto_black; + xsane.slider_blue.value[1] = xsane.auto_gray; + xsane.slider_blue.value[2] = xsane.auto_white; + } + else /* set different values for each color component */ + { + xsane.slider_red.value[0] = xsane.auto_black_red; + xsane.slider_red.value[1] = xsane.auto_gray_red; + xsane.slider_red.value[2] = xsane.auto_white_red; + + xsane.slider_green.value[0] = xsane.auto_black_green; + xsane.slider_green.value[1] = xsane.auto_gray_green; + xsane.slider_green.value[2] = xsane.auto_white_green; + + xsane.slider_blue.value[0] = xsane.auto_black_blue; + xsane.slider_blue.value[1] = xsane.auto_gray_blue; + xsane.slider_blue.value[2] = xsane.auto_white_blue; + } + + xsane_enhancement_by_histogram(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_show_standard_options_callback(GtkWidget * widget) +{ + preferences.show_standard_options = (GTK_CHECK_MENU_ITEM(widget)->active != 0); + if (preferences.show_standard_options) + { + gtk_widget_show(xsane.standard_options_shell); + } + else + { + gtk_widget_hide(xsane.standard_options_shell); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_show_advanced_options_callback(GtkWidget * widget) +{ + preferences.show_advanced_options = (GTK_CHECK_MENU_ITEM(widget)->active != 0); + if (preferences.show_advanced_options) + { + gtk_widget_show(xsane.advanced_options_shell); + } + else + { + gtk_widget_hide(xsane.advanced_options_shell); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_show_resolution_list_callback(GtkWidget *widget) +{ + preferences.show_resolution_list = (GTK_CHECK_MENU_ITEM(widget)->active != 0); + xsane_refresh_dialog(0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_page_rotate_callback(GtkWidget *widget) +{ + preferences.psrotate = (GTK_CHECK_MENU_ITEM(widget)->active != 0); + xsane_define_maximum_output_size(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_show_histogram_callback(GtkWidget * widget) +{ + preferences.show_histogram = (GTK_CHECK_MENU_ITEM(widget)->active != 0); + if (preferences.show_histogram) + { + xsane_update_histogram(); + gtk_widget_show(xsane.histogram_dialog); + } + else + { + gtk_widget_hide(xsane.histogram_dialog); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_printer_callback(GtkWidget *widget, gpointer data) +{ + preferences.printernr = (int) data; + xsane_back_gtk_refresh_dialog(dialog); + xsane_define_maximum_output_size(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_resolution_scale_update(GtkAdjustment *adj_data, double *val) +{ +#if 1 +/* gtk does not make sure that the value is quantisized correct */ + float diff, old, new, quant; + + quant = adj_data->step_increment; + + if (quant != 0) + { + new = adj_data->value; + old = *val; + diff = quant*((int) ((new - old)/quant)); + + *val = old + diff; + adj_data->value = *val; + } +#else + *val = adj_data->value; +#endif + + xsane_set_all_resolutions(); + + xsane_update_param(dialog, 0); + xsane.zoom = xsane.resolution / preferences.printer[preferences.printernr]->resolution; + xsane.zoom_x = xsane.resolution_x / preferences.printer[preferences.printernr]->resolution; + xsane.zoom_y = xsane.resolution_y / preferences.printer[preferences.printernr]->resolution; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_resolution_list_callback(GtkWidget *widget, gpointer data) +{ + GSGMenuItem *menu_item = data; + GSGDialogElement *elem = menu_item->elem; + GSGDialog *dialog = elem->dialog; + SANE_Word val; + gchar *name = gtk_widget_get_name(widget->parent); + + sscanf(menu_item->label, "%d", &val); + + if (!strcmp(name, XSANE_GTK_NAME_RESOLUTION)) + { + xsane.resolution = val; + xsane.resolution_x = val; + xsane.resolution_y = val; + + xsane_set_resolution(dialog->well_known.dpi, xsane.resolution); + xsane_set_resolution(dialog->well_known.dpi_x, xsane.resolution_x); + xsane_set_resolution(dialog->well_known.dpi_y, xsane.resolution_y); + + xsane.zoom = xsane.resolution / preferences.printer[preferences.printernr]->resolution; + xsane.zoom_x = xsane.resolution_x / preferences.printer[preferences.printernr]->resolution; + xsane.zoom_y = xsane.resolution_y / preferences.printer[preferences.printernr]->resolution; + } + else if (!strcmp(name, XSANE_GTK_NAME_X_RESOLUTION)) + { + xsane.resolution = val; + xsane.resolution_x = val; + xsane_set_resolution(dialog->well_known.dpi_x, xsane.resolution_x); + xsane.zoom = xsane.resolution / preferences.printer[preferences.printernr]->resolution; + } + else if (!strcmp(name, XSANE_GTK_NAME_Y_RESOLUTION)) + { + xsane.resolution_y = val; + xsane_set_resolution(dialog->well_known.dpi_y, xsane.resolution_y); + xsane.zoom = xsane.resolution / preferences.printer[preferences.printernr]->resolution; + } + + xsane_update_param(dialog, 0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +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; + const SANE_Option_Descriptor *opt; + + opt = sane_get_option_descriptor(dialog->dev, well_known_option); + + if (!opt) + { + return -1; /* options does not exist */ + } + else + { + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + { + SANE_Word quant=0; + SANE_Word min=0; + SANE_Word max=0; + SANE_Word val=0; + + gtk_widget_set_sensitive(xsane.show_resolution_list_widget, TRUE); + sane_control_option(dialog->dev, well_known_option, SANE_ACTION_GET_VALUE, &val, 0); + + switch (opt->type) + { + case SANE_TYPE_INT: + min = opt->constraint.range->min; + max = opt->constraint.range->max; + quant = opt->constraint.range->quant; + break; + + case SANE_TYPE_FIXED: + min = SANE_UNFIX(opt->constraint.range->min); + max = SANE_UNFIX(opt->constraint.range->max); + quant = SANE_UNFIX(opt->constraint.range->quant); + val = SANE_UNFIX(val); + break; + + default: + fprintf(stderr, "zoom_scale_update: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + } + + if (quant == 0) + { + quant = 1; + } + + if (!(*resolution)) /* no prefered value */ + { + *resolution = val; /* set backend predefined value */ + } + + if (!preferences.show_resolution_list) /* user wants slider */ + { + xsane_scale_new_with_pixmap(GTK_BOX(parent), image_xpm, desc, + min, max, quant, quant, 0.0, 0, resolution, &resolution_widget, + well_known_option, xsane_resolution_scale_update, SANE_OPTION_IS_SETTABLE(opt->cap)); + } + else /* user wants list instead of slider */ + { + SANE_Int max_items = 20; + char **str_list; + char str[16]; + int i; + int j = 0; + SANE_Word wanted_res; + SANE_Word val = max; + int res = max; + double mul; + + sane_control_option(dialog->dev, well_known_option, SANE_ACTION_GET_VALUE, &wanted_res, 0); + if (opt->type == SANE_TYPE_FIXED) + { + wanted_res = (int) SANE_UNFIX(wanted_res); + } + + if (*resolution) /* prefered value */ + { + wanted_res = *resolution; /* set frontend prefered value */ + } + + str_list = malloc((max_items + 1) * sizeof(str_list[0])); + + sprintf(str, "%d", max); + str_list[j++] = strdup(str); + + i=9; + while ((j < max_items) && (res > 50) && (res > min) && (i > 0)) + { + mul = ((double) i) / (i+1); + res = (int) (max * mul); + if (res/mul == max) + { + sprintf(str, "%d", res); + str_list[j++] = strdup(str); + if (res >= wanted_res) + { + val = res; + } + } + i--; + } + + i = 3; + while ((j < max_items) && (res > 50) && (res > min)) + { + mul = 1.0/i; + res = max * mul; + if (res/mul == max) + { + sprintf(str, "%d", res); + str_list[j++] = strdup(str); + if (res >= wanted_res) + { + val = res; + } + } + i++; + } + + str_list[j] = 0; + sprintf(str, "%d", (int) val); + + xsane_option_menu_new_with_pixmap(GTK_BOX(parent), image_xpm, desc, str_list, str, &resolution_widget, well_known_option, + xsane_resolution_list_callback, SANE_OPTION_IS_SETTABLE(opt->cap), widget_name); + + free(str_list); + *resolution = val; + xsane_set_resolution(well_known_option, *resolution); + } + } + break; + + case SANE_CONSTRAINT_WORD_LIST: + { + /* use a "list-selection" widget */ + SANE_Int items; + char **str_list; + char str[16]; + int j; + SANE_Word val=0; + + gtk_widget_set_sensitive(xsane.show_resolution_list_widget, FALSE); + + items = opt->constraint.word_list[0]; + str_list = malloc((items + 1) * sizeof(str_list[0])); + switch (opt->type) + { + case SANE_TYPE_INT: + for (j = 0; j < items; ++j) + { + sprintf(str, "%d", opt->constraint.word_list[j + 1]); + str_list[j] = strdup(str); + } + str_list[j] = 0; + sane_control_option(dialog->dev, well_known_option, SANE_ACTION_GET_VALUE, &val, 0); + sprintf(str, "%d", (int) val); + break; + + case SANE_TYPE_FIXED: + for (j = 0; j < items; ++j) + { + sprintf(str, "%d", (int) SANE_UNFIX(opt->constraint.word_list[j + 1])); + str_list[j] = strdup(str); + } + str_list[j] = 0; + sane_control_option(dialog->dev, well_known_option, SANE_ACTION_GET_VALUE, &val, 0); + sprintf(str, "%d", (int) SANE_UNFIX(val)); + break; + + default: + fprintf(stderr, "resolution_word_list_creation: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + } + + + xsane_option_menu_new_with_pixmap(GTK_BOX(parent), image_xpm, desc, + str_list, str, &resolution_widget, well_known_option, + xsane_resolution_list_callback, SANE_OPTION_IS_SETTABLE(opt->cap), widget_name); + free(str_list); + } + break; + + default: + break; + } /* constraint type */ + + return 0; /* everything is ok */ + + } /* if resolution option active */ + + return 1; /* not active */ + + } /* if (opt) */ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_zoom_update(GtkAdjustment *adj_data, double *val) +{ + *val=adj_data->value; + + /* update all resolutions */ + xsane.resolution = xsane.zoom * preferences.printer[preferences.printernr]->resolution; + xsane.resolution_x = xsane.zoom_x * preferences.printer[preferences.printernr]->resolution; + xsane.resolution_y = xsane.zoom_y * preferences.printer[preferences.printernr]->resolution; + + xsane_set_all_resolutions(); + + xsane_update_param(dialog, 0); + + xsane_define_maximum_output_size(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_zoom_widget_new(GtkWidget *parent, int well_known_option, double *zoom, double resolution, + const char *image_xpm[], const gchar *desc) +{ + const SANE_Option_Descriptor *opt; + double output_resolution = preferences.printer[preferences.printernr]->resolution; + + opt = sane_get_option_descriptor(dialog->dev, well_known_option); + if (!opt) + { + return -1; /* option not available */ + } + else + { + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + double min = 0.0; + double max = 0.0; + SANE_Word val = 0.0; + + sane_control_option(dialog->dev, well_known_option, SANE_ACTION_GET_VALUE, &val, 0); + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + switch (opt->type) + { + case SANE_TYPE_INT: + min = ((double) opt->constraint.range->min) / output_resolution; + max = ((double) opt->constraint.range->max) / output_resolution; + break; + + case SANE_TYPE_FIXED: + min = SANE_UNFIX(opt->constraint.range->min) / output_resolution; + max = SANE_UNFIX(opt->constraint.range->max) / output_resolution; + val = SANE_UNFIX(val); + break; + + default: + fprintf(stderr, "zoom_scale_update: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + } + break; + + case SANE_CONSTRAINT_WORD_LIST: + xsane_get_bounds(opt, &min, &max); + min = min / output_resolution; + max = max / output_resolution; + break; + + default: + fprintf(stderr, "zoom_scale_update: %s %d\n", ERR_UNKNOWN_CONSTRAINT_TYPE, opt->constraint_type); + } + + if (resolution == 0) /* no prefered value */ + { + resolution = val; /* set backend predefined value */ + } + + *zoom = resolution / output_resolution; + + xsane_scale_new_with_pixmap(GTK_BOX(parent), image_xpm, desc, min, max, 0.01, 0.01, 0.1, 2, + zoom, &xsane.zoom_widget, well_known_option, xsane_zoom_update, + SANE_OPTION_IS_SETTABLE(opt->cap)); + + return 0; /* everything is ok */ + } + return 1; /* option not active */ + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +GtkWidget *xsane_update_xsane_callback() +{ + /* creates the XSane option window */ + + GtkWidget *xsane_vbox, *xsane_hbox; + GtkWidget *xsane_modus_menu; + GtkWidget *xsane_modus_item; + GtkWidget *xsane_modus_option_menu; + GtkWidget *xsane_vbox_xsane_modus; + GtkWidget *xsane_hbox_xsane_modus; + GtkWidget *xsane_label; + GtkWidget *xsane_text; + GtkWidget *xsane_hbox_xsane_enhancement; + GtkWidget *xsane_frame; + GtkWidget *xsane_button; + gchar buf[200]; + + /* xsane main options */ + + xsane_hbox = gtk_hbox_new(FALSE, 2); + gtk_widget_show(xsane_hbox); + xsane_vbox = gtk_vbox_new(/* homogeneous */ FALSE, 0); + gtk_widget_show(xsane_vbox); +/* gtk_box_pack_start(GTK_BOX(xsane_hbox), xsane_vbox, FALSE, FALSE, 0); */ /* make scales fixed */ + gtk_box_pack_start(GTK_BOX(xsane_hbox), xsane_vbox, TRUE, TRUE, 0); /* make scales sizeable */ + + /* XSane Frame */ + + xsane_frame = gtk_frame_new(TEXT_XSANE_OPTIONS); + gtk_container_set_border_width(GTK_CONTAINER(xsane_frame), 4); + gtk_frame_set_shadow_type(GTK_FRAME(xsane_frame), GTK_SHADOW_ETCHED_IN); +/* gtk_box_pack_start(GTK_BOX(xsane_vbox), xsane_frame, FALSE, FALSE, 0); */ /* fixed frameheight */ + gtk_box_pack_start(GTK_BOX(xsane_vbox), xsane_frame, TRUE, TRUE, 0); /* sizeable framehight */ + gtk_widget_show(xsane_frame); + +/* xsane_vbox_xsane_modus = gtk_vbox_new(FALSE, 5); */ + xsane_vbox_xsane_modus = gtk_vbox_new(FALSE, 1); + gtk_container_add(GTK_CONTAINER(xsane_frame), xsane_vbox_xsane_modus); + gtk_widget_show(xsane_vbox_xsane_modus); + +/* scan copy fax selection */ + + if ( (xsane.mode == XSANE_STANDALONE) && (xsane.mode_selection) ) /* display xsane mode selection menu */ + { + xsane_hbox_xsane_modus = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(xsane_hbox_xsane_modus), 2); + gtk_box_pack_start(GTK_BOX(xsane_vbox_xsane_modus), xsane_hbox_xsane_modus, FALSE, FALSE, 0); + + xsane_label = gtk_label_new(TEXT_XSANE_MODE); + gtk_box_pack_start(GTK_BOX(xsane_hbox_xsane_modus), xsane_label, FALSE, FALSE, 2); + gtk_widget_show(xsane_label); + + xsane_modus_menu = gtk_menu_new(); + + xsane_modus_item = gtk_menu_item_new_with_label(MENU_ITEM_SCAN); + gtk_widget_set_usize(xsane_modus_item, 60, 0); + gtk_container_add(GTK_CONTAINER(xsane_modus_menu), xsane_modus_item); + gtk_signal_connect(GTK_OBJECT(xsane_modus_item), "activate", + (GtkSignalFunc) xsane_modus_callback, &xsane_scanmode_number[XSANE_SCAN]); + gtk_widget_show(xsane_modus_item); + + xsane_modus_item = gtk_menu_item_new_with_label(MENU_ITEM_COPY); + gtk_container_add(GTK_CONTAINER(xsane_modus_menu), xsane_modus_item); + gtk_signal_connect(GTK_OBJECT(xsane_modus_item), "activate", + (GtkSignalFunc) xsane_modus_callback, &xsane_scanmode_number[XSANE_COPY]); + gtk_widget_show(xsane_modus_item); + + xsane_modus_item = gtk_menu_item_new_with_label(MENU_ITEM_FAX); + gtk_container_add(GTK_CONTAINER(xsane_modus_menu), xsane_modus_item); + gtk_signal_connect(GTK_OBJECT(xsane_modus_item), "activate", + (GtkSignalFunc) xsane_modus_callback, &xsane_scanmode_number[XSANE_FAX]); + gtk_widget_show(xsane_modus_item); + + xsane_modus_option_menu = gtk_option_menu_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, xsane_modus_option_menu, DESC_XSANE_MODE); + gtk_box_pack_end(GTK_BOX(xsane_hbox_xsane_modus), xsane_modus_option_menu, FALSE, FALSE, 2); + gtk_option_menu_set_menu(GTK_OPTION_MENU(xsane_modus_option_menu), xsane_modus_menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(xsane_modus_option_menu), xsane.xsane_mode); + gtk_widget_show(xsane_modus_option_menu); + gtk_widget_show(xsane_hbox_xsane_modus); + + dialog->xsanemode_widget = xsane_modus_option_menu; + } + + { + GtkWidget *pixmapwidget; + GdkBitmap *mask; + GdkPixmap *pixmap; + GtkWidget *hbox; + const SANE_Option_Descriptor *opt; + + + /* colormode */ + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.scanmode); + if (opt) + { + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + 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, 2); + + pixmap = gdk_pixmap_create_from_xpm_d(xsane.histogram_dialog->window, &mask, xsane.bg_trans, (gchar **) colormode_xpm); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); + gdk_pixmap_unref(pixmap); + gtk_widget_show(pixmapwidget); + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_STRING_LIST: + { + char *set; + SANE_Status status; + + /* use a "list-selection" widget */ + set = malloc(opt->size); + status = sane_control_option(dialog->dev, dialog->well_known.scanmode, SANE_ACTION_GET_VALUE, set, 0); + + xsane_option_menu_new(hbox, (char **) opt->constraint.string_list, set, dialog->well_known.scanmode, + _BGT(opt->desc), 0, SANE_OPTION_IS_SETTABLE(opt->cap), 0); + } + break; + + default: + fprintf(stderr, "scanmode_selection: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + } + gtk_widget_show(hbox); + } + } + + + /* input selection */ + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.scansource); + if (opt) + { + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + 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, 2); + + pixmap = gdk_pixmap_create_from_xpm_d(xsane.histogram_dialog->window, &mask, xsane.bg_trans, (gchar **) scanner_xpm); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); + gdk_pixmap_unref(pixmap); + gtk_widget_show(pixmapwidget); + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_STRING_LIST: + { + char *set; + SANE_Status status; + + /* use a "list-selection" widget */ + set = malloc(opt->size); + status = sane_control_option(dialog->dev, dialog->well_known.scansource, SANE_ACTION_GET_VALUE, set, 0); + + xsane_option_menu_new(hbox, (char **) opt->constraint.string_list, set, dialog->well_known.scansource, + _BGT(opt->desc), 0, SANE_OPTION_IS_SETTABLE(opt->cap), 0); + } + break; + + default: + fprintf(stderr, "scansource_selection: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + } + gtk_widget_show(hbox); + } + } + + } + + if (xsane.xsane_mode == XSANE_SCAN) + { + xsane.copy_number_entry = 0; + + if (xsane.mode == XSANE_STANDALONE) + { + xsane_outputfilename_new(xsane_vbox_xsane_modus); + } + + /* resolution selection */ + if (!xsane_resolution_widget_new(xsane_vbox_xsane_modus, dialog->well_known.dpi_x, &xsane.resolution_x, resolution_x_xpm, + DESC_RESOLUTION_X, XSANE_GTK_NAME_X_RESOLUTION)) /* draw x resolution widget if possible */ + { + xsane_resolution_widget_new(xsane_vbox_xsane_modus, dialog->well_known.dpi_y, &xsane.resolution_y, resolution_y_xpm, + DESC_RESOLUTION_Y, XSANE_GTK_NAME_Y_RESOLUTION); /* ok, also draw y resolution widget */ + } + else /* no x resolution, so lets draw common resolution widget */ + { + xsane_resolution_widget_new(xsane_vbox_xsane_modus, dialog->well_known.dpi, &xsane.resolution, resolution_xpm, + DESC_RESOLUTION, XSANE_GTK_NAME_RESOLUTION); + } + } + else if (xsane.xsane_mode == XSANE_COPY) + { + GtkWidget *pixmapwidget, *hbox, *xsane_printer_option_menu, *xsane_printer_menu, *xsane_printer_item; + GdkBitmap *mask; + GdkPixmap *pixmap; + int i; + + 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, 2); + + pixmap = gdk_pixmap_create_from_xpm_d(xsane.histogram_dialog->window, &mask, xsane.bg_trans, (gchar **) printer_xpm); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); + gdk_pixmap_unref(pixmap); + gtk_widget_show(pixmapwidget); + + xsane_printer_menu = gtk_menu_new(); + + for (i=0; i < preferences.printerdefinitions; i++) + { + xsane_printer_item = gtk_menu_item_new_with_label(preferences.printer[i]->name); + gtk_container_add(GTK_CONTAINER(xsane_printer_menu), xsane_printer_item); + gtk_signal_connect(GTK_OBJECT(xsane_printer_item), "activate", (GtkSignalFunc) xsane_printer_callback, (void *) i); + gtk_widget_show(xsane_printer_item); + } + + xsane_printer_option_menu = gtk_option_menu_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, xsane_printer_option_menu, DESC_PRINTER_SELECT); + gtk_box_pack_end(GTK_BOX(hbox), xsane_printer_option_menu, FALSE, FALSE, 2); + gtk_widget_show(xsane_printer_option_menu); + gtk_widget_show(hbox); + + gtk_option_menu_set_menu(GTK_OPTION_MENU(xsane_printer_option_menu), xsane_printer_menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(xsane_printer_option_menu), preferences.printernr); + + /* number of copies */ + xsane_text = gtk_entry_new(); + xsane_back_gtk_set_tooltip(dialog->tooltips, xsane_text, DESC_COPY_NUMBER); + gtk_widget_set_usize(xsane_text, 25, 0); + snprintf(buf, sizeof(buf), "%d", xsane.copy_number); + gtk_entry_set_text(GTK_ENTRY(xsane_text), (char *) buf); + gtk_box_pack_end(GTK_BOX(hbox), xsane_text, FALSE, FALSE, 10); + gtk_widget_show(xsane_text); + gtk_widget_show(hbox); + xsane.copy_number_entry = xsane_text; + + /* zoom selection */ + if (!xsane_zoom_widget_new(xsane_vbox_xsane_modus, dialog->well_known.dpi_x, &xsane.zoom_x, + xsane.resolution_x, zoom_x_xpm, DESC_ZOOM_X)) + { + xsane_zoom_widget_new(xsane_vbox_xsane_modus, dialog->well_known.dpi_y, &xsane.zoom_y, + xsane.resolution_y, zoom_y_xpm, DESC_ZOOM_Y); + } + else + { + xsane_zoom_widget_new(xsane_vbox_xsane_modus, dialog->well_known.dpi, &xsane.zoom, + xsane.resolution, zoom_xpm, DESC_ZOOM); + } + } + else /* XSANE_FAX */ + { + const SANE_Option_Descriptor *opt; + + xsane.copy_number_entry = 0; + xsane.resolution = 98; + xsane.resolution_x = 98; + xsane.resolution_y = 98; + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.dpi); + if (!opt) + { + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.dpi_x); + } + + if (opt) + { + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + xsane_button = gtk_check_button_new_with_label(RADIO_BUTTON_FINE_MODE); + xsane_back_gtk_set_tooltip(dialog->tooltips, xsane_button, DESC_FAX_FINE_MODE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xsane_button), xsane.fax_fine_mode); + gtk_box_pack_start(GTK_BOX(xsane_vbox_xsane_modus), xsane_button, FALSE, FALSE, 2); + gtk_widget_show(xsane_button); + gtk_signal_connect(GTK_OBJECT(xsane_button), "clicked", (GtkSignalFunc) xsane_fax_fine_mode_callback, 0); + + if (xsane.fax_fine_mode) + { + xsane.resolution = 196; + xsane.resolution_x = 98; + xsane.resolution_y = 196; + } + + xsane_set_all_resolutions(); + } + } + xsane_fax_dialog(); + } + + /* test if scanner gamma table is selected */ + + xsane.scanner_gamma_gray = FALSE; + if (dialog->well_known.gamma_vector >0) + { + const SANE_Option_Descriptor *opt; + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector); + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + xsane.scanner_gamma_gray = TRUE; + } + } + + xsane.scanner_gamma_color = FALSE; + if (dialog->well_known.gamma_vector_r >0) + { + const SANE_Option_Descriptor *opt; + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector_r); + if (SANE_OPTION_IS_ACTIVE(opt->cap)) + { + xsane.scanner_gamma_color = TRUE; + } + } + + + + /* XSane Frame Enhancement */ + + sane_get_parameters(dialog->dev, &xsane.param); /* update xsane.param */ + + if (xsane.param.depth == 1) + { + return(xsane_hbox); + } + + xsane.slider_gray.active = XSANE_SLIDER_ACTIVE; /* mark slider active */ + + if ( (xsane.xsane_color) && (!xsane.enhancement_rgb_default) ) + { + xsane_separator_new(xsane_vbox_xsane_modus, 2); + } + + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), Gamma_xpm, DESC_GAMMA, + XSANE_GAMMA_MIN, XSANE_GAMMA_MAX, 0.01, 0.01, 0.0, 2, + &xsane.gamma, &xsane.gamma_widget, 0, xsane_gamma_changed, TRUE); + if ( (xsane.xsane_color) && (!xsane.enhancement_rgb_default) ) + { + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), Gamma_red_xpm, DESC_GAMMA_R, + XSANE_GAMMA_MIN, XSANE_GAMMA_MAX, 0.01, 0.01, 0.0, 2, + &xsane.gamma_red , &xsane.gamma_red_widget, 0, xsane_gamma_changed, TRUE); + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), Gamma_green_xpm, DESC_GAMMA_G, + XSANE_GAMMA_MIN, XSANE_GAMMA_MAX, 0.01, 0.01, 0.0, 2, + &xsane.gamma_green, &xsane.gamma_green_widget, 0, xsane_gamma_changed, TRUE); + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), Gamma_blue_xpm, DESC_GAMMA_B, + XSANE_GAMMA_MIN, XSANE_GAMMA_MAX, 0.01, 0.01, 0.0, 2, + &xsane.gamma_blue , &xsane.gamma_blue_widget, 0, xsane_gamma_changed, TRUE); + + xsane_separator_new(xsane_vbox_xsane_modus, 2); + } + + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), brightness_xpm, DESC_BRIGHTNESS, + XSANE_BRIGHTNESS_MIN, XSANE_BRIGHTNESS_MAX, 1.0, 1.0, 0.0, 0, + &xsane.brightness, &xsane.brightness_widget, 0, xsane_gamma_changed, TRUE); + if ( (xsane.xsane_color) && (!xsane.enhancement_rgb_default) ) + { + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), brightness_red_xpm, DESC_BRIGHTNESS_R, + XSANE_BRIGHTNESS_MIN, XSANE_BRIGHTNESS_MAX, 1.0, 1.0, 0.0, 0, + &xsane.brightness_red , &xsane.brightness_red_widget, 0, xsane_gamma_changed, TRUE); + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), brightness_green_xpm, DESC_BRIGHTNESS_G, + XSANE_BRIGHTNESS_MIN, XSANE_BRIGHTNESS_MAX, 1.0, 1.0, 0.0, 0, + &xsane.brightness_green, &xsane.brightness_green_widget, 0, xsane_gamma_changed, TRUE); + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), brightness_blue_xpm, DESC_BRIGHTNESS_B, + XSANE_BRIGHTNESS_MIN, XSANE_BRIGHTNESS_MAX, 1.0, 1.0, 0.0, 0, + &xsane.brightness_blue, &xsane.brightness_blue_widget, 0, xsane_gamma_changed, TRUE); + + xsane_separator_new(xsane_vbox_xsane_modus, 2); + } + + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), contrast_xpm, DESC_CONTRAST, + XSANE_CONTRAST_GRAY_MIN, XSANE_CONTRAST_MAX, 1.0, 1.0, 0.0, 0, + &xsane.contrast, &xsane.contrast_widget, 0, xsane_gamma_changed, TRUE); + if ( (xsane.xsane_color) && (!xsane.enhancement_rgb_default) ) + { + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), contrast_red_xpm, DESC_CONTRAST_R, + XSANE_CONTRAST_MIN, XSANE_CONTRAST_MAX, 1.0, 1.0, 0.0, 0, + &xsane.contrast_red , &xsane.contrast_red_widget, 0, xsane_gamma_changed, TRUE); + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), contrast_green_xpm, DESC_CONTRAST_G, + XSANE_CONTRAST_MIN, XSANE_CONTRAST_MAX, 1.0, 1.0, 0.0, 0, + &xsane.contrast_green, &xsane.contrast_green_widget, 0, xsane_gamma_changed, TRUE); + xsane_scale_new_with_pixmap(GTK_BOX(xsane_vbox_xsane_modus), contrast_blue_xpm, DESC_CONTRAST_B, + XSANE_CONTRAST_MIN, XSANE_CONTRAST_MAX, 1.0, 1.0, 0.0, 0, + &xsane.contrast_blue, &xsane.contrast_blue_widget, 0, xsane_gamma_changed, TRUE); + } + + xsane_separator_new(xsane_vbox_xsane_modus, 2); + + /* create lower button box (rgb default, negative ,... */ + xsane_hbox_xsane_enhancement = gtk_hbox_new(TRUE, 4); + gtk_container_set_border_width(GTK_CONTAINER(xsane_hbox_xsane_enhancement), 4); + 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_color) + { + xsane_toggle_button_new_with_pixmap(xsane_hbox_xsane_enhancement, rgb_default_xpm, DESC_RGB_DEFAULT, + &xsane.enhancement_rgb_default, xsane_enhancement_rgb_default_callback); + } + + xsane_toggle_button_new_with_pixmap(xsane_hbox_xsane_enhancement, negative_xpm, DESC_NEGATIVE, + &xsane.negative, xsane_enhancement_negative_callback); + + xsane_button_new_with_pixmap(xsane_hbox_xsane_enhancement, enhance_xpm, DESC_ENH_AUTO, + xsane_auto_enhancement_callback, 0); + + xsane_button_new_with_pixmap(xsane_hbox_xsane_enhancement, default_enhancement_xpm, DESC_ENH_DEFAULT, + xsane_enhancement_restore_default, 0); + + xsane_button_new_with_pixmap(xsane_hbox_xsane_enhancement, restore_enhancement_xpm, DESC_ENH_RESTORE, + xsane_enhancement_restore, 0); + + xsane_button_new_with_pixmap(xsane_hbox_xsane_enhancement, store_enhancement_xpm, DESC_ENH_STORE, + xsane_enhancement_store, 0); + + xsane_update_histogram(); + + return(xsane_hbox); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_update_preview(GSGDialog *dialog, void *arg) +{ + if (xsane.preview) + { + preview_update_surface(xsane.preview, 0); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_pref_save(void) +{ + char filename[PATH_MAX]; + int fd; + + /* first save xsane-specific preferences: */ + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, "xsane", 0, ".rc", XSANE_PATH_LOCAL_SANE); + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_CREATE_FILE, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + return; + } + preferences_save(fd); + close(fd); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_pref_restore(void) +{ + char filename[PATH_MAX]; + int fd; + + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, "xsane", 0, ".rc", XSANE_PATH_LOCAL_SANE); + fd = open(filename, O_RDONLY); + + if (fd >= 0) + { + preferences_restore(fd); + close(fd); + } + else /* no local sane file, look for system file */ + { + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, "xsane", 0, ".rc", XSANE_PATH_SYSTEM); + fd = open(filename, O_RDONLY); + + if (fd >= 0) + { + preferences_restore(fd); + close(fd); + } + } + + if (!preferences.filename) + { + preferences.filename = strdup(OUTFILENAME); + } + + if (preferences.printerdefinitions == 0) + { + xsane_new_printer(); + } + + if (!preferences.fax_project) + { + preferences.fax_project = strdup(FAXPROJECT); + } + + if (!preferences.fax_command) + { + preferences.fax_command = strdup(FAXCOMMAND); + } + + if (!preferences.fax_receiver_option) + { + preferences.fax_receiver_option = strdup(FAXRECEIVEROPT); + } + + if (!preferences.fax_postscript_option) + { + preferences.fax_postscript_option = strdup(FAXPOSTSCRIPTOPT); + } + + if (!preferences.fax_normal_option) + { + preferences.fax_normal_option = strdup(FAXNORMALOPT); + } + + if (!preferences.fax_fine_option) + { + preferences.fax_fine_option = strdup(FAXFINEOPT); + } + + if (!preferences.fax_viewer) + { + preferences.fax_viewer = strdup(FAXVIEWER); + } + + if (!preferences.doc_viewer) + { + preferences.doc_viewer = strdup(DOCVIEWER); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_quit(void) +{ + if (xsane.preview) + { + Preview *preview = xsane.preview; + xsane.preview = 0; + preview_destroy(preview); + } + + while (xsane_back_gtk_message_dialog_active) + { + gtk_main_iteration(); + } + + if (dialog && xsane_back_gtk_dialog_get_device(dialog)) + { + sane_close(xsane_back_gtk_dialog_get_device(dialog)); + } + + sane_exit(); + gtk_main_quit(); + + if (xsane.preview_gamma_data_red) + { + free(xsane.preview_gamma_data_red); + free(xsane.preview_gamma_data_green); + free(xsane.preview_gamma_data_blue); + + xsane.preview_gamma_data_red = 0; + xsane.preview_gamma_data_green = 0; + xsane.preview_gamma_data_blue = 0; + } + +#ifdef HAVE_LIBGIMP_GIMP_H + if (xsane.mode == XSANE_GIMP_EXTENSION) + { + gimp_quit(); + } +#endif + exit(0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_exit(void) /* this is called when xsane exits before gtk_main is called */ +{ + while (xsane_back_gtk_message_dialog_active) + { + gtk_main_iteration(); + } + + sane_exit(); + +#ifdef HAVE_LIBGIMP_GIMP_H + if (xsane.mode == XSANE_GIMP_EXTENSION) + { + gimp_quit(); + } +#endif + exit(0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static gint xsane_standard_option_win_delete(GtkWidget *widget, gpointer data) +{ + gtk_widget_hide(widget); + preferences.show_standard_options = FALSE; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_standard_options_widget), preferences.show_standard_options); + return TRUE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static gint xsane_advanced_option_win_delete(GtkWidget *widget, gpointer data) +{ + gtk_widget_hide(widget); + preferences.show_advanced_options = FALSE; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_advanced_options_widget), preferences.show_advanced_options); + return TRUE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* Invoked when window manager's "delete" (or "close") function is invoked. */ +static gint xsane_scan_win_delete(GtkWidget *w, gpointer data) +{ + xsane_scan_done(-1); /* stop scanner when still scanning */ + + if (xsane.filetype) /* add extension to filename */ + { + char buffer[256]; + + snprintf(buffer, sizeof(buffer), "%s%s", preferences.filename, xsane.filetype); + free(preferences.filename); + free(xsane.filetype); + xsane.filetype = 0; + preferences.filename = strdup(buffer); + } + + xsane_pref_save(); + xsane_quit(); + return FALSE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static gint xsane_preview_window_destroyed(GtkWidget *widget, gpointer call_data) +{ + gtk_widget_hide(widget); + xsane.show_preview = FALSE; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_preview_widget), FALSE); + return TRUE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_show_preview_callback(GtkWidget * widget, gpointer call_data) +{ + if (GTK_CHECK_MENU_ITEM(widget)->active) + { + gtk_widget_show(xsane.preview->top); + xsane.show_preview = TRUE; + } + else + { + gtk_widget_hide(xsane.preview->top); + xsane.show_preview = FALSE; + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static GtkWidget *xsane_files_build_menu(void) +{ + GtkWidget *menu, *item; + + menu = gtk_menu_new(); + + item = gtk_menu_item_new(); + gtk_container_add(GTK_CONTAINER(menu), item); + gtk_widget_show(item); + + + /* XSane about dialog */ + + item = gtk_menu_item_new_with_label(MENU_ITEM_ABOUT); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_about_dialog, 0); + gtk_widget_show(item); + + + /* XSane info dialog */ + + item = gtk_menu_item_new_with_label(MENU_ITEM_INFO); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_info_dialog, 0); + gtk_widget_show(item); + + + /* Exit */ + + item = gtk_menu_item_new_with_label(MENU_ITEM_EXIT); + gtk_container_add(GTK_CONTAINER(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_scan_win_delete, 0); + gtk_widget_show(item); + + return menu; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_set_pref_unit_callback(GtkWidget *widget, gpointer data) +{ + const char *unit = data; + double unit_conversion_factor = 1.0; + + gtk_signal_handler_block_by_func(GTK_OBJECT(xsane.length_unit_mm), (GtkSignalFunc) xsane_set_pref_unit_callback, "mm"); + gtk_signal_handler_block_by_func(GTK_OBJECT(xsane.length_unit_cm), (GtkSignalFunc) xsane_set_pref_unit_callback, "cm"); + gtk_signal_handler_block_by_func(GTK_OBJECT(xsane.length_unit_in), (GtkSignalFunc) xsane_set_pref_unit_callback, "in"); + + if (strcmp(unit, "mm") == 0) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.length_unit_mm), TRUE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.length_unit_cm), FALSE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.length_unit_in), FALSE); + } + else if (strcmp(unit, "cm") == 0) + { + unit_conversion_factor = 10.0; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.length_unit_mm), FALSE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.length_unit_cm), TRUE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.length_unit_in), FALSE); + } + else if (strcmp(unit, "in") == 0) + { + unit_conversion_factor = 25.4; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.length_unit_mm), FALSE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.length_unit_cm), FALSE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.length_unit_in), TRUE); + } + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(xsane.length_unit_mm), (GtkSignalFunc) xsane_set_pref_unit_callback, "mm"); + gtk_signal_handler_unblock_by_func(GTK_OBJECT(xsane.length_unit_cm), (GtkSignalFunc) xsane_set_pref_unit_callback, "cm"); + gtk_signal_handler_unblock_by_func(GTK_OBJECT(xsane.length_unit_in), (GtkSignalFunc) xsane_set_pref_unit_callback, "in"); + + preferences.length_unit = unit_conversion_factor; + + xsane_refresh_dialog(dialog); + if (xsane.preview) + { + preview_area_resize(xsane.preview->window); + } + + xsane_pref_save(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_set_update_policy_callback(GtkWidget *widget, gpointer data) +{ + GtkUpdateType policy = (GtkUpdateType) data; + + gtk_signal_handler_block_by_func(GTK_OBJECT(xsane.update_policy_continu), (GtkSignalFunc) xsane_set_update_policy_callback, + (void *) GTK_UPDATE_CONTINUOUS); + gtk_signal_handler_block_by_func(GTK_OBJECT(xsane.update_policy_discont), (GtkSignalFunc) xsane_set_update_policy_callback, + (void *) GTK_UPDATE_DISCONTINUOUS); + gtk_signal_handler_block_by_func(GTK_OBJECT(xsane.update_policy_delayed), (GtkSignalFunc) xsane_set_update_policy_callback, + (void *) GTK_UPDATE_DELAYED); + + if (policy == GTK_UPDATE_CONTINUOUS) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.update_policy_continu), TRUE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.update_policy_discont), FALSE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.update_policy_delayed), FALSE); + } + else if (policy == GTK_UPDATE_DISCONTINUOUS) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.update_policy_continu), FALSE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.update_policy_discont), TRUE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.update_policy_delayed), FALSE); + } + else if (policy == GTK_UPDATE_DELAYED) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.update_policy_continu), FALSE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.update_policy_discont), FALSE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.update_policy_delayed), TRUE); + } + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(xsane.update_policy_continu), (GtkSignalFunc) xsane_set_update_policy_callback, + (void *) GTK_UPDATE_CONTINUOUS); + gtk_signal_handler_unblock_by_func(GTK_OBJECT(xsane.update_policy_discont), (GtkSignalFunc) xsane_set_update_policy_callback, + (void *) GTK_UPDATE_DISCONTINUOUS); + gtk_signal_handler_unblock_by_func(GTK_OBJECT(xsane.update_policy_delayed), (GtkSignalFunc) xsane_set_update_policy_callback, + (void *) GTK_UPDATE_DELAYED); + + preferences.gtk_update_policy = policy; + xsane_pref_save(); + + xsane_back_gtk_refresh_dialog(dialog); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static gint xsane_close_info_callback(GtkWidget *widget, gpointer data) +{ + GtkWidget *dialog = data; + + gtk_widget_destroy(dialog); + + xsane_set_sensitivity(TRUE); + + xsane_update_histogram(); + + return FALSE; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_info_dialog(GtkWidget *widget, gpointer data) +{ + GtkWidget *info_dialog, *vbox, *button, *label, *frame, *framebox, *hbox, *table; + char buf[256]; + char *bufptr; + + sane_get_parameters(dialog->dev, &xsane.param); /* update xsane.param */ + + info_dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_position(GTK_WINDOW(info_dialog), GTK_WIN_POS_CENTER); + gtk_window_set_policy(GTK_WINDOW(info_dialog), FALSE, FALSE, FALSE); + gtk_signal_connect(GTK_OBJECT(info_dialog), "destroy", GTK_SIGNAL_FUNC(xsane_close_info_callback), info_dialog); + snprintf(buf, sizeof(buf), "%s %s %s", prog_name, WINDOW_INFO, device_text); + gtk_window_set_title(GTK_WINDOW(info_dialog), buf); + + xsane_set_window_icon(info_dialog, 0); + + vbox = gtk_vbox_new(/* not homogeneous */ FALSE, 5); + gtk_container_add(GTK_CONTAINER(info_dialog), vbox); + gtk_widget_show(vbox); + + frame = gtk_frame_new(TEXT_SCANNER_BACKEND); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5); + gtk_widget_show(frame); + + framebox = gtk_vbox_new(/* not homogeneous */ FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame), framebox); + gtk_widget_show(framebox); + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(framebox), hbox, TRUE, TRUE, 5); + gtk_widget_show(hbox); + + table = gtk_table_new(6, 2, FALSE); + gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 5); + gtk_widget_show(table); + + snprintf(buf, sizeof(buf), TEXT_VENDOR); + label = xsane_info_table_text_new(table, buf, 0, 0); + snprintf(buf, sizeof(buf), "%s", devlist[seldev]->vendor); + label = xsane_info_table_text_new(table, buf, 1, 0); + + snprintf(buf, sizeof(buf), TEXT_MODEL); + label = xsane_info_table_text_new(table, buf, 0, 1); + snprintf(buf, sizeof(buf), "%s", devlist[seldev]->model); + label = xsane_info_table_text_new(table, buf, 1, 1); + + snprintf(buf, sizeof(buf), TEXT_TYPE); + label = xsane_info_table_text_new(table, buf, 0, 2); + snprintf(buf, sizeof(buf), "%s", devlist[seldev]->type); + label = xsane_info_table_text_new(table, buf, 1, 2); + + snprintf(buf, sizeof(buf), TEXT_DEVICE); + label = xsane_info_table_text_new(table, buf, 0, 3); + bufptr = strrchr(devlist[seldev]->name, ':'); + if (bufptr) + { + snprintf(buf, sizeof(buf), "%s", bufptr+1); + } + else + { + snprintf(buf, sizeof(buf), devlist[seldev]->name); + } + label = xsane_info_table_text_new(table, buf, 1, 3); + + snprintf(buf, sizeof(buf), "%s", devlist[seldev]->name); + bufptr = strrchr(buf, ':'); + if (bufptr) + { + *bufptr = 0; + label = xsane_info_table_text_new(table, buf, 1, 4); + snprintf(buf, sizeof(buf), TEXT_LOADED_BACKEND); + label = xsane_info_table_text_new(table, buf, 0, 4); + } + + snprintf(buf, sizeof(buf), TEXT_SANE_VERSION); + label = xsane_info_table_text_new(table, buf, 0, 5); + snprintf(buf, sizeof(buf), "%d.%d build %d",SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), + SANE_VERSION_MINOR(xsane.sane_backend_versioncode), + SANE_VERSION_BUILD(xsane.sane_backend_versioncode)); + label = xsane_info_table_text_new(table, buf, 1, 5); + + + frame = gtk_frame_new(TEXT_RECENT_VALUES); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5); + gtk_widget_show(frame); + + framebox = gtk_vbox_new(/* not homogeneous */ FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame), framebox); + gtk_widget_show(framebox); + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(framebox), hbox, TRUE, TRUE, 5); + gtk_widget_show(hbox); + + table = gtk_table_new(4, 2, FALSE); + gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 5); + gtk_widget_show(table); + + if ((xsane.xsane_color) && (xsane.scanner_gamma_color)) /* color gamma correction by scanner */ + { + const SANE_Option_Descriptor *opt; + + snprintf(buf, sizeof(buf), TEXT_GAMMA_CORR_BY); + label = xsane_info_table_text_new(table, buf, 0, 0); + snprintf(buf, sizeof(buf), TEXT_SCANNER); + label = xsane_info_table_text_new(table, buf, 1, 0); + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector_r); + + snprintf(buf, sizeof(buf), TEXT_GAMMA_INPUT_DEPTH); + label = xsane_info_table_text_new(table, buf, 0, 1); + snprintf(buf, sizeof(buf), "%d bit", (int) (0.5 + log((double)opt->size / sizeof(opt->type)) / log(2.0))); + label = xsane_info_table_text_new(table, buf, 1, 1); + + snprintf(buf, sizeof(buf), TEXT_GAMMA_OUTPUT_DEPTH); + label = xsane_info_table_text_new(table, buf, 0, 2); + 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_color) && (xsane.scanner_gamma_gray)) /* gray gamma correction by scanner */ + { + const SANE_Option_Descriptor *opt; + + snprintf(buf, sizeof(buf), TEXT_GAMMA_CORR_BY); + label = xsane_info_table_text_new(table, buf, 0, 0); + snprintf(buf, sizeof(buf), TEXT_SCANNER); + label = xsane_info_table_text_new(table, buf, 1, 0); + + opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector); + + snprintf(buf, sizeof(buf), TEXT_GAMMA_INPUT_DEPTH); + label = xsane_info_table_text_new(table, buf, 0, 1); + snprintf(buf, sizeof(buf), "%d bit", (int) (0.5 + log((double)opt->size / sizeof(opt->type)) / log(2.0))); + label = xsane_info_table_text_new(table, buf, 1, 1); + + snprintf(buf, sizeof(buf), TEXT_GAMMA_OUTPUT_DEPTH); + label = xsane_info_table_text_new(table, buf, 0, 2); + 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.param.depth != 1) /* gamma correction by xsane */ + { + snprintf(buf, sizeof(buf), TEXT_GAMMA_CORR_BY); + label = xsane_info_table_text_new(table, buf, 0, 0); + snprintf(buf, sizeof(buf), TEXT_SOFTWARE_XSANE); + label = xsane_info_table_text_new(table, buf, 1, 0); + + snprintf(buf, sizeof(buf), TEXT_GAMMA_INPUT_DEPTH); + label = xsane_info_table_text_new(table, buf, 0, 1); + snprintf(buf, sizeof(buf), "%d bit", xsane.param.depth); + label = xsane_info_table_text_new(table, buf, 1, 1); + + snprintf(buf, sizeof(buf), TEXT_GAMMA_OUTPUT_DEPTH); + label = xsane_info_table_text_new(table, buf, 0, 2); +/* snprintf(buf, sizeof(buf), "%d bit", 8); */ + snprintf(buf, sizeof(buf), "%d bit", xsane.param.depth); + label = xsane_info_table_text_new(table, buf, 1, 2); + } + else /* no gamma enhancement */ + { + snprintf(buf, sizeof(buf), TEXT_GAMMA_CORR_BY); + label = xsane_info_table_text_new(table, buf, 0, 0); + snprintf(buf, sizeof(buf), TEXT_NONE); + label = xsane_info_table_text_new(table, buf, 1, 0); + + snprintf(buf, sizeof(buf), TEXT_GAMMA_INPUT_DEPTH); + label = xsane_info_table_text_new(table, buf, 0, 1); + snprintf(buf, sizeof(buf), TEXT_NONE); + label = xsane_info_table_text_new(table, buf, 1, 1); + + snprintf(buf, sizeof(buf), TEXT_GAMMA_OUTPUT_DEPTH); + label = xsane_info_table_text_new(table, buf, 0, 2); + snprintf(buf, sizeof(buf), TEXT_NONE); + label = xsane_info_table_text_new(table, buf, 1, 2); + } + + snprintf(buf, sizeof(buf), TEXT_SCANNER_OUTPUT_DEPTH); + label = xsane_info_table_text_new(table, buf, 0, 3); + snprintf(buf, sizeof(buf), "%d bit", xsane.param.depth); + label = xsane_info_table_text_new(table, buf, 1, 3); + + frame = gtk_frame_new(TEXT_OUTPUT_FORMATS); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5); + gtk_widget_show(frame); + + framebox = gtk_vbox_new(/* not homogeneous */ FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame), framebox); + gtk_widget_show(framebox); + + hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(framebox), hbox, TRUE, TRUE, 5); + gtk_widget_show(hbox); + + table = gtk_table_new(2, 2, FALSE); + gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 5); + gtk_widget_show(table); + + snprintf(buf, sizeof(buf), TEXT_8BIT_FORMATS); + label = xsane_info_table_text_new(table, buf, 0, 0); + + bufptr=buf; + +#ifdef HAVE_LIBJPEG + sprintf(bufptr, "JPEG, "); + bufptr += strlen(bufptr); +#endif + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ + sprintf(bufptr, "PNG, "); + bufptr += strlen(bufptr); +#endif +#endif + + sprintf(bufptr, "PNM, "); + bufptr += strlen(bufptr); + + sprintf(bufptr, "PS, "); + bufptr += strlen(bufptr); + +#ifdef SUPPORT_RGBA + sprintf(bufptr, "RGBA, "); + bufptr += strlen(bufptr); +#endif + +#ifdef HAVE_LIBTIFF + sprintf(bufptr, "TIFF, "); + bufptr += strlen(bufptr); +#endif + + bufptr--; + bufptr--; + *bufptr = 0; /* erase last comma */ + + label = xsane_info_table_text_new(table, buf, 1, 0); + + snprintf(buf, sizeof(buf), TEXT_16BIT_FORMATS); + label = xsane_info_table_text_new(table, buf, 0, 1); + + bufptr=buf; + +#ifdef HAVE_LIBPNG +#ifdef HAVE_LIBZ + sprintf(bufptr, "PNG, "); + bufptr += strlen(bufptr); +#endif +#endif + + sprintf(bufptr, "PNM, "); + bufptr += strlen(bufptr); + + sprintf(bufptr, "RAW, "); + bufptr += strlen(bufptr); + +#ifdef SUPPORT_RGBA + sprintf(bufptr, "RGBA, "); + bufptr += strlen(bufptr); +#endif + + bufptr--; + bufptr--; + *bufptr = 0; /* erase last comma */ + + label = xsane_info_table_text_new(table, buf, 1, 1); + +/* gtk_label_set((GtkLabel *)label, "HALLO"); */ + + button = gtk_button_new_with_label(BUTTON_CLOSE); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_close_info_callback, info_dialog); + gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + gtk_widget_show(info_dialog); + + xsane_clear_histogram(&xsane.histogram_raw); + xsane_clear_histogram(&xsane.histogram_enh); + + xsane_set_sensitivity(FALSE); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_about_dialog(GtkWidget *widget, gpointer data) +{ + GtkWidget *about_dialog, *vbox, *button, *label; + char buf[256]; + GtkWidget *pixmapwidget; + GdkBitmap *mask; + GdkPixmap *pixmap; + GtkStyle *style; + GdkColor *bg_trans; + + + about_dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_position(GTK_WINDOW(about_dialog), GTK_WIN_POS_CENTER); + gtk_window_set_policy(GTK_WINDOW(about_dialog), FALSE, FALSE, FALSE); + gtk_signal_connect(GTK_OBJECT(about_dialog), "destroy", GTK_SIGNAL_FUNC(xsane_close_info_callback), about_dialog); + snprintf(buf, sizeof(buf), "%s %s", WINDOW_ABOUT, prog_name); + gtk_window_set_title(GTK_WINDOW(about_dialog), buf); + + xsane_set_window_icon(about_dialog, 0); + + vbox = gtk_vbox_new(/* not homogeneous */ FALSE, 5); + gtk_container_add(GTK_CONTAINER(about_dialog), vbox); + gtk_widget_show(vbox); + + /* xsane logo */ + gtk_widget_realize(about_dialog); + + style = gtk_widget_get_style(about_dialog); + bg_trans = &style->bg[GTK_STATE_NORMAL]; + + snprintf(buf, sizeof(buf), "%s/xsane-logo.xpm", STRINGIFY(PATH_SANE_DATA_DIR)); + pixmap = gdk_pixmap_create_from_xpm(about_dialog->window, &mask, bg_trans, buf); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(vbox), pixmapwidget, FALSE, FALSE, 2); + gtk_widget_show(pixmapwidget); + gdk_pixmap_unref(pixmap); + + xsane_separator_new(vbox, 5); + + snprintf(buf, sizeof(buf), "XSane %s %s\n", TEXT_VERSION, XSANE_VERSION); + label = gtk_label_new(buf); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + snprintf(buf, sizeof(buf), "(c) %s %s\n", XSANE_DATE, XSANE_COPYRIGHT); + label = gtk_label_new(buf); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + snprintf(buf, sizeof(buf), "%s %s\n", TEXT_EMAIL, XSANE_EMAIL); + label = gtk_label_new(buf); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + button = gtk_button_new_with_label(BUTTON_CLOSE); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_close_info_callback, about_dialog); + gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + gtk_widget_show(about_dialog); + + xsane_clear_histogram(&xsane.histogram_raw); + xsane_clear_histogram(&xsane.histogram_enh); + + xsane_set_sensitivity(FALSE); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static SANE_Status xsane_get_area_value(int option, float *val, SANE_Int *unit) +{ + const SANE_Option_Descriptor *opt; + SANE_Handle dev; + SANE_Word word; + + if (option <= 0) + { + return -1; + } + + if (sane_control_option(dialog->dev, option, SANE_ACTION_GET_VALUE, &word, 0) == SANE_STATUS_GOOD) + { + dev = dialog->dev; + opt = sane_get_option_descriptor(dev, option); + + if (unit) + { + *unit = opt->unit; + } + + if (val) + { + if (opt->type == SANE_TYPE_FIXED) + { + *val = (float) word / 65536.0; + } + else + { + *val = (float) word; + } + } + + return 0; + } + else if (val) + { + *val = 0; + } + return -2; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef XSANE_TEST +static void xsane_batch_scan_delete_callback(GtkWidget *widget, gpointer list) +{ + gtk_list_remove_items(GTK_LIST(list), GTK_LIST(list)->selection); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_batch_scan_add_callback(GtkWidget *widget, gpointer list) +{ + GtkWidget *list_item; + float tlx, tly, brx, bry; + SANE_Int unit; + char buf[255]; + + + xsane_get_area_value(dialog->well_known.coord[0], &tlx, &unit); + xsane_get_area_value(dialog->well_known.coord[1], &tly, &unit); + xsane_get_area_value(dialog->well_known.coord[2], &brx, &unit); + xsane_get_area_value(dialog->well_known.coord[3], &bry, &unit); + + if (unit == SANE_UNIT_MM) + { + snprintf(buf, sizeof(buf), " top left (%7.2fmm, %7.2fmm), bottom right (%7.2fmm, %7.2fmm)", tlx, tly, brx, bry); + } + else + { + snprintf(buf, sizeof(buf), " top left (%5.0fpx, %5.0fpx), bottom right (%5.0fpx, %5.0fpx)", tlx, tly, brx, bry); + } + + list_item = gtk_list_item_new_with_label(buf); + gtk_object_set_data(GTK_OBJECT(list_item), "list_item_data", strdup(buf)); + gtk_container_add(GTK_CONTAINER(list), list_item); + gtk_widget_show(list_item); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_batch_scan_dialog(GtkWidget *widget, gpointer data) +{ + GtkWidget *batch_scan_dialog, *batch_scan_vbox, *hbox, *button, *scrolled_window, *list; + char buf[64]; + + batch_scan_dialog = gtk_dialog_new(); + snprintf(buf, sizeof(buf), "%s %s", prog_name, WINDOW_BATCH_SCAN); + gtk_window_set_title(GTK_WINDOW(batch_scan_dialog), buf); + + batch_scan_vbox = GTK_DIALOG(batch_scan_dialog)->vbox; + + scrolled_window = gtk_scrolled_window_new(0, 0); + gtk_widget_set_usize(scrolled_window, 400, 200); + gtk_container_add(GTK_CONTAINER(batch_scan_vbox), scrolled_window); + gtk_widget_show(scrolled_window); + + list = gtk_list_new(); + + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), list); + + gtk_widget_show(list); + + + /* fill in action area: */ + hbox = GTK_DIALOG(batch_scan_dialog)->action_area; + + button = gtk_button_new_with_label(BUTTON_OK); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_close_dialog_callback, batch_scan_dialog); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_grab_default(button); + gtk_widget_show(button); + + button = gtk_button_new_with_label(BUTTON_ADD_AREA); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_batch_scan_add_callback, list); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + button = gtk_button_new_with_label(BUTTON_DELETE); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_batch_scan_delete_callback, list); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + gtk_widget_show(batch_scan_dialog); +} +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_dialog_delete() +{ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static 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; + GdkBitmap *mask; + GdkPixmap *pixmap; + + + if (xsane.fax_dialog) + { + return; /* window already is open */ + } + + fax_dialog = gtk_dialog_new(); + snprintf(buf, sizeof(buf), "%s %s", prog_name, WINDOW_FAX_PROJECT); + gtk_window_set_title(GTK_WINDOW(fax_dialog), buf); + gtk_signal_connect(GTK_OBJECT(fax_dialog), "delete_event", (GtkSignalFunc) xsane_fax_dialog_delete, 0); + xsane_set_window_icon(fax_dialog, 0); + + fax_scan_vbox = GTK_DIALOG(fax_dialog)->vbox; + + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); + gtk_box_pack_start(GTK_BOX(fax_scan_vbox), hbox, FALSE, FALSE, 2); + + pixmap = gdk_pixmap_create_from_xpm_d(xsane.shell->window, &mask, xsane.bg_trans, (gchar **) fax_xpm); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); + gdk_pixmap_unref(pixmap); + + text = gtk_entry_new_with_max_length(128); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAXPROJECT); + gtk_entry_set_text(GTK_ENTRY(text), (char *) preferences.fax_project); + gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 4); + gtk_signal_connect(GTK_OBJECT(text), "changed", (GtkSignalFunc) xsane_faxproject_changed_callback, 0); + + xsane.fax_project_entry = text; + + gtk_widget_show(pixmapwidget); + gtk_widget_show(text); + gtk_widget_show(hbox); + + fax_project_vbox = gtk_vbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(fax_scan_vbox), fax_project_vbox, TRUE, TRUE, 0); + gtk_widget_show(fax_project_vbox); + + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); + gtk_box_pack_start(GTK_BOX(fax_project_vbox), hbox, FALSE, FALSE, 2); + + gtk_widget_realize(fax_dialog); + + pixmap = gdk_pixmap_create_from_xpm_d(fax_dialog->window, &mask, xsane.bg_trans, (gchar **) faxreceiver_xpm); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2); + gdk_pixmap_unref(pixmap); + + text = gtk_entry_new_with_max_length(128); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAXRECEIVER); + gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 4); + gtk_signal_connect(GTK_OBJECT(text), "changed", (GtkSignalFunc) xsane_faxreceiver_changed_callback, 0); + + xsane.fax_receiver_entry = text; + + gtk_widget_show(pixmapwidget); + gtk_widget_show(text); + gtk_widget_show(hbox); + + + scrolled_window = gtk_scrolled_window_new(0, 0); + gtk_widget_set_usize(scrolled_window, 200, 100); + gtk_container_add(GTK_CONTAINER(fax_project_vbox), scrolled_window); + gtk_widget_show(scrolled_window); + + list = gtk_list_new(); +/* gtk_list_set_selection_mode(list, GTK_SELECTION_BROWSE); */ + + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), list); + + gtk_widget_show(list); + + xsane.fax_list = list; + + + hbox = gtk_hbox_new(FALSE, 2); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); + gtk_box_pack_start(GTK_BOX(fax_project_vbox), hbox, FALSE, FALSE, 2); + + button = gtk_button_new_with_label(BUTTON_SHOW); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_show_callback, list); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + button = gtk_button_new_with_label(BUTTON_RENAME); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_entry_rename_callback, list); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + button = gtk_button_new_with_label(BUTTON_DELETE); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_entry_delete_callback, list); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + xsane_button_new_with_pixmap(hbox, move_up_xpm, 0, (GtkSignalFunc) xsane_fax_entry_move_up_callback, list); + xsane_button_new_with_pixmap(hbox, move_down_xpm, 0, (GtkSignalFunc) xsane_fax_entry_move_down_callback, list); + + gtk_widget_show(hbox); + + xsane.fax_project_box = fax_project_vbox; + + /* fill in action area: */ + hbox = GTK_DIALOG(fax_dialog)->action_area; + + fax_project_exists_hbox = gtk_hbox_new(FALSE, 2); + gtk_box_pack_start(GTK_BOX(hbox), fax_project_exists_hbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label(BUTTON_SEND_PROJECT); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_send, 0); + gtk_box_pack_start(GTK_BOX(fax_project_exists_hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + button = gtk_button_new_with_label(BUTTON_DELETE_PROJECT); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_project_delete, 0); + gtk_box_pack_start(GTK_BOX(fax_project_exists_hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + gtk_widget_show(fax_project_exists_hbox); + xsane.fax_project_exists = fax_project_exists_hbox; + + button = gtk_button_new_with_label(BUTTON_CREATE_PROJECT); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_fax_project_create, 0); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + xsane.fax_project_not_exists = button; + + xsane.fax_dialog = fax_dialog; + + xsane_fax_project_load(); + + gtk_widget_show(fax_dialog); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_dialog_close() +{ + if (xsane.fax_dialog == 0) + { + return; + } + + gtk_widget_destroy(xsane.fax_dialog); + + xsane.fax_dialog = 0; + xsane.fax_list = 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_project_load() +{ + FILE *projectfile; + char page[256]; + char buf[256]; + GtkWidget *list_item; + int i; + char c; + + gtk_signal_disconnect_by_func(GTK_OBJECT(xsane.fax_receiver_entry), GTK_SIGNAL_FUNC(xsane_faxreceiver_changed_callback), 0); + gtk_list_remove_items(GTK_LIST(xsane.fax_list), GTK_LIST(xsane.fax_list)->children); + + snprintf(buf, sizeof(buf), "%s/project-list", preferences.fax_project); + projectfile = fopen(buf, "r"); + + if ((!projectfile) || (feof(projectfile))) + { + snprintf(buf, sizeof(buf), "%s/page-001.ps", preferences.fax_project); + xsane.fax_filename=strdup(buf); + + xsane.fax_receiver=strdup(""); + gtk_entry_set_text(GTK_ENTRY(xsane.fax_receiver_entry), (char *) xsane.fax_receiver); + + gtk_widget_set_sensitive(xsane.fax_project_box, FALSE); + gtk_widget_hide(xsane.fax_project_exists); + gtk_widget_show(xsane.fax_project_not_exists); + gtk_widget_set_sensitive(GTK_WIDGET(xsane.start_button), FALSE); + } + else + { + i=0; + c=0; + while ((i<255) && (c != 10) && (c != EOF)) /* first line is receiver phone number or address */ + { + c = fgetc(projectfile); + page[i++] = c; + } + page[i-1] = 0; + + xsane.fax_receiver=strdup(page); + gtk_entry_set_text(GTK_ENTRY(xsane.fax_receiver_entry), (char *) xsane.fax_receiver); + + + i=0; + c=0; + while ((i<255) && (c != 10) && (c != EOF)) /* second line is next fax filename */ + { + c = fgetc(projectfile); + page[i++] = c; + } + page[i-1] = 0; + + snprintf(buf, sizeof(buf), "%s/%s", preferences.fax_project, page); + xsane.fax_filename=strdup(buf); + + while (!feof(projectfile)) + { + i=0; + c=0; + + while ((i<255) && (c != 10) && (c != EOF)) + { + c = fgetc(projectfile); + page[i++] = c; + } + page[i-1]=0; + + if (c > 1) + { + list_item = gtk_list_item_new_with_label(page); + gtk_object_set_data(GTK_OBJECT(list_item), "list_item_data", strdup(page)); + gtk_container_add(GTK_CONTAINER(xsane.fax_list), list_item); + gtk_widget_show(list_item); + } + } + gtk_widget_set_sensitive(xsane.fax_project_box, TRUE); + gtk_widget_show(xsane.fax_project_exists); + gtk_widget_hide(xsane.fax_project_not_exists); + gtk_widget_set_sensitive(GTK_WIDGET(xsane.start_button), TRUE); + } + + if (projectfile) + { + fclose(projectfile); + } + + gtk_signal_connect(GTK_OBJECT(xsane.fax_receiver_entry), "changed", (GtkSignalFunc) xsane_faxreceiver_changed_callback, 0); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_project_delete() +{ + char *page; + char file[256]; + GList *list = (GList *) GTK_LIST(xsane.fax_list)->children; + GtkObject *list_item; + + while (list) + { + list_item = GTK_OBJECT(list->data); + page = strdup((char *) gtk_object_get_data(list_item, "list_item_data")); + xsane_convert_text_to_filename(&page); + snprintf(file, sizeof(file), "%s/%s.ps", preferences.fax_project, page); + free(page); + remove(file); + list = list->next; + } + snprintf(file, sizeof(file), "%s/project-list", preferences.fax_project); + remove(file); + snprintf(file, sizeof(file), "%s", preferences.fax_project); + rmdir(file); + + xsane_fax_project_load(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_fax_project_save() +{ + FILE *projectfile; + char *page; + char buf[256]; + GList *list = (GList *) GTK_LIST(xsane.fax_list)->children; + GtkObject *list_item; + + umask(preferences.directory_umask); /* define new file permissions */ + mkdir(preferences.fax_project, 0777); /* make sure directory exists */ + + snprintf(buf, sizeof(buf), "%s/project-list", preferences.fax_project); + umask(preferences.image_umask); /* define image file permissions */ + projectfile = fopen(buf, "w"); + umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ + + if (xsane.fax_receiver) + { + fprintf(projectfile, "%s\n", xsane.fax_receiver); /* first line is receiver phone number or address */ + } + else + { + fprintf(projectfile, "\n"); + } + + if (xsane.fax_filename) + { + fprintf(projectfile, "%s\n", strrchr(xsane.fax_filename, '/')+1); /* second line is next fax filename */ + } + else + { + fprintf(projectfile, "\n"); + } + + + while (list) + { + list_item = GTK_OBJECT(list->data); + page = (char *) gtk_object_get_data(list_item, "list_item_data"); + fprintf(projectfile, "%s\n", page); + list = list->next; + } + fclose(projectfile); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_project_create() +{ + if (strlen(preferences.fax_project)) + { + xsane_fax_project_save(); + xsane_fax_project_load(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_pref_toggle_tooltips(GtkWidget *widget, gpointer data) +{ + preferences.tooltips_enabled = (GTK_CHECK_MENU_ITEM(widget)->active != 0); + xsane_back_gtk_set_tooltips(dialog, preferences.tooltips_enabled); + xsane_pref_save(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_show_doc_via_nsr(GtkWidget *widget, gpointer data) /* show via netscape remote */ +{ + char *name = (char *) data; + char buf[256]; + FILE *ns_pipe; + pid_t pid; + char *arg[3]; + + snprintf(buf, sizeof(buf), "netscape -no-about-splash -remote \"openFile(%s/%s-doc.html)\" 2>&1", STRINGIFY(PATH_SANE_DATA_DIR), name); + ns_pipe = popen(buf, "r"); + + if (ns_pipe) + { + while (!feof(ns_pipe)) + { + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + fgetc(ns_pipe); /* remove char from pipe */ + } + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (pclose(ns_pipe)) /* netscape not running, start it */ + { + snprintf(buf, sizeof(buf), "%s/%s-doc.html", STRINGIFY(PATH_SANE_DATA_DIR), name); + arg[0] = "netscape"; + arg[1] = buf; + arg[2] = 0; + + pid = fork(); + + if (pid == 0) /* new process */ + { + execvp(arg[0], arg); /* does not return if successfully */ + fprintf(stderr, "%s %s\n", ERR_FAILD_EXEC_DOC_VIEWER, preferences.doc_viewer); + _exit(0); /* do not use exit() here! otherwise gtk gets in trouble */ + } + } + } + else /* execution failed */ + { + snprintf(buf, sizeof(buf), "%s", ERR_NETSCAPE_EXECUTE_FAIL); + xsane_back_gtk_error(buf, TRUE); + } + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_show_doc(GtkWidget *widget, gpointer data) +{ + char *name = (char *) data; + char buf[256]; + pid_t pid; + char *arg[3]; + + if (!strcmp(preferences.doc_viewer, DOCVIEWERNETSCAPEREMOTE)) + { + xsane_show_doc_via_nsr(widget, data); + } + else + { + snprintf(buf, sizeof(buf), "%s/%s-doc.html", STRINGIFY(PATH_SANE_DATA_DIR), name); + arg[0] = preferences.doc_viewer; + arg[1] = buf; + arg[2] = 0; + + pid = fork(); + + if (pid == 0) /* new process */ + { + execvp(arg[0], arg); /* does not return if successfully */ + fprintf(stderr, "%s %s\n", ERR_FAILD_EXEC_DOC_VIEWER, preferences.doc_viewer); + _exit(0); /* do not use exit() here! otherwise gtk gets in trouble */ + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_entrys_swap(GtkWidget *list_item_1, GtkWidget *list_item_2) +{ + char *text1; + char *text2; + + text1 = (char *) gtk_object_get_data(GTK_OBJECT(list_item_1), "list_item_data"); + text2 = (char *) gtk_object_get_data(GTK_OBJECT(list_item_2), "list_item_data"); + + gtk_label_set(GTK_LABEL(gtk_container_children(GTK_CONTAINER(list_item_1))->data), text2); + gtk_label_set(GTK_LABEL(gtk_container_children(GTK_CONTAINER(list_item_2))->data), text1); + gtk_object_set_data(GTK_OBJECT(list_item_1), "list_item_data", text2); + gtk_object_set_data(GTK_OBJECT(list_item_2), "list_item_data", text1); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_entry_move_up_callback(GtkWidget *widget, gpointer list) +{ + GList *select; + GList *item = GTK_LIST(list)->children; + GtkWidget *list_item_1; + GtkWidget *list_item_2; + int position; + int newpos; + + select = GTK_LIST(list)->selection; + if (select) + { + list_item_1 = select->data; + + position = gtk_list_child_position(GTK_LIST(list), list_item_1); + position--; /* move up */ + newpos = position; + + if (position >= 0) + { + while (position>0) + { + item = item->next; + position--; + } + + list_item_2 = item->data; + if (list_item_2) + { + xsane_fax_entrys_swap(list_item_1, list_item_2); + gtk_list_select_item(GTK_LIST(list), newpos); + xsane_fax_project_save(); + } + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_entry_move_down_callback(GtkWidget *widget, gpointer list) +{ + GList *select; + GList *item = GTK_LIST(list)->children; + GtkWidget *list_item_1; + GtkWidget *list_item_2; + int position; + int newpos; + + select = GTK_LIST(list)->selection; + if (select) + { + list_item_1 = select->data; + + position = gtk_list_child_position(GTK_LIST(list), list_item_1); + position++; /* move down */ + newpos = position; + + while ((position>0) && (item)) + { + item = item->next; + position--; + } + + if (item) + { + list_item_2 = item->data; + if (list_item_2) + { + xsane_fax_entrys_swap(list_item_1, list_item_2); + gtk_list_select_item(GTK_LIST(list), newpos); + xsane_fax_project_save(); + } + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +int xsane_fax_entry_rename; + +static void xsane_fax_entry_rename_button_callback(GtkWidget *widget, gpointer data) +{ + xsane_fax_entry_rename = (int) data; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_entry_rename_callback(GtkWidget *widget, gpointer list) +{ + GtkWidget *list_item; + GList *select; + char *oldpage; + char *newpage; + char oldfile[256]; + char newfile[256]; + + select = GTK_LIST(list)->selection; + if (select) + { + GtkWidget *rename_dialog; + GtkWidget *text; + GtkWidget *button; + GtkWidget *vbox, *hbox; + char buf[256]; + + list_item = select->data; + oldpage = strdup((char *) gtk_object_get_data(GTK_OBJECT(list_item), "list_item_data")); + + xsane_set_sensitivity(FALSE); + + rename_dialog = gtk_dialog_new(); + gtk_window_set_position(GTK_WINDOW(rename_dialog), GTK_WIN_POS_CENTER); + gtk_window_set_policy(GTK_WINDOW(rename_dialog), FALSE, FALSE, FALSE); + snprintf(buf, sizeof(buf), "%s %s", prog_name, WINDOW_FAX_RENAME); + gtk_window_set_title(GTK_WINDOW(rename_dialog), buf); + gtk_signal_connect(GTK_OBJECT(rename_dialog), "delete_event", (GtkSignalFunc) xsane_fax_entry_rename_button_callback, (void *) -1); + gtk_widget_show(rename_dialog); + + vbox = GTK_DIALOG(rename_dialog)->vbox; + + text = gtk_entry_new_with_max_length(64); + xsane_back_gtk_set_tooltip(dialog->tooltips, text, DESC_FAXPAGENAME); + gtk_entry_set_text(GTK_ENTRY(text), oldpage); + gtk_widget_set_usize(text, 300, 0); + gtk_box_pack_start(GTK_BOX(vbox), text, TRUE, TRUE, 4); + gtk_widget_show(text); + + + hbox = GTK_DIALOG(rename_dialog)->action_area; + + button = gtk_button_new_with_label("OK"); + gtk_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); + + button = gtk_button_new_with_label("Cancel"); + gtk_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); + + + xsane_fax_entry_rename = 0; + + while (xsane_fax_entry_rename == 0) + { + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + } + + newpage = strdup(gtk_entry_get_text(GTK_ENTRY(text))); + + if (xsane_fax_entry_rename == 1) + { + gtk_label_set(GTK_LABEL(gtk_container_children(GTK_CONTAINER(list_item))->data), newpage); + gtk_object_set_data(GTK_OBJECT(list_item), "list_item_data", strdup(newpage)); + + xsane_convert_text_to_filename(&oldpage); + xsane_convert_text_to_filename(&newpage); + snprintf(oldfile, sizeof(oldfile), "%s/%s.ps", preferences.fax_project, oldpage); + snprintf(newfile, sizeof(newfile), "%s/%s.ps", preferences.fax_project, newpage); + + rename(oldfile, newfile); + + xsane_fax_project_save(); + } + + free(oldpage); + free(newpage); + + gtk_widget_destroy(rename_dialog); + + xsane_set_sensitivity(TRUE); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_entry_delete_callback(GtkWidget *widget, gpointer list) +{ + GtkObject *list_item; + GList *select; + char *page; + char file[256]; + + select = GTK_LIST(list)->selection; + if (select) + { + list_item = GTK_OBJECT(select->data); + page = strdup((char *) gtk_object_get_data(list_item, "list_item_data")); + xsane_convert_text_to_filename(&page); + snprintf(file, sizeof(file), "%s/%s.ps", preferences.fax_project, page); + free(page); + remove(file); + gtk_widget_destroy(GTK_WIDGET(list_item)); + xsane_fax_project_save(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_show_callback(GtkWidget *widget, gpointer list) +{ + GtkObject *list_item; + GList *select; + pid_t pid; + char *arg[100]; + char *page; + char buf[256]; + int argnr; + + select = GTK_LIST(list)->selection; + if (select) + { + argnr = xsane_parse_options(preferences.fax_viewer, arg); + + list_item = GTK_OBJECT(select->data); + page = (char *) gtk_object_get_data(list_item, "list_item_data"); + page = strdup(page); + xsane_convert_text_to_filename(&page); + snprintf(buf, sizeof(buf), "%s/%s.ps", preferences.fax_project, page); + free(page); + arg[argnr++] = buf; + arg[argnr] = 0; + + pid = fork(); + + if (pid == 0) /* new process */ + { + execvp(arg[0], arg); /* does not return if successfully */ + fprintf(stderr, "%s %s\n", ERR_FAILD_EXEC_FAX_VIEWER, preferences.fax_viewer); + _exit(0); /* do not use exit() here! otherwise gtk gets in trouble */ + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_fax_send() +{ + char *page; + GList *list = (GList *) GTK_LIST(xsane.fax_list)->children; + GtkObject *list_item; + pid_t pid; + char *arg[1000]; + char buf[256]; + int argnr = 0; + int i; + + if (list) + { + if (!xsane_option_defined(xsane.fax_receiver)) + { + snprintf(buf, sizeof(buf), "%s\n", ERR_SENDFAX_RECEIVER_MISSING); + xsane_back_gtk_error(buf, TRUE); + return; + } + + argnr = xsane_parse_options(preferences.fax_command, arg); + + if (xsane.fax_fine_mode) /* fine mode */ + { + if (xsane_option_defined(preferences.fax_fine_option)) + { + arg[argnr++] = strdup(preferences.fax_fine_option); + } + } + else /* normal mode */ + { + if (xsane_option_defined(preferences.fax_normal_option)) + { + arg[argnr++] = strdup(preferences.fax_normal_option); + } + } + + if (xsane_option_defined(preferences.fax_receiver_option)) + { + arg[argnr++] = strdup(preferences.fax_receiver_option); + } + arg[argnr++] = strdup(xsane.fax_receiver); + + if (xsane_option_defined(preferences.fax_postscript_option)) + { + arg[argnr++] = strdup(preferences.fax_postscript_option); + } + + while ((list) && (argnr<999)) /* add pages to options */ + { + list_item = GTK_OBJECT(list->data); + page = strdup((char *) gtk_object_get_data(list_item, "list_item_data")); + xsane_convert_text_to_filename(&page); + snprintf(buf, sizeof(buf), "%s/%s.ps", preferences.fax_project, page); + free(page); + arg[argnr++] = strdup(buf); + list = list->next; + } + + arg[argnr] = 0; + + pid = fork(); + + if (pid == 0) /* new process */ + { + execvp(arg[0], arg); /* does not return if successfully */ + fprintf(stderr, "%s %s\n", ERR_FAILED_EXEC_FAX_CMD, preferences.fax_command); + _exit(0); /* do not use exit() here! otherwise gtk gets in trouble */ + } + + for (i=0; i<argnr; i++) + { + free(arg[i]); + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static GtkWidget *xsane_view_build_menu(void) +{ + GtkWidget *menu, *item; + + menu = gtk_menu_new(); + + + /* show tooltips */ + + item = gtk_check_menu_item_new_with_label(MENU_ITEM_SHOW_TOOLTIPS); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), preferences.tooltips_enabled); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + gtk_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_pref_toggle_tooltips, 0); + + + /* insert separator: */ + + item = gtk_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + + /* show preview */ + + xsane.show_preview_widget = gtk_check_menu_item_new_with_label(MENU_ITEM_SHOW_PREVIEW); + gtk_menu_append(GTK_MENU(menu), xsane.show_preview_widget); + gtk_widget_show(xsane.show_preview_widget); + gtk_signal_connect(GTK_OBJECT(xsane.show_preview_widget), "toggled", (GtkSignalFunc) xsane_show_preview_callback, 0); + + /* show histogram */ + + xsane.show_histogram_widget = gtk_check_menu_item_new_with_label(MENU_ITEM_SHOW_HISTOGRAM); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_histogram_widget), preferences.show_histogram); + gtk_menu_append(GTK_MENU(menu), xsane.show_histogram_widget); + gtk_widget_show(xsane.show_histogram_widget); + gtk_signal_connect(GTK_OBJECT(xsane.show_histogram_widget), "toggled", (GtkSignalFunc) xsane_show_histogram_callback, 0); + + + /* show standard options */ + + xsane.show_standard_options_widget = gtk_check_menu_item_new_with_label(MENU_ITEM_SHOW_STANDARDOPTIONS); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_standard_options_widget), preferences.show_standard_options); + gtk_menu_append(GTK_MENU(menu), xsane.show_standard_options_widget); + gtk_widget_show(xsane.show_standard_options_widget); + gtk_signal_connect(GTK_OBJECT(xsane.show_standard_options_widget), "toggled", (GtkSignalFunc) xsane_show_standard_options_callback, 0); + + + /* show advanced options */ + + xsane.show_advanced_options_widget = gtk_check_menu_item_new_with_label(MENU_ITEM_SHOW_ADVANCEDOPTIONS); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_advanced_options_widget), preferences.show_advanced_options); + gtk_menu_append(GTK_MENU(menu), xsane.show_advanced_options_widget); + gtk_widget_show(xsane.show_advanced_options_widget); + gtk_signal_connect(GTK_OBJECT(xsane.show_advanced_options_widget), "toggled", + (GtkSignalFunc) xsane_show_advanced_options_callback, 0); + + return menu; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static GtkWidget *xsane_pref_build_menu(void) +{ + GtkWidget *menu, *item, *submenu, *subitem; + + menu = gtk_menu_new(); + + + /* XSane setup dialog */ + + item = gtk_menu_item_new_with_label(MENU_ITEM_SETUP); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_setup_dialog, 0); + gtk_widget_show(item); + + /* insert separator: */ + + item = gtk_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + +#ifdef XSANE_TEST + /* XSane batch scan dialog */ + + item = gtk_menu_item_new_with_label("Batch scan"); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_batch_scan_dialog, 0); + gtk_widget_show(item); + + /* insert separator: */ + + item = gtk_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); +#endif + + + /* length unit */ + + item = gtk_menu_item_new_with_label(MENU_ITEM_LENGTH_UNIT); + 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_LENGTH_MILLIMETERS); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (preferences.length_unit == 1.0) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + gtk_signal_connect(GTK_OBJECT(subitem), "activate", (GtkSignalFunc) xsane_set_pref_unit_callback, "mm"); + gtk_widget_show(subitem); + xsane.length_unit_mm = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_LENGTH_CENTIMETERS); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (preferences.length_unit == 10.0) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + gtk_signal_connect(GTK_OBJECT(subitem), "activate", (GtkSignalFunc) xsane_set_pref_unit_callback, "cm"); + gtk_widget_show(subitem); + xsane.length_unit_cm = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_LENGTH_INCHES); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (preferences.length_unit == 25.4) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + gtk_signal_connect(GTK_OBJECT(subitem), "activate", (GtkSignalFunc) xsane_set_pref_unit_callback, "in"); + gtk_widget_show(subitem); + xsane.length_unit_in = subitem; + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); + + xsane.length_unit_widget = item; + + + /* insert separator: */ + + item = gtk_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + /* update policy */ + + item = gtk_menu_item_new_with_label(MENU_ITEM_UPDATE_POLICY); + 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_POLICY_CONTINUOUS); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (preferences.gtk_update_policy == GTK_UPDATE_CONTINUOUS) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + gtk_signal_connect(GTK_OBJECT(subitem), "activate", (GtkSignalFunc) xsane_set_update_policy_callback, (void *) GTK_UPDATE_CONTINUOUS); + gtk_widget_show(subitem); + xsane.update_policy_continu = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_POLICY_DISCONTINU); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (preferences.gtk_update_policy == GTK_UPDATE_DISCONTINUOUS) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + gtk_signal_connect(GTK_OBJECT(subitem), "activate", (GtkSignalFunc) xsane_set_update_policy_callback, (void *) GTK_UPDATE_DISCONTINUOUS); + gtk_widget_show(subitem); + xsane.update_policy_discont = subitem; + + subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_POLICY_DELAYED); + gtk_menu_append(GTK_MENU(submenu), subitem); + if (preferences.gtk_update_policy == GTK_UPDATE_DELAYED) + { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE); + } + gtk_signal_connect(GTK_OBJECT(subitem), "activate", (GtkSignalFunc) xsane_set_update_policy_callback, (void *) GTK_UPDATE_DELAYED); + gtk_widget_show(subitem); + xsane.update_policy_delayed = subitem; + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); + + + /* insert separator: */ + + item = gtk_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + + /* show resolution list */ + + xsane.show_resolution_list_widget = gtk_check_menu_item_new_with_label(MENU_ITEM_SHOW_RESOLUTIONLIST); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_resolution_list_widget), preferences.show_resolution_list); + gtk_menu_append(GTK_MENU(menu), xsane.show_resolution_list_widget); + gtk_widget_show(xsane.show_resolution_list_widget); + gtk_signal_connect(GTK_OBJECT(xsane.show_resolution_list_widget), "toggled", + (GtkSignalFunc) xsane_show_resolution_list_callback, 0); + + + /* insert separator: */ + + item = gtk_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + + /* page orientation */ + + item = gtk_check_menu_item_new_with_label(MENU_ITEM_PAGE_ROTATE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), preferences.psrotate); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + gtk_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_page_rotate_callback, 0); + + + + /* insert separator: */ + + item = gtk_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + /* Save device setting */ + + item = gtk_menu_item_new_with_label(MENU_ITEM_SAVE_DEVICE_SETTINGS); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_device_preferences_save, 0); + gtk_widget_show(item); + + /* Load device setting */ + + item = gtk_menu_item_new_with_label(MENU_ITEM_LOAD_DEVICE_SETTINGS); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_device_preferences_load, 0); + gtk_widget_show(item); + + return menu; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static GtkWidget *xsane_help_build_menu(void) +{ + GtkWidget *menu, *item; + + menu = gtk_menu_new(); + + item = gtk_menu_item_new_with_label(MENU_ITEM_XSANE_DOC); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_show_doc, (void *) "sane-xsane"); + gtk_widget_show(item); + + item = gtk_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + if (xsane.backend) + { + item = gtk_menu_item_new_with_label(MENU_ITEM_BACKEND_DOC); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_show_doc, (void *) xsane.backend); + gtk_widget_show(item); + } + + item = gtk_menu_item_new_with_label(MENU_ITEM_AVAILABLE_BACKENDS); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_show_doc, (void *) "sane-backends"); + gtk_widget_show(item); + + item = gtk_menu_item_new_with_label(MENU_ITEM_PROBLEMS); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_show_doc, (void *) "sane-problems"); + gtk_widget_show(item); + + item = gtk_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), item); + gtk_widget_show(item); + + item = gtk_menu_item_new_with_label(MENU_ITEM_SCANTIPS); + gtk_menu_append(GTK_MENU(menu), item); + gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_show_doc, (void *) "sane-scantips"); + gtk_widget_show(item); + + return menu; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_panel_build(GSGDialog *dialog) +{ + GtkWidget *xsane_hbox; + GtkWidget *standard_hbox, *standard_vbox; + GtkWidget *advanced_hbox, *advanced_vbox; + GtkWidget *parent, *vbox, *button, *label; + const SANE_Option_Descriptor *opt; + SANE_Handle dev = dialog->dev; + double dval, dmin, dmax, dquant; + char *buf, str[16], title[256]; + GSGDialogElement *elem; + SANE_Word quant, val; + SANE_Status status; + SANE_Int num_words; + char **str_list; + int i, j; + int num_vector_opts = 0; + int *vector_opts; + + xsane_hbox = 0; + + /* reset well-known options: */ + dialog->well_known.scanmode = -1; + dialog->well_known.scansource = -1; + dialog->well_known.preview = -1; + dialog->well_known.dpi = -1; + dialog->well_known.dpi_x = -1; + dialog->well_known.dpi_y = -1; + dialog->well_known.coord[xsane_back_gtk_TL_X] = -1; + dialog->well_known.coord[xsane_back_gtk_TL_Y] = -1; + dialog->well_known.coord[xsane_back_gtk_BR_X] = -1; + dialog->well_known.coord[xsane_back_gtk_BR_Y] = -1; + dialog->well_known.gamma_vector = -1; + dialog->well_known.gamma_vector_r = -1; + dialog->well_known.gamma_vector_g = -1; + dialog->well_known.gamma_vector_b = -1; + dialog->well_known.bit_depth = -1; + + + /* standard options */ + standard_hbox = gtk_hbox_new(FALSE, 2); + gtk_widget_show(standard_hbox); + standard_vbox = gtk_vbox_new(/* homogeneous */ FALSE, 0); + gtk_widget_show(standard_vbox); +/* gtk_box_pack_start(GTK_BOX(standard_hbox), standard_vbox, FALSE, FALSE, 0); */ /* make frame fixed */ + gtk_box_pack_start(GTK_BOX(standard_hbox), standard_vbox, TRUE, TRUE, 0); /* make frame sizeable */ + + /* advanced options */ + advanced_hbox = gtk_hbox_new(FALSE, 2); + gtk_widget_show(advanced_hbox); + advanced_vbox = gtk_vbox_new(/* homogeneous */ FALSE, 0); + gtk_widget_show(advanced_vbox); +/* gtk_box_pack_start(GTK_BOX(advanced_hbox), advanced_vbox, FALSE, FALSE, 0); */ /* make frame fixed */ + gtk_box_pack_start(GTK_BOX(advanced_hbox), advanced_vbox, TRUE, TRUE, 0); /* make frame sizeable */ + + + vector_opts = alloca(dialog->num_elements * sizeof (int)); + + parent = standard_vbox; + for (i = 1; i < dialog->num_elements; ++i) + { + opt = sane_get_option_descriptor (dev, i); + if (!SANE_OPTION_IS_ACTIVE(opt->cap)) + continue; + + /* pick up well-known options as we go: */ + if (opt->name) + { + if (strcmp(opt->name, SANE_NAME_PREVIEW) == 0 && opt->type == SANE_TYPE_BOOL) + { + dialog->well_known.preview = i; + continue; + } + else if (strcmp(opt->name, SANE_NAME_SCAN_RESOLUTION) == 0 + && opt->unit == SANE_UNIT_DPI && (opt->type == SANE_TYPE_INT || opt->type == SANE_TYPE_FIXED)) + dialog->well_known.dpi = i; + else if (strcmp(opt->name, SANE_NAME_SCAN_X_RESOLUTION) == 0 + && opt->unit == SANE_UNIT_DPI && (opt->type == SANE_TYPE_INT || opt->type == SANE_TYPE_FIXED)) + dialog->well_known.dpi_x = i; + else if (strcmp(opt->name, SANE_NAME_SCAN_Y_RESOLUTION) == 0 + && opt->unit == SANE_UNIT_DPI && (opt->type == SANE_TYPE_INT || opt->type == SANE_TYPE_FIXED)) + dialog->well_known.dpi_y = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_MODE) == 0) + dialog->well_known.scanmode = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_SOURCE) == 0) + dialog->well_known.scansource = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_TL_X) == 0) + dialog->well_known.coord[xsane_back_gtk_TL_X] = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_TL_Y) == 0) + dialog->well_known.coord[xsane_back_gtk_TL_Y] = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_BR_X) == 0) + dialog->well_known.coord[xsane_back_gtk_BR_X] = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_BR_Y) == 0) + dialog->well_known.coord[xsane_back_gtk_BR_Y] = i; + else if (strcmp (opt->name, SANE_NAME_GAMMA_VECTOR) == 0) + dialog->well_known.gamma_vector = i; + else if (strcmp (opt->name, SANE_NAME_GAMMA_VECTOR_R) == 0) + dialog->well_known.gamma_vector_r = i; + else if (strcmp (opt->name, SANE_NAME_GAMMA_VECTOR_G) == 0) + dialog->well_known.gamma_vector_g = i; + else if (strcmp (opt->name, SANE_NAME_GAMMA_VECTOR_B) == 0) + dialog->well_known.gamma_vector_b = i; + else if (strcmp (opt->name, SANE_NAME_BIT_DEPTH) == 0) + dialog->well_known.bit_depth = i; + } + + elem = dialog->element + i; + elem->dialog = dialog; + + + if (opt->unit == SANE_UNIT_NONE) + { + snprintf(title, sizeof(title), "%s", _BGT(opt->title)); + } + else + { + snprintf(title, sizeof(title), "%s [%s]", _BGT(opt->title), xsane_back_gtk_unit_string(opt->unit)); + } + + switch (opt->type) + { + case SANE_TYPE_GROUP: + /* group a set of options */ + vbox = standard_vbox; + if (opt->cap & SANE_CAP_ADVANCED) + { + vbox = advanced_vbox; + } + parent = xsane_back_gtk_group_new(vbox, title); + elem->widget = parent; + break; + + case SANE_TYPE_BOOL: + assert(opt->size == sizeof(SANE_Word)); + status = sane_control_option(dialog->dev, i, SANE_ACTION_GET_VALUE, &val, 0); + if (status != SANE_STATUS_GOOD) + { + goto get_value_failed; + } + xsane_back_gtk_button_new(parent, title, val, elem, dialog->tooltips, _BGT(opt->desc), SANE_OPTION_IS_SETTABLE(opt->cap)); + gtk_widget_show(parent->parent); + break; + + case SANE_TYPE_INT: + if (opt->size != sizeof(SANE_Word)) + { + vector_opts[num_vector_opts++] = i; + break; + } + status = sane_control_option(dialog->dev, i, SANE_ACTION_GET_VALUE, &val, 0); + if (status != SANE_STATUS_GOOD) + { + goto get_value_failed; + } + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + if ( (strcmp(opt->name, SANE_NAME_SCAN_RESOLUTION) ) && /* do not show resolution */ + (strcmp(opt->name, SANE_NAME_SCAN_X_RESOLUTION)) && /* do not show x-resolution */ + (strcmp(opt->name, SANE_NAME_SCAN_Y_RESOLUTION)) ) /* do not show y-resolution */ + { + /* use a scale */ + quant = opt->constraint.range->quant; + if (quant == 0) + quant = 1; + xsane_back_gtk_scale_new(parent, title, val, opt->constraint.range->min, opt->constraint.range->max, quant, + (opt->cap & SANE_CAP_AUTOMATIC), elem, dialog->tooltips, _BGT(opt->desc), SANE_OPTION_IS_SETTABLE(opt->cap)); + gtk_widget_show(parent->parent); + } + break; + + case SANE_CONSTRAINT_WORD_LIST: + if ( (strcmp(opt->name, SANE_NAME_SCAN_RESOLUTION) ) && /* do not show resolution */ + (strcmp(opt->name, SANE_NAME_SCAN_X_RESOLUTION)) && /* do not show x-resolution */ + (strcmp(opt->name, SANE_NAME_SCAN_Y_RESOLUTION)) ) /* do not show y-resolution */ + { + /* use a "list-selection" widget */ + num_words = opt->constraint.word_list[0]; + str_list = malloc((num_words + 1) * sizeof(str_list[0])); + for (j = 0; j < num_words; ++j) + { + sprintf(str, "%d", opt->constraint.word_list[j + 1]); + str_list[j] = strdup(str); + } + str_list[j] = 0; + sprintf(str, "%d", val); + xsane_back_gtk_option_menu_new(parent, title, str_list, str, elem, dialog->tooltips, _BGT(opt->desc), + SANE_OPTION_IS_SETTABLE(opt->cap)); + free(str_list); + gtk_widget_show(parent->parent); + } + break; + + default: + fprintf(stderr, "xsane_panel_build: %s %d!\n", ERR_UNKNOWN_CONSTRAINT_TYPE, opt->constraint_type); + break; + } + break; + + case SANE_TYPE_FIXED: + if (opt->size != sizeof (SANE_Word)) + { + vector_opts[num_vector_opts++] = i; + break; + } + status = sane_control_option(dialog->dev, i, SANE_ACTION_GET_VALUE, &val, 0); + if (status != SANE_STATUS_GOOD) + { + goto get_value_failed; + } + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + if ( (strcmp(opt->name, SANE_NAME_SCAN_RESOLUTION) ) && /* do not show resolution */ + (strcmp(opt->name, SANE_NAME_SCAN_X_RESOLUTION)) && /* do not show x-resolution */ + (strcmp(opt->name, SANE_NAME_SCAN_Y_RESOLUTION)) ) /* do not show y-resolution */ + { + /* use a scale */ + quant = opt->constraint.range->quant; + if (quant == 0) + quant = 1; + dval = SANE_UNFIX(val); + dmin = SANE_UNFIX(opt->constraint.range->min); + dmax = SANE_UNFIX(opt->constraint.range->max); + dquant = SANE_UNFIX(quant); + if (opt->unit == SANE_UNIT_MM) + { + dval /= preferences.length_unit; + dmin /= preferences.length_unit; + dmax /= preferences.length_unit; + dquant /= preferences.length_unit; + } + xsane_back_gtk_scale_new(parent, title, dval, dmin, dmax, dquant, (opt->cap & SANE_CAP_AUTOMATIC), elem, + dialog->tooltips, _BGT(opt->desc), SANE_OPTION_IS_SETTABLE(opt->cap)); + gtk_widget_show(parent->parent); + } + break; + + case SANE_CONSTRAINT_WORD_LIST: + if ( (strcmp(opt->name, SANE_NAME_SCAN_RESOLUTION) ) && /* do not show resolution */ + (strcmp(opt->name, SANE_NAME_SCAN_X_RESOLUTION)) && /* do not show x-resolution */ + (strcmp(opt->name, SANE_NAME_SCAN_Y_RESOLUTION)) ) /* do not show y-resolution */ + { + /* use a "list-selection" widget */ + num_words = opt->constraint.word_list[0]; + str_list = malloc ((num_words + 1) * sizeof (str_list[0])); + for (j = 0; j < num_words; ++j) + { + sprintf(str, "%g", SANE_UNFIX(opt->constraint.word_list[j + 1])); + str_list[j] = strdup (str); + } + str_list[j] = 0; + sprintf(str, "%g", SANE_UNFIX (val)); + xsane_back_gtk_option_menu_new(parent, title, str_list, str, elem, dialog->tooltips, _BGT(opt->desc), SANE_OPTION_IS_SETTABLE(opt->cap)); + free (str_list); + gtk_widget_show(parent->parent); + } + break; + + default: + fprintf(stderr, "xsane_panel_build: %s %d!\n", ERR_UNKNOWN_CONSTRAINT_TYPE, opt->constraint_type); + break; + } + break; + + case SANE_TYPE_STRING: + buf = malloc (opt->size); + status = sane_control_option(dialog->dev, i, SANE_ACTION_GET_VALUE, buf, 0); + if (status != SANE_STATUS_GOOD) + { + free (buf); + goto get_value_failed; + } + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_STRING_LIST: + if ( (strcmp (opt->name, SANE_NAME_SCAN_MODE) != 0) && /* do not show scanmode */ + (strcmp (opt->name, SANE_NAME_SCAN_SOURCE) != 0) ) /* do not show scansource */ + { + /* use a "list-selection" widget */ + xsane_back_gtk_option_menu_new(parent, title, (char **) opt->constraint.string_list, buf, + elem, dialog->tooltips, _BGT(opt->desc), SANE_OPTION_IS_SETTABLE(opt->cap)); + gtk_widget_show (parent->parent); + } + break; + + case SANE_CONSTRAINT_NONE: + xsane_back_gtk_text_entry_new(parent, title, buf, elem, dialog->tooltips, _BGT(opt->desc), SANE_OPTION_IS_SETTABLE(opt->cap)); + gtk_widget_show (parent->parent); + break; + + default: + fprintf(stderr, "xsane_panel_build: %s %d!\n", ERR_UNKNOWN_CONSTRAINT_TYPE, opt->constraint_type); + break; + } + free (buf); + break; + + case SANE_TYPE_BUTTON: + button = gtk_button_new(); + gtk_signal_connect(GTK_OBJECT (button), "clicked", (GtkSignalFunc) xsane_back_gtk_push_button_callback, elem); + xsane_back_gtk_set_tooltip(dialog->tooltips, button, _BGT(opt->desc)); + + label = gtk_label_new(title); + gtk_container_add(GTK_CONTAINER (button), label); + + gtk_box_pack_start(GTK_BOX (parent), button, FALSE, TRUE, 0); + + gtk_widget_show(label); + gtk_widget_show(button); + + gtk_widget_set_sensitive(button, SANE_OPTION_IS_SETTABLE(opt->cap)); + + elem->widget = button; + gtk_widget_show(parent->parent); + break; + + default: + fprintf(stderr, "xsane_panel_build: %s %d\n", ERR_UNKNOWN_TYPE, opt->type); + break; + } + continue; + + get_value_failed: + { + char msg[256]; + + sprintf(msg, "%s %s: %s.", ERR_GET_OPTION, opt->name, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(msg, TRUE); + } + } + + if ((dialog->well_known.dpi_x == -1) && (dialog->well_known.dpi_y != -1)) + { + dialog->well_known.dpi_x = dialog->well_known.dpi; + } + + xsane_hbox = xsane_update_xsane_callback(); + + gtk_container_add(GTK_CONTAINER(dialog->xsane_window), xsane_hbox); + gtk_container_add(GTK_CONTAINER(dialog->standard_window), standard_hbox); + gtk_container_add(GTK_CONTAINER(dialog->advanced_window), advanced_hbox); + + dialog->xsane_hbox = xsane_hbox; + dialog->standard_hbox = standard_hbox; + dialog->advanced_hbox = advanced_hbox; + + xsane_update_histogram(); +/* + xsane_draw_slider_level(&xsane.slider_gray); + xsane_draw_slider_level(&xsane.slider_red); + xsane_draw_slider_level(&xsane.slider_green); + xsane_draw_slider_level(&xsane.slider_blue); +*/ + xsane_update_sliders(); + + if (xsane.length_unit_widget) + { + int unit; + + status = xsane_get_area_value(dialog->well_known.coord[0], 0, &unit); + + if ( (unit == SANE_UNIT_PIXEL) || (status) ) + { + gtk_widget_set_sensitive(xsane.length_unit_widget, FALSE); + } + else + { + gtk_widget_set_sensitive(xsane.length_unit_widget, TRUE); + } + } + + /* now add in vector editor, if necessary: */ +/* + if (num_vector_opts) + vector_new (dialog, custom_gamma_vbox, num_vector_opts, vector_opts); +*/ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* Create the main dialog box. */ + +static void xsane_device_dialog(void) +{ + GtkWidget *hbox, *button, *frame, *infobox; + GtkWidget *main_dialog_window, *standard_dialog_window, *advanced_dialog_window; + GtkWidget *menubar, *menubar_item; + const gchar *devname; + char buf[256]; + char windowname[255]; + char devicetext[255]; + char *textptr; + GtkWidget *xsane_window; + GtkWidget *xsane_vbox_main; + GtkWidget *xsane_vbox_standard; + GtkWidget *xsane_vbox_advanced; + GdkColormap *colormap; + SANE_Int num_elements; + SANE_Status status; + SANE_Handle dev; + + + devname = devlist[seldev]->name; + + status = sane_open(devname, &dev); + if (status != SANE_STATUS_GOOD) + { + snprintf(buf, sizeof(buf), "%s `%s':\n %s.", ERR_DEVICE_OPEN_FAILED, devname, XSANE_STRSTATUS(status)); + xsane_back_gtk_error(buf, TRUE); + return; + } + + if (sane_control_option(dev, 0, SANE_ACTION_GET_VALUE, &num_elements, 0) != SANE_STATUS_GOOD) + { + xsane_back_gtk_error(ERR_OPTION_COUNT, TRUE); + sane_close(dev); + return; + } + + snprintf(buf, sizeof(buf), "%s", devlist[seldev]->name); /* generate "sane-BACKENDNAME" */ + textptr = strrchr(buf, ':'); /* format is midend:midend:midend:backend:device or backend:device */ + if (textptr) + { + *textptr = 0; /* erase ":device" at end of text */ + textptr = strrchr(buf, ':'); + if (textptr) /* midend:backend:device */ + { + textptr++; + } + else /* backend:device */ + { + textptr = buf; + } + + xsane.backend = malloc(strlen(textptr)+6); + sprintf(xsane.backend, "sane-%s", textptr); /* add "sane-" */ + + bindtextdomain(xsane.backend, LOCALEDIR); /* set path for backend translation texts */ + } + + /* create device-text for window titles */ + + snprintf(devicetext, sizeof(devicetext), "%s", devlist[seldev]->model); + textptr = devicetext + strlen(devicetext); + while (*(textptr-1) == ' ') /* erase spaces at end of text */ + { + textptr--; + } + + *textptr = ':'; + textptr++; + *textptr = 0; + + if (!strncmp(devname, "net:", 4)) /* network device ? */ + { + sprintf(textptr, "net:"); + textptr = devicetext + strlen(devicetext); + } + + snprintf(buf, sizeof(buf), ":%s", devname); + snprintf(buf, sizeof(buf), "/%s", (strrchr(buf, ':')+1)); + sprintf(textptr, (strrchr(buf, '/')+1)); + + device_text = strdup(devicetext); + + + /* if no preferences filename is given on commandline create one from devicenaname */ + + if (!xsane.device_set_filename) + { + if (!strcmp(devlist[seldev]->vendor, TEXT_UNKNOWN)) + { + snprintf(buf, sizeof(buf), "%s", devlist[seldev]->name); + } + else + { + snprintf(buf, sizeof(buf), "%s:%s", devlist[seldev]->vendor, devlist[seldev]->model); + } + xsane.device_set_filename = strdup(buf); /* set preferences filename */ + } + + + xsane_pref_restore(); /* restore preferences */ + + if (xsane.main_window_fixed == -1) /* no command line option given */ + { + xsane.main_window_fixed = preferences.main_window_fixed; + } + + + /* create the xsane dialog box */ + + xsane.shell = gtk_dialog_new(); + gtk_widget_set_uposition(xsane.shell, XSANE_SHELL_POS_X, XSANE_SHELL_POS_Y); + sprintf(windowname, "%s %s %s", prog_name, XSANE_VERSION, device_text); + gtk_window_set_title(GTK_WINDOW(xsane.shell), (char *) windowname); + gtk_signal_connect(GTK_OBJECT(xsane.shell), "delete_event", GTK_SIGNAL_FUNC(xsane_scan_win_delete), 0); + + xsane_set_window_icon(xsane.shell, 0); + + /* set the main vbox */ + + xsane_window = GTK_DIALOG(xsane.shell)->vbox; + gtk_widget_show(xsane_window); /* normally not necessary, but to be sure */ + + /* create the menubar */ + + menubar = gtk_menu_bar_new(); + gtk_box_pack_start(GTK_BOX(xsane_window), menubar, FALSE, FALSE, 0); + + /* "Files" submenu: */ + menubar_item = gtk_menu_item_new_with_label(MENU_FILE); + gtk_container_add(GTK_CONTAINER(menubar), menubar_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_files_build_menu()); + gtk_widget_show(menubar_item); + + /* "Preferences" submenu: */ + menubar_item = gtk_menu_item_new_with_label(MENU_PREFERENCES); + gtk_container_add(GTK_CONTAINER(menubar), menubar_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_pref_build_menu()); + gtk_widget_show(menubar_item); + + /* "View" submenu: */ + menubar_item = gtk_menu_item_new_with_label(MENU_VIEW); + gtk_container_add(GTK_CONTAINER(menubar), menubar_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_view_build_menu()); + gtk_widget_show(menubar_item); + + + /* "Help" submenu: */ + menubar_item = gtk_menu_item_new_with_label(MENU_HELP); + gtk_container_add(GTK_CONTAINER(menubar), menubar_item); + gtk_menu_item_right_justify((GtkMenuItem *) menubar_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_help_build_menu()); + gtk_widget_show(menubar_item); + + gtk_widget_show(menubar); + + if (xsane.main_window_fixed) /* fixed window: use it like it is */ + { + /* shrink grow auto_shrink */ + gtk_window_set_policy(GTK_WINDOW(xsane.shell), FALSE, FALSE, TRUE); /* auto size */ + + xsane_vbox_main = gtk_vbox_new(TRUE, 5); /* we need this to set the wanted borders */ + gtk_container_set_border_width(GTK_CONTAINER(xsane_vbox_main), 5); + gtk_container_add(GTK_CONTAINER(xsane_window), xsane_vbox_main); + } + else /* scrolled window: create a scrolled window and put it into the xsane dialog box */ + { + gtk_window_set_default_size(GTK_WINDOW(xsane.shell), XSANE_SHELL_WIDTH, XSANE_SHELL_HEIGHT); /* set default size */ + + /* shrink grow auto_shrink */ + gtk_window_set_policy(GTK_WINDOW(xsane.shell), TRUE, TRUE, FALSE); /* allow resizing */ + + xsane.main_dialog_scrolled = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(xsane.main_dialog_scrolled), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + gtk_container_add(GTK_CONTAINER(xsane_window), xsane.main_dialog_scrolled); + gtk_widget_show(xsane.main_dialog_scrolled); + + xsane_vbox_main = gtk_vbox_new(TRUE, 5); + gtk_container_set_border_width(GTK_CONTAINER(xsane_vbox_main), 5); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(xsane.main_dialog_scrolled), xsane_vbox_main); + } + + /* create a subwindow so the standard dialog keeps its position on rebuilds: */ + main_dialog_window = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(xsane_vbox_main), main_dialog_window, TRUE, TRUE, 0); + gtk_widget_show(main_dialog_window); + + gtk_widget_show(xsane_vbox_main); + + + /* create the scanner standard options dialog box */ + + xsane.standard_options_shell = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_widget_set_uposition(xsane.standard_options_shell, XSANE_STD_OPTIONS_POS_X, XSANE_STD_OPTIONS_POS_Y); + sprintf(windowname, "%s %s", WINDOW_STANDARD_OPTIONS, device_text); + gtk_window_set_title(GTK_WINDOW(xsane.standard_options_shell), (char *) windowname); + + /* shrink grow auto_shrink */ + gtk_window_set_policy(GTK_WINDOW(xsane.standard_options_shell), FALSE, FALSE, TRUE); + gtk_signal_connect(GTK_OBJECT(xsane.standard_options_shell), "delete_event", + GTK_SIGNAL_FUNC(xsane_standard_option_win_delete), 0); + + xsane_set_window_icon(xsane.standard_options_shell, 0); + + xsane_vbox_standard = gtk_vbox_new(TRUE, 5); + gtk_container_set_border_width(GTK_CONTAINER(xsane_vbox_standard), 5); + gtk_container_add(GTK_CONTAINER(xsane.standard_options_shell), xsane_vbox_standard); + gtk_widget_show(xsane_vbox_standard); + + /* create a subwindow so the standard dialog keeps its position on rebuilds: */ + standard_dialog_window = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(xsane_vbox_standard), standard_dialog_window, TRUE, TRUE, 0); + gtk_widget_show(standard_dialog_window); + + + + /* create the scanner advanced options dialog box */ + + xsane.advanced_options_shell = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_widget_set_uposition(xsane.advanced_options_shell, XSANE_ADV_OPTIONS_POS_X, XSANE_ADV_OPTIONS_POS_Y); + sprintf(windowname, "%s %s",WINDOW_ADVANCED_OPTIONS, device_text); + gtk_window_set_title(GTK_WINDOW(xsane.advanced_options_shell), (char *) windowname); + + /* shrink grow auto_shrink */ + gtk_window_set_policy(GTK_WINDOW(xsane.advanced_options_shell), FALSE, FALSE, TRUE); + gtk_signal_connect(GTK_OBJECT(xsane.advanced_options_shell), "delete_event", + GTK_SIGNAL_FUNC(xsane_advanced_option_win_delete), 0); + + xsane_set_window_icon(xsane.advanced_options_shell, 0); + + xsane_vbox_advanced = gtk_vbox_new(TRUE, 5); + gtk_container_set_border_width(GTK_CONTAINER(xsane_vbox_advanced), 5); + gtk_container_add(GTK_CONTAINER(xsane.advanced_options_shell), xsane_vbox_advanced); + gtk_widget_show(xsane_vbox_advanced); + + /* create a subwindow so the advanced dialog keeps its position on rebuilds: */ + advanced_dialog_window = gtk_hbox_new(/* homogeneous */ FALSE, 0); + gtk_box_pack_start(GTK_BOX(xsane_vbox_advanced), advanced_dialog_window, TRUE, TRUE, 0); + gtk_widget_show(advanced_dialog_window); + + + dialog = malloc(sizeof (*dialog)); + if (!dialog) + { + printf("Could not create dialog\n"); + return; + } + + /* fill in dialog structure */ + + memset(dialog, 0, sizeof(*dialog)); + + dialog->xsane_window = main_dialog_window; + dialog->standard_window = standard_dialog_window; + dialog->advanced_window = advanced_dialog_window; + dialog->dev = dev; + dialog->dev_name = strdup(devname); + dialog->num_elements = num_elements; + dialog->option_reload_callback = xsane_update_preview; + dialog->option_reload_arg = 0; + dialog->param_change_callback = xsane_update_param; + dialog->param_change_arg = 0; + + dialog->element = malloc(num_elements * sizeof(dialog->element[0])); + memset(dialog->element, 0, num_elements * sizeof(dialog->element[0])); + + + + + /* realize xsane main dialog */ + /* normally a realize should be ok, but then + the default size of the scrollwed window is ignored + so we use a widget_show in that case */ + + if (xsane.main_window_fixed) + { + gtk_widget_realize(xsane.shell); + } + else + { + gtk_widget_show(xsane.shell); + /* the disadavantage of this is that the main window does + not have the focus when every window is shown */ + } + + + /* define tooltips colors */ + + dialog->tooltips = gtk_tooltips_new(); + colormap = gdk_window_get_colormap(xsane.shell->window); + +/* I don`t know why the following does not work with gtk-1.2.x */ +/* but the gimp has the same problems ;-) */ + /* use black as foreground: */ + dialog->tooltips_fg.red = 0; + dialog->tooltips_fg.green = 0; + dialog->tooltips_fg.blue = 0; + gdk_color_alloc(colormap, &dialog->tooltips_fg); + + /* postit yellow (khaki) as background: */ + dialog->tooltips_bg.red = 61669; + dialog->tooltips_bg.green = 59113; + dialog->tooltips_bg.blue = 35979; + gdk_color_alloc(colormap, &dialog->tooltips_bg); + +/* as long as gtk_tooltips_set_colors() does not work : */ +#if 1 + gtk_tooltips_force_window(dialog->tooltips); + { + GtkStyle *current_style = gtk_style_copy(gtk_widget_get_style(dialog->tooltips->tip_window)); + + current_style->bg[GTK_STATE_NORMAL] = dialog->tooltips_bg; + current_style->fg[GTK_STATE_NORMAL] = dialog->tooltips_fg; + gtk_widget_set_style(dialog->tooltips->tip_window, current_style); + } +#else + gtk_tooltips_set_colors(dialog->tooltips, &dialog->tooltips_bg, &dialog->tooltips_fg); +#endif + xsane_back_gtk_set_tooltips(dialog, preferences.tooltips_enabled); + + + + /* create histogram dialog and set colors */ + xsane_create_histogram_dialog(device_text); /* create the histogram dialog */ + + + /* The bottom row of info and start button */ + +#if 0 + hbox = GTK_DIALOG(xsane.shell)->action_area; +#endif + + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_end(GTK_BOX(GTK_DIALOG(xsane.shell)->action_area), hbox, TRUE, TRUE, 0); + gtk_widget_show(hbox); + + /* Info frame */ + frame = gtk_frame_new(0); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); +#if 0 + gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); +#endif + gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); + gtk_widget_show(frame); + + infobox = gtk_hbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(infobox), 2); + gtk_container_add(GTK_CONTAINER(frame), infobox); + gtk_widget_show(infobox); + + xsane.info_label = gtk_label_new(TEXT_INFO_BOX); + gtk_box_pack_start(GTK_BOX(infobox), xsane.info_label, FALSE, FALSE, 0); +#if 0 + gtk_box_pack_start(GTK_BOX(infobox), xsane.info_label, TRUE, TRUE, 0); +#endif + gtk_widget_show(xsane.info_label); + + + /* The Scan button */ + button = gtk_button_new_with_label(BUTTON_START); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_scan_dialog, 0); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + xsane.start_button = GTK_OBJECT(button); + + + /* create backend dependend options */ + xsane_panel_build(dialog); + + + /* create preview dialog */ + xsane.preview = preview_new(dialog); + gtk_signal_connect(GTK_OBJECT(xsane.preview->top), "delete_event", GTK_SIGNAL_FUNC(xsane_preview_window_destroyed), 0); + + + xsane_device_preferences_restore(); /* restore device-settings */ + + xsane_update_param(dialog, 0); + + gtk_widget_realize(xsane.standard_options_shell); /* is needed for saving window geometry */ + gtk_widget_realize(xsane.advanced_options_shell); + + if (preferences.show_standard_options) + { + gtk_widget_show(xsane.standard_options_shell); + } + + if (preferences.show_advanced_options) + { + gtk_widget_show(xsane.advanced_options_shell); + } + + gtk_widget_show(xsane.shell); /* call as last so focus is on it */ + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + xsane_device_preferences_restore(); /* restore device-settings */ + + xsane_update_sliders(); + + if (xsane.show_preview) + { + gtk_widget_show(xsane.preview->top); + } + else + { + gtk_widget_hide(xsane.preview->top); + } + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_preview_widget), xsane.show_preview); + + xsane_set_all_resolutions(); /* make sure resolution, resolution_x and resolution_y are up to date */ +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_choose_dialog_ok_callback(void) +{ + gtk_signal_disconnect_by_func(GTK_OBJECT(choose_device_dialog), GTK_SIGNAL_FUNC(xsane_quit), 0); + gtk_widget_destroy(choose_device_dialog); + xsane_device_dialog(); + + if (!dialog) + { + xsane_quit(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_select_device_by_key_callback(GtkWidget * widget, gpointer data) +{ + seldev = (long) data; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_select_device_by_mouse_callback(GtkWidget * widget, GdkEventButton *event, gpointer data) +{ + seldev = (long) data; + if (event->type == GDK_2BUTTON_PRESS && event->button == 1) + { + xsane_choose_dialog_ok_callback(); + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static gint32 xsane_choose_device(void) +{ + GtkWidget *main_vbox, *vbox, *hbox, *button, *device_frame, *device_vbox, *pixmapwidget; + GdkBitmap *mask; + GdkPixmap *pixmap; + GtkStyle *style; + GdkColor *bg_trans; + GSList *owner; + gint i; + const SANE_Device *adev; + char buf[256]; + char vendor[9]; + char model[17]; + char type[20]; + int j; + + choose_device_dialog = gtk_dialog_new(); + gtk_window_set_position(GTK_WINDOW(choose_device_dialog), GTK_WIN_POS_CENTER); + gtk_window_set_policy(GTK_WINDOW(choose_device_dialog), FALSE, FALSE, FALSE); + gtk_signal_connect(GTK_OBJECT(choose_device_dialog), "destroy", GTK_SIGNAL_FUNC(xsane_quit), 0); + snprintf(buf, sizeof(buf), "%s %s", prog_name, WINDOW_DEVICE_SELECTION); + gtk_window_set_title(GTK_WINDOW(choose_device_dialog), buf); + + main_vbox = GTK_DIALOG(choose_device_dialog)->vbox; + + vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 3); + gtk_box_pack_start(GTK_BOX(main_vbox), vbox, TRUE, TRUE, 0); + gtk_widget_show(vbox); + + /* xsane logo */ + gtk_widget_realize(choose_device_dialog); + + style = gtk_widget_get_style(choose_device_dialog); + bg_trans = &style->bg[GTK_STATE_NORMAL]; + + snprintf(buf, sizeof(buf), "%s/xsane-logo.xpm", STRINGIFY(PATH_SANE_DATA_DIR)); + pixmap = gdk_pixmap_create_from_xpm(choose_device_dialog->window, &mask, bg_trans, buf); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(vbox), pixmapwidget, FALSE, FALSE, 2); + gtk_widget_show(pixmapwidget); + gdk_pixmap_unref(pixmap); + + xsane_set_window_icon(choose_device_dialog, (gchar **) 0); + + xsane_separator_new(vbox, 5); + + + /* list the drivers with radiobuttons */ + device_frame = gtk_frame_new(TEXT_AVAILABLE_DEVICES); + gtk_box_pack_start(GTK_BOX(vbox), device_frame, FALSE, FALSE, 2); + gtk_widget_show(device_frame); + + device_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(device_vbox), 3); + gtk_container_add(GTK_CONTAINER(device_frame), device_vbox); + + owner = 0; + for (i = 0; i < ndevs; i++) + { + adev = devlist[i]; + + strncpy(vendor, adev->vendor, sizeof(vendor)-1); + vendor[sizeof(vendor)-1] = 0; + for (j = strlen(vendor); j < sizeof(vendor)-1; j++) + { + vendor[j] = ' '; + } + + strncpy(model, adev->model, sizeof(model)-1); + model[sizeof(model)-1] = 0; + for (j = strlen(model); j < sizeof(model)-1; j++) + { + model[j] = ' '; + } + + strncpy(type, _(adev->type), sizeof(type)-1); /* allow translation of device type */ + type[sizeof(type)-1] = 0; + for (j = strlen(type); j < sizeof(type)-1; j++) + { + type[j] = ' '; + } + + snprintf(buf, sizeof(buf), "%s %s %s [%s]", vendor, model, type, adev->name); + button = gtk_radio_button_new_with_label(owner, (char *) buf); + gtk_signal_connect(GTK_OBJECT(button), "button_press_event", + (GtkSignalFunc) xsane_select_device_by_mouse_callback, (void *) (long) i); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + (GtkSignalFunc) xsane_select_device_by_key_callback, (void *) (long) i); + gtk_box_pack_start(GTK_BOX(device_vbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + owner = gtk_radio_button_group(GTK_RADIO_BUTTON(button));; + } + gtk_widget_show(device_vbox); + + /* The bottom row of buttons */ + hbox = GTK_DIALOG(choose_device_dialog)->action_area; + + /* The OK button */ + button = gtk_button_new_with_label(BUTTON_OK); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_choose_dialog_ok_callback, 0); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_grab_default(button); + gtk_widget_show(button); + + /* The Cancel button */ + button = gtk_button_new_with_label(BUTTON_CANCEL); + gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_quit, 0); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + gtk_widget_show(choose_device_dialog); + + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_usage(void) +{ + printf("%s %s %s\n", TEXT_USAGE, prog_name, TEXT_USAGE_OPTIONS); + printf("\n%s\n\n", TEXT_HELP); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static void xsane_init(int argc, char **argv) +{ + char filename[PATH_MAX]; + struct stat st; + + gtk_init(&argc, &argv); +#ifdef HAVE_LIBGIMP_GIMP_H + gtk_rc_parse(gimp_gtkrc()); + + gdk_set_use_xshm(gimp_use_xshm()); +#endif + + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, "xsane-style", 0, ".rc", XSANE_PATH_LOCAL_SANE); + if (stat(filename, &st) >= 0) + { + gtk_rc_parse(filename); + } + else /* no local xsane-style.rc, look for system file */ + { + xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, "xsane-style", 0, ".rc", XSANE_PATH_SYSTEM); + if (stat(filename, &st) >= 0) + { + gtk_rc_parse(filename); + } + } + + sane_init(&xsane.sane_backend_versioncode, (void *) xsane_authorization_callback); + if (SANE_VERSION_MAJOR(xsane.sane_backend_versioncode) != SANE_V_MAJOR) + { + fprintf(stderr, "\n\n" + "%s %s:\n" + " %s\n" + " %s %d\n" + " %s %d\n" + "%s\n\n", + 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; + } + + if (argc > 1) + { + int ch; + + while((ch = getopt_long(argc, argv, "cd:fghnsvFR", long_options, 0)) != EOF) + { + switch(ch) + { + case 'g': /* This options is set when xsane is called from the */ + /* GIMP. If xsane is compiled without GIMP support */ + /* then you get the error message when GIMP does */ + /* query or tries to start the xsane plugin! */ +#ifndef HAVE_LIBGIMP_GIMP_H + printf("%s: %s\n", argv[0], ERR_GIMP_SUPPORT_MISSING); + exit(0); +#endif + break; + + case 'v': /* --version */ +#ifdef HAVE_LIBGIMP_GIMP_H + printf("%s-%s, %s \"%s\", SANE-%d.%d, %s, %s%s\n", + prog_name, + XSANE_VERSION, + TEXT_PACKAGE, + PACKAGE_VERSION, + SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), + SANE_VERSION_MINOR(xsane.sane_backend_versioncode), + TEXT_WITH_GIMP_SUPPORT, + TEXT_GIMP_VERSION, + GIMP_VERSION); +#else + printf("%s-%s, %s \"%s\", SANE-%d.%d, %s\n", + prog_name, + XSANE_VERSION, + TEXT_PACKAGE, + PACKAGE_VERSION, + SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), + SANE_VERSION_MINOR(xsane.sane_backend_versioncode), + TEXT_WITHOUT_GIMP_SUPPORT); +#endif + exit(0); + + case 'd': /* --device-settings */ + xsane.device_set_filename = strdup(optarg); + break; + + case 's': /* --scan */ + xsane.xsane_mode = XSANE_SCAN; + break; + + case 'c': /* --copy */ + xsane.xsane_mode = XSANE_COPY; + break; + + case 'n': /* --No-modes-election */ + xsane.mode_selection = 0; + break; + + case 'f': /* --fax */ + xsane.xsane_mode = XSANE_FAX; + break; + + case 'F': /* --Fixed */ + xsane.main_window_fixed = 1; + break; + + case 'R': /* --Resizeable */ + xsane.main_window_fixed = 0; + break; + + case 'h': /* --help */ + default: + xsane_usage(); + exit(0); + } + } + } + + sane_get_devices(&devlist, SANE_FALSE /* local and network devices */); + + /* if devicename is given try to identify it, if not found, open device list */ + if (optind < argc) + { + int ndevs; + + for (ndevs = 0; devlist[ndevs]; ++ndevs) + { + if (!strncmp(devlist[ndevs]->name, argv[argc - 1], strlen(argv[argc - 1]))) + { + seldev = ndevs; + break; + } + } + + if ((seldev < 0) && (argc > 1)) + { + static SANE_Device dev; + static const SANE_Device *device_list[] = { &dev, 0 }; + + memset(&dev, 0, sizeof(dev)); + dev.name = argv[argc - 1]; + dev.vendor = TEXT_UNKNOWN; + dev.type = TEXT_UNKNOWN; + dev.model = TEXT_UNKNOWN; + + devlist = device_list; + seldev = 0; + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_interface(int argc, char **argv) +{ + xsane.info_label = 0; + + xsane_init(argc, argv); /* initialize xsane variables if command line option is given, set seldev */ + + for (ndevs = 0; devlist[ndevs]; ++ndevs); /* count available devices */ + + if (seldev >= 0) /* device name is given on cammand line */ + { + xsane_device_dialog(); /* open device seldev */ + + if (!dialog) + { + xsane_exit(); + } + } + else /* no device name given on command line */ + { + if (ndevs > 0) /* devices available */ + { + seldev = 0; + if (ndevs == 1) + { + xsane_device_dialog(); /* open device seldev */ + if (!dialog) + { + xsane_exit(); + } + } + else + { + xsane_choose_device(); /* open device selection window and get device */ + } + } + else /* ndevs == 0, no devices available */ + { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s: %s\n", prog_name, ERR_NO_DEVICES); + xsane_back_gtk_error(buf, TRUE); + xsane_exit(); + } + } + + gtk_main(); + sane_exit(); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + dialog = 0; + memset(&xsane, 0, sizeof(xsane)); /* set all values in xsane to 0 */ + + umask(XSANE_DEFAULT_UMASK); /* define permissions of new files */ + + xsane.sensitivity = TRUE; + + xsane.main_window_fixed = -1; /* no command line option given, use preferences or fixed */ + + xsane.mode = XSANE_STANDALONE; + xsane.xsane_mode = XSANE_SCAN; + xsane.xsane_output_format = XSANE_PNM; + xsane.mode_selection = 1; /* enable selection of xsane mode */ + + xsane.input_tag = -1; /* no input tag */ + + xsane.histogram_lines = 1; + + xsane.zoom = 1.0; + xsane.zoom_x = 1.0; + xsane.zoom_y = 1.0; + xsane.resolution = 0.0; + xsane.resolution_x = 0.0; + xsane.resolution_y = 0.0; + xsane.copy_number = 1; + + 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.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.auto_white = 100.0; + xsane.auto_gray = 50.0; + xsane.auto_black = 0.0; + + xsane.histogram_red = 1; + xsane.histogram_green = 1; + xsane.histogram_blue = 1; + xsane.histogram_int = 1; + xsane.histogram_log = 1; + + xsane.xsane_color = TRUE; + xsane.scanner_gamma_color = FALSE; + xsane.scanner_gamma_gray = FALSE; + xsane.enhancement_rgb_default = TRUE; + + prog_name = strrchr(argv[0], '/'); + if (prog_name) + { + ++prog_name; + } + else + { + prog_name = argv[0]; + } +#if 0 + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +#endif + bindtextdomain(prog_name, LOCALEDIR); + textdomain(prog_name); + +#ifdef HAVE_LIBGIMP_GIMP_H + { + GPrintFunc old_print_func; + int result; + + /* Temporarily install a print function that discards all output. + This is to avoid annoying "you must run this program under + gimp" messages when xsane gets invoked in stand-alone + mode. */ + old_print_func = g_set_print_handler((GPrintFunc) null_print_func); + + /* gimp_main() returns 1 if xsane wasn't invoked by GIMP */ + result = gimp_main(argc, argv); + g_set_message_handler(old_print_func); + if (result) + { + xsane_interface(argc, argv); + } + } +#else + xsane_interface(argc, argv); +#endif + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ diff --git a/frontend/xsane.h b/frontend/xsane.h new file mode 100644 index 0000000..69e6d2c --- /dev/null +++ b/frontend/xsane.h @@ -0,0 +1,513 @@ +/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend + + xsane.h + + Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> + Copyright (C) 1998-2000 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. */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifndef XSANE_H +#define XSANE_H + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* #define XSANE_TEST */ +/* #define SUPPORT_RGBA */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#define XSANE_VERSION "0.50" +#define XSANE_AUTHOR "Oliver Rauch" +#define XSANE_COPYRIGHT "Oliver Rauch" +#define XSANE_DATE "1998-2000" +#define XSANE_EMAIL "Oliver.Rauch@Wolfsburg.DE" + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#define PATH_SANE_TMP "/tmp" +// #define XSANE_DEFAULT_UMASK 0157 +#define XSANE_DEFAULT_UMASK 0007 + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +/* needed for most of the xsane sources: */ + +#ifdef _AIX +# include <lalloca.h> +#endif + +#include <assert.h> +#include <errno.h> +#include <memory.h> +#include <pwd.h> +#include <fcntl.h> +#include <getopt.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <getopt.h> +#include <time.h> + +#include <sys/stat.h> +#include <sys/types.h> + +#include <sane/sane.h> +#include <sane/saneopts.h> + +#include "sane/config.h" +#include "sane/sanei_signal.h" + +#include "xsane-text.h" +#include "xsane-icons.h" + +#ifdef ENABLE_NLS +# include <libintl.h> +# define _(String) gettext (String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +/* Stubs that do something close enough. */ +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + +/* ----------------------------- */ + +/* needed for xsane.h */ +#include "xsane-back-gtk.h" +#include "xsane-preferences.h" +#include "xsane-preview.h" + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_LIBGIMP_GIMP_H +# include <libgimp/gimp.h> + +# ifdef HAVE_LIBGIMP_GIMPFEATURES_H +# include <libgimp/gimpfeatures.h> +# else +# define GIMP_CHECK_VERSION(major, minor, micro) 0 +# endif /* HAVE_LIBGIMP_GIMPFEATURES_H */ + +#endif /* HAVE_LIBGIMP_GIMP_H */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +enum { XSANE_SCAN, XSANE_COPY, XSANE_FAX }; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +extern void xsane_pref_save(void); +extern void xsane_interface(int argc, char **argv); +extern void xsane_fax_project_save(void); + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +extern const char *prog_name; +extern const char *device_text; +extern GtkWidget *choose_device_dialog; +extern GSGDialog *dialog; +extern const SANE_Device **devlist; +extern gint seldev; /* The selected device */ +extern gint ndevs; /* The number of available devices */ + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +extern int xsane_scanmode_number[]; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#define OUTFILENAME "out.pnm" +#define FAXPROJECT "faxproject" +#define FAXFILENAME "page-001.fax" +#define PRINTERNAME "new printer" +#define PRINTERCOMMAND "lpr -" +#define PRINTERCOPYNUMBEROPTION "-#" +#define FAXCOMMAND "sendfax" +#define FAXRECEIVEROPT "-d" +#define FAXPOSTSCRIPTOPT "" +#define FAXNORMALOPT "-l" +#define FAXFINEOPT "-m" +#define FAXVIEWER "xv" +#define DOCVIEWERNETSCAPEREMOTE "netscape-remote" +#define DOCVIEWER DOCVIEWERNETSCAPEREMOTE + +#define XSANE_BRIGHTNESS_MIN -400.0 +#define XSANE_BRIGHTNESS_MAX 400.0 +#define XSANE_CONTRAST_GRAY_MIN -100.0 +#define XSANE_CONTRAST_MIN -400.0 +#define XSANE_CONTRAST_MAX 400.0 +#define XSANE_GAMMA_MIN 0.3 +#define XSANE_GAMMA_MAX 3.0 + +#define HIST_WIDTH 256 +#define HIST_HEIGHT 100 +#define XSANE_SHELL_WIDTH 296 +#define XSANE_SHELL_HEIGHT 451 +#define XSANE_SHELL_POS_X 1 +#define XSANE_SHELL_POS_Y 50 +#define XSANE_HISTOGRAM_POS_X 280 +#define XSANE_HISTOGRAM_POS_Y 50 +#define XSANE_STD_OPTIONS_POS_X 1 +#define XSANE_STD_OPTIONS_POS_Y 400 +#define XSANE_ADV_OPTIONS_POS_X 280 +#define XSANE_ADV_OPTIONS_POS_Y 420 +#define XSANE_PREVIEW_POS_X 560 +#define XSANE_PREVIEW_POS_Y 50 +#define XSANE_PREVIEW_WIDTH 100 +#define XSANE_PREVIEW_HEIGHT 100 + +#define XSANE_SLIDER_ACTIVE 0 +#define XSANE_SLIDER_INACTIVE 4 +#define XSANE_SLIDER_WIDTH 260 +#define XSANE_SLIDER_HEIGHT 10 +#define XSANE_SLIDER_OFFSET 2 +#define XSANE_SLIDER_EVENTS GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK | \ + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | \ + GDK_BUTTON1_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK +#define INF 5.0e9 +#define MM_PER_INCH 25.4 + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#ifndef SANE_NAME_DOCUMENT_FEEDER +#define SANE_NAME_DOCUMENT_FEEDER "Automatic Document Feeder" +#endif + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#define STRINGIFY1(x) #x +#define STRINGIFY(x) STRINGIFY1(x) + +#define NELEMS(a) ((int)(sizeof (a) / sizeof (a[0]))) + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +enum +{ + XSANE_UNKNOWN, XSANE_PNM, XSANE_JPEG, XSANE_PNG, XSANE_PS, XSANE_TIFF, XSANE_RGBA, + XSANE_RAW16, XSANE_PNM16 +}; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +enum +{ + XSANE_STANDALONE, XSANE_GIMP_EXTENSION +}; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +typedef struct XsaneProgress_t +{ + GtkSignalFunc callback; + gpointer callback_data; + GtkWidget *shell; + GtkWidget *pbar; +} XsaneProgress_t; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +typedef struct XsanePixmap +{ + GtkWidget *frame; + GdkPixmap *pixmap; + GtkWidget *pixmapwid; +} XsanePixmap; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +typedef struct XsaneSlider +{ + int position[3]; + double value[3]; + double min, max; + int active; + GtkWidget *preview; + int r, g, b; +} XsaneSlider; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +typedef struct Xsane +{ + SANE_Int sane_backend_versioncode; + char *backend; + char *device_set_filename; + char *filetype; + char *output_filename; + char *dummy_filename; + + SANE_Int sensitivity; + + /* dialogs */ + GtkWidget *shell; + GtkWidget *standard_options_shell; + GtkWidget *advanced_options_shell; + GtkWidget *main_dialog_scrolled; + GtkWidget *histogram_dialog; + GtkWidget *fax_dialog; + GtkWidget *fax_list; + + GtkWidget *fax_project_box; + GtkWidget *fax_project_exists; + GtkWidget *fax_project_not_exists; + + GdkPixmap *window_icon_pixmap; + GdkBitmap *window_icon_mask; + + /* window position and geometry */ + SANE_Int shell_posx; + SANE_Int shell_posy; + SANE_Int shell_height; + SANE_Int shell_width; + SANE_Int standard_options_shell_posx; + SANE_Int standard_options_shell_posy; + SANE_Int advanced_options_shell_posx; + SANE_Int advanced_options_shell_posy; + SANE_Int histogram_dialog_posx; + SANE_Int histogram_dialog_posy; + SANE_Int preview_dialog_posx; + SANE_Int preview_dialog_posy; + SANE_Int preview_dialog_width; + SANE_Int preview_dialog_height; + + GtkWidget *hruler; + GtkWidget *vruler; + GtkWidget *info_label; + GtkObject *start_button; + Preview *preview; + gint32 mode; + + int main_window_fixed; + int mode_selection; + + /* various scanning related state: */ + size_t num_bytes; + size_t bytes_read; + XsaneProgress_t *progress; + int input_tag; + SANE_Parameters param; + int x, y; + + /* for standalone mode: */ + GtkWidget *filename_entry; + GtkWidget *fax_project_entry; + GtkWidget *fax_receiver_entry; + GtkWidget *filetype_option_menu; + FILE *out; + int xsane_mode; + int xsane_output_format; + long header_size; + + /* histogram window */ + struct XsanePixmap histogram_raw; + struct XsanePixmap histogram_enh; + + struct XsaneSlider slider_gray; + struct XsaneSlider slider_red; + struct XsaneSlider slider_green; + struct XsaneSlider slider_blue; + + int negative; + double gamma; + double gamma_red; + double gamma_green; + double gamma_blue; + double brightness; + double brightness_red; + double brightness_green; + double brightness_blue; + double contrast; + double contrast_red; + double contrast_green; + double contrast_blue; + + double auto_white; + double auto_gray; + double auto_black; + double auto_white_red; + double auto_gray_red; + double auto_black_red; + double auto_white_green; + double auto_gray_green; + double auto_black_green; + double auto_white_blue; + double auto_gray_blue; + double auto_black_blue; + + int histogram_red; + int histogram_green; + int histogram_blue; + int histogram_int; + int histogram_lines; + int histogram_log; + + /* colors */ + GdkGC *gc_red; + GdkGC *gc_green; + GdkGC *gc_blue; + GdkGC *gc_black; + GdkGC *gc_trans; + GdkGC *gc_backg; + GdkColor *bg_trans; + + int copy_number; + double zoom; + double zoom_x; + double zoom_y; + double resolution; + double resolution_x; + double resolution_y; + + GtkWidget *length_unit_widget; + GtkWidget *length_unit_mm; + GtkWidget *length_unit_cm; + GtkWidget *length_unit_in; + GtkWidget *update_policy_continu; + GtkWidget *update_policy_discont; + GtkWidget *update_policy_delayed; + GtkWidget *show_preview_widget; + GtkWidget *show_histogram_widget; + 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; + + SANE_Int xsane_color; + SANE_Bool show_preview; + SANE_Bool scanner_gamma_color; + SANE_Bool scanner_gamma_gray; + SANE_Bool enhancement_rgb_default; + + SANE_Bool fax_fine_mode; + + GtkWidget *outputfilename_entry; + GtkWidget *copy_number_entry; + + SANE_Int *gamma_data, *gamma_data_red, *gamma_data_green, *gamma_data_blue; + SANE_Int *preview_gamma_data_red, *preview_gamma_data_green, *preview_gamma_data_blue; + SANE_Int *histogram_gamma_data_red, *histogram_gamma_data_green, *histogram_gamma_data_blue; + + char *fax_filename; + char *fax_receiver; + + int block_update_param; + + int broken_pipe; /* for printercommand pipe */ + +#ifdef HAVE_LIBGIMP_GIMP_H + /* for GIMP mode: */ + gint32 image_ID; + GDrawable *drawable; + guchar *tile; + unsigned tile_offset; + GPixelRgn region; + int first_frame; /* used for RED/GREEN/BLUE frames */ +#endif +} Xsane; + +extern struct Xsane xsane; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +typedef struct XsaneSetup +{ + GtkWidget *printer_name_entry; + GtkWidget *printer_command_entry; + GtkWidget *printer_copy_number_option_entry; + GtkWidget *printer_resolution_entry; + GtkWidget *printer_leftoffset_entry; + GtkWidget *printer_bottomoffset_entry; + GtkWidget *printer_gamma_entry; + GtkWidget *printer_gamma_red_entry; + GtkWidget *printer_gamma_green_entry; + GtkWidget *printer_gamma_blue_entry; + GtkWidget *printer_width_entry; + GtkWidget *printer_height_entry; + + GtkWidget *jpeg_image_quality_scale; + GtkWidget *pnm_image_compression_scale; + GtkWidget *overwrite_warning_button; + GtkWidget *increase_filename_counter_button; + GtkWidget *skip_existing_numbers_button; + + GtkWidget *main_window_fixed_button; + + GtkWidget *preview_gamma_entry; + GtkWidget *preview_gamma_red_entry; + GtkWidget *preview_gamma_green_entry; + GtkWidget *preview_gamma_blue_entry; + GtkWidget *preview_preserve_button; + GtkWidget *preview_own_cmap_button; + GtkWidget *doc_viewer_entry; + + GtkWidget *fax_command_entry; + GtkWidget *fax_receiver_option_entry; + GtkWidget *fax_postscript_option_entry; + GtkWidget *fax_normal_option_entry; + GtkWidget *fax_fine_option_entry; + GtkWidget *fax_viewer_entry; + GtkWidget *fax_width_entry; + GtkWidget *fax_leftoffset_entry; + GtkWidget *fax_bottomoffset_entry; + GtkWidget *fax_height_entry; + + int tiff_compression_nr; + int tiff_compression_1_nr; + + int image_permissions; + int directory_permissions; + +} XsaneSetup; + +extern struct XsaneSetup xsane_setup; + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#endif |