summaryrefslogtreecommitdiff
path: root/src/xsane-viewer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xsane-viewer.c')
-rw-r--r--src/xsane-viewer.c1448
1 files changed, 1448 insertions, 0 deletions
diff --git a/src/xsane-viewer.c b/src/xsane-viewer.c
new file mode 100644
index 0000000..e9a8dd9
--- /dev/null
+++ b/src/xsane-viewer.c
@@ -0,0 +1,1448 @@
+/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend
+
+ xsane-viewer.c
+
+ Oliver Rauch <Oliver.Rauch@rauch-domain.de>
+ Copyright (C) 1998-2002 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 <sys/param.h> */
+#include "xsane-back-gtk.h"
+#include "xsane-front-gtk.h"
+#include "xsane-preferences.h"
+#include "xsane-viewer.h"
+#include "xsane-gamma.h"
+#include "xsane-icons.h"
+#include "xsane-save.h"
+#include <gdk/gdkkeysyms.h>
+#include <sys/wait.h>
+
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_viewer_zoom[] = {35, 50, 71, 100, 141, 200, 282, 400 };
+#define XSANE_VIEWER_ZOOM_ITEMS 8
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static gint xsane_viewer_close_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_dialog_cancel(GtkWidget *window, gpointer data);
+static void xsane_viewer_save_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_ocr_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_clone_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_despeckle_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_blur_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_scale_image(GtkWidget *window, gpointer data);
+static void xsane_viewer_despeckle_image(GtkWidget *window, gpointer data);
+static void xsane_viewer_blur_image(GtkWidget *window, gpointer data);
+static void xsane_viewer_rotate(Viewer *v, int rotation);
+static void xsane_viewer_rotate90_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_rotate180_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_rotate270_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_mirror_x_callback(GtkWidget *window, gpointer data);
+static void xsane_viewer_mirror_y_callback(GtkWidget *window, gpointer data);
+static GtkWidget *xsane_viewer_files_build_menu(Viewer *v);
+static GtkWidget *xsane_viewer_filters_build_menu(Viewer *v);
+static int xsane_viewer_read_image(Viewer *v);
+Viewer *xsane_viewer_new(char *filename, int reduce_to_lineart, char *output_filename);
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static gint xsane_viewer_close_callback(GtkWidget *widget, gpointer data)
+{
+ Viewer *v, *list, **prev_list;
+
+ v = (Viewer*) gtk_object_get_data(GTK_OBJECT(widget), "Viewer");
+
+ DBG(DBG_proc, "xsane_viewer_close_callback\n");
+
+ if (!v->image_saved)
+ {
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), WARN_VIEWER_IMAGE_NOT_SAVED);
+ if (xsane_back_gtk_decision(ERR_HEADER_WARNING, (gchar **) warning_xpm, buf, BUTTON_DO_NOT_CLOSE, BUTTON_DISCARD_IMAGE, TRUE /* wait */))
+ {
+ return TRUE;
+ }
+ }
+
+ remove(v->filename);
+
+ gtk_widget_destroy(v->top);
+
+
+ list = xsane.viewer_list;
+ prev_list = &xsane.viewer_list;
+
+ while (list)
+ {
+ if (list == v)
+ {
+ DBG(DBG_info, "removing viewer from viewer list\n");
+ *prev_list = list->next_viewer;
+ break;
+ }
+
+ prev_list = &list->next_viewer;
+ list = list->next_viewer;
+ }
+
+ free(v);
+
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_dialog_cancel(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_save_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+ char outputfilename[1024];
+ char *inputfilename;
+ char windowname[256];
+ int output_format;
+
+ DBG(DBG_proc, "xsane_viewer_save_callback\n");
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ if (v->output_filename)
+ {
+ strncpy(outputfilename, v->output_filename, sizeof(outputfilename));
+ }
+ else
+ {
+ int abort = 0;
+
+ strcpy(outputfilename, preferences.filename);
+
+ snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_VIEWER_OUTPUT_FILENAME, xsane.device_text);
+
+ umask((mode_t) preferences.directory_umask); /* define new file permissions */
+ abort = xsane_back_gtk_get_filename(windowname, outputfilename, sizeof(outputfilename), outputfilename, TRUE, TRUE, FALSE);
+ umask(XSANE_DEFAULT_UMASK); /* define new file permissions */
+
+ if (abort)
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+ return;
+ }
+ }
+
+ if (preferences.overwrite_warning) /* test if filename already used */
+ {
+ FILE *testfile;
+
+ testfile = fopen(outputfilename, "rb"); /* read binary (b for win32) */
+ if (testfile) /* filename used: skip */
+ {
+ char buf[256];
+
+ fclose(testfile);
+ snprintf(buf, sizeof(buf), WARN_FILE_EXISTS, outputfilename);
+ if (xsane_back_gtk_decision(ERR_HEADER_WARNING, (gchar **) warning_xpm, buf, BUTTON_OVERWRITE, BUTTON_CANCEL, TRUE /* wait */) == FALSE)
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+ return;
+ }
+ }
+ }
+
+ inputfilename = strdup(v->filename);
+
+ output_format = xsane_identify_output_format(outputfilename, 0);
+
+ if (v->reduce_to_lineart) /* reduce grayscale image to lineart before saving */
+ {
+ char dummyfilename[1024];
+
+ if (output_format != XSANE_PNM)
+ {
+ xsane_back_gtk_make_path(sizeof(dummyfilename), dummyfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
+ }
+ else /* pbm: no further conversion, we save to destination filename */
+ {
+ snprintf(dummyfilename, sizeof(dummyfilename), "%s", outputfilename);
+ if (xsane_create_secure_file(dummyfilename)) /* remove possibly existing symbolic links for security */
+ {
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "%s %s %s\n", ERR_DURING_SAVE, ERR_CREATE_SECURE_FILE, dummyfilename);
+ xsane_back_gtk_error(buf, TRUE);
+ return; /* error */
+ }
+ }
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_PACKING_DATA);
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ /* the outputfile always is a temporary file, so we do not have to care about symlinks here */
+ xsane_save_image_as_lineart(v->filename, dummyfilename, v->progress_bar, &v->cancel_save);
+
+ free(inputfilename);
+ inputfilename = strdup(dummyfilename);
+ }
+
+
+ if ((!v->reduce_to_lineart) || (output_format != XSANE_PNM)) /* pbm already is saved above, otherwise save now */
+ {
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_SAVING_DATA);
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ xsane_save_image_as(inputfilename, outputfilename, output_format, v->progress_bar, &v->cancel_save);
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+ }
+
+ free(inputfilename);
+
+ v->image_saved = TRUE;
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_ocr_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+ char outputfilename[1024];
+ char *extensionptr;
+ char windowname[256];
+ char *arg[1000];
+ int argnr;
+ pid_t pid;
+ int abort = 0;
+ int i;
+
+ DBG(DBG_proc, "xsane_viewer_ocr_callback\n");
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ strncpy(outputfilename, preferences.filename, sizeof(outputfilename)-5);
+
+ extensionptr = strchr(outputfilename, '.');
+ if (!extensionptr)
+ {
+ extensionptr=outputfilename + strlen(outputfilename);
+ }
+ strcpy(extensionptr, ".txt");
+
+ snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_OCR_OUTPUT_FILENAME, xsane.device_text);
+
+ umask((mode_t) preferences.directory_umask); /* define new file permissions */
+ abort = xsane_back_gtk_get_filename(windowname, outputfilename, sizeof(outputfilename), outputfilename, TRUE, TRUE, FALSE);
+ umask(XSANE_DEFAULT_UMASK); /* define new file permissions */
+
+ if (abort)
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+ return;
+ }
+
+ argnr = xsane_parse_options(preferences.ocr_command, arg);
+
+ arg[argnr++] = strdup(preferences.ocr_inputfile_option);
+ arg[argnr++] = strdup(v->filename);
+
+ arg[argnr++] = strdup(preferences.ocr_outputfile_option);
+ arg[argnr++] = strdup(outputfilename);
+
+ arg[argnr] = 0;
+
+ pid = fork();
+
+ if (pid == 0) /* new process */
+ {
+ DBG(DBG_info, "trying to change user id fo new subprocess:\n");
+ DBG(DBG_info, "old effective uid = %d\n", geteuid());
+ setuid(getuid());
+ DBG(DBG_info, "new effective uid = %d\n", geteuid());
+
+ execvp(arg[0], arg); /* does not return if successfully */
+ DBG(DBG_error, "%s %s\n", ERR_FAILED_EXEC_OCR_CMD, preferences.ocr_command);
+ _exit(0); /* do not use exit() here! otherwise gtk gets in trouble */
+ }
+
+ for (i=0; i<argnr; i++)
+ {
+ free(arg[i]);
+ }
+
+ while (pid)
+ {
+ int status = 0;
+ pid_t pid_status = waitpid(pid, &status, WNOHANG);
+
+ if (pid == pid_status)
+ {
+ pid = 0; /* ok, child process has terminated */
+ }
+
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_clone_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+ FILE *outfile;
+ FILE *infile;
+ char outfilename[256];
+ Image_info image_info;
+
+ DBG(DBG_proc, "xsane_viewer_clone_callback\n");
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ infile = fopen(v->filename, "rb");
+ if (!infile)
+ {
+ DBG(DBG_error, "could not load file %s\n", v->filename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ xsane_read_pnm_header(infile, &image_info);
+
+ DBG(DBG_info, "cloning image %s with geometry: %d x %d x %d, %d colors\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors);
+
+ xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
+
+ outfile = fopen(outfilename, "wb");
+ if (!outfile)
+ {
+ DBG(DBG_error, "could not save file %s\n", outfilename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_CLONING_DATA);
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ xsane_save_rotate_image(outfile, infile, &image_info, 0, v->progress_bar, &v->cancel_save);
+
+ fclose(infile);
+ fclose(outfile);
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ xsane_viewer_new(outfilename, v->reduce_to_lineart, NULL);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_spinbutton_float_changed(GtkWidget *spinbutton, gpointer data)
+{
+ float *val = (float *) data;
+
+ *val = gtk_spin_button_get_value_as_float((GtkSpinButton *) spinbutton);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_spinbutton_int_changed(GtkWidget *spinbutton, gpointer data)
+{
+ int *val = (int *) data;
+
+ *val = gtk_spin_button_get_value_as_int((GtkSpinButton *) spinbutton);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_scale_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+ GtkWidget *selection_dialog;
+ GtkWidget *hbox, *vbox;
+ GtkWidget *label, *spinbutton, *button;
+ GtkAdjustment *adjustment;
+ char buf[256];
+
+ DBG(DBG_proc, "xsane_viewer_scale_callback\n");
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ if (v->output_filename)
+ {
+ snprintf(buf, sizeof(buf), "%s: %s", WINDOW_SCALE, v->output_filename);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), WINDOW_SCALE);
+ }
+
+ selection_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_window_set_position(GTK_WINDOW(selection_dialog), GTK_WIN_POS_MOUSE);
+ gtk_window_set_title(GTK_WINDOW(selection_dialog), buf);
+ xsane_set_window_icon(selection_dialog, 0);
+
+ v->active_dialog = selection_dialog;
+
+ vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(selection_dialog), vbox);
+ gtk_widget_show(vbox);
+
+#if 0
+ /* bind scale */
+
+ button = gtk_check_button_new_with_label(BUTTON_SCALE_BIND);
+ gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 5);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
+ gtk_widget_show(button);
+#endif
+
+ /* x_scale factor: <-> */
+
+ v->x_scale_factor = 1.0;
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
+ gtk_widget_show(hbox);
+
+ label = gtk_label_new(TEXT_X_SCALE_FACTOR);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
+ gtk_widget_show(label);
+
+ adjustment = (GtkAdjustment *) gtk_adjustment_new(1.0, 0.01, 2.0, 0.01, 0.1, 0.0);
+ spinbutton = gtk_spin_button_new(adjustment, 0, 2);
+ gtk_signal_connect(GTK_OBJECT(spinbutton), "changed", (GtkSignalFunc) xsane_viewer_spinbutton_float_changed, (void *) &v->x_scale_factor);
+ gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), TRUE);
+ gtk_spin_button_set_shadow_type(GTK_SPIN_BUTTON(spinbutton), GTK_SHADOW_OUT);
+ gtk_box_pack_end(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 10);
+ gtk_widget_show(spinbutton);
+
+ /* y_scale factor: <-> */
+
+ v->y_scale_factor = 1.0;
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
+ gtk_widget_show(hbox);
+
+ label = gtk_label_new(TEXT_Y_SCALE_FACTOR);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
+ gtk_widget_show(label);
+
+ adjustment = (GtkAdjustment *) gtk_adjustment_new(1.0, 0.01, 2.0, 0.01, 0.1, 0.0);
+ spinbutton = gtk_spin_button_new(adjustment, 0, 2);
+ gtk_signal_connect(GTK_OBJECT(spinbutton), "changed", (GtkSignalFunc) xsane_viewer_spinbutton_float_changed, (void *) &v->y_scale_factor);
+ gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), TRUE);
+ gtk_spin_button_set_shadow_type(GTK_SPIN_BUTTON(spinbutton), GTK_SHADOW_OUT);
+ gtk_box_pack_end(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 10);
+ gtk_widget_show(spinbutton);
+
+ /* Apply Cancel */
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
+ gtk_widget_show(hbox);
+
+ button = gtk_button_new_with_label(BUTTON_APPLY);
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_viewer_scale_image, (void *) v);
+ gtk_signal_connect_object(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
+ gtk_container_add(GTK_CONTAINER(hbox), 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", (GtkSignalFunc) xsane_viewer_dialog_cancel, (void *) v);
+ gtk_signal_connect_object(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
+ gtk_container_add(GTK_CONTAINER(hbox), button);
+ gtk_widget_show(button);
+
+ gtk_widget_show(selection_dialog);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_despeckle_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+ GtkWidget *selection_dialog;
+ GtkWidget *hbox, *vbox;
+ GtkWidget *label, *spinbutton, *button;
+ GtkAdjustment *adjustment;
+ char buf[256];
+
+ DBG(DBG_proc, "xsane_viewer_despeckle_callback\n");
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ if (v->output_filename)
+ {
+ snprintf(buf, sizeof(buf), "%s: %s", WINDOW_DESPECKLE, v->output_filename);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), WINDOW_DESPECKLE);
+ }
+
+ selection_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_window_set_position(GTK_WINDOW(selection_dialog), GTK_WIN_POS_MOUSE);
+ gtk_window_set_title(GTK_WINDOW(selection_dialog), buf);
+ xsane_set_window_icon(selection_dialog, 0);
+
+ v->active_dialog = selection_dialog;
+
+ vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(selection_dialog), vbox);
+ gtk_widget_show(vbox);
+
+ /* Despeckle radius: <-> */
+
+ v->filter_radius = 2;
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
+ gtk_widget_show(hbox);
+
+ label = gtk_label_new(TEXT_DESPECKLE_RADIUS);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
+ gtk_widget_show(label);
+
+ adjustment = (GtkAdjustment *) gtk_adjustment_new(2.0, 2.0, 10.0, 1.0, 5.0, 0.0);
+ spinbutton = gtk_spin_button_new(adjustment, 0, 0);
+ gtk_signal_connect(GTK_OBJECT(spinbutton), "changed", (GtkSignalFunc) xsane_viewer_spinbutton_int_changed, (void *) &v->filter_radius);
+ gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), TRUE);
+ gtk_spin_button_set_shadow_type(GTK_SPIN_BUTTON(spinbutton), GTK_SHADOW_OUT);
+ gtk_box_pack_end(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 10);
+ gtk_widget_show(spinbutton);
+
+ /* Apply Cancel */
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
+ gtk_widget_show(hbox);
+
+ button = gtk_button_new_with_label(BUTTON_APPLY);
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_viewer_despeckle_image, (void *) v);
+ gtk_signal_connect_object(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
+ gtk_container_add(GTK_CONTAINER(hbox), 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", (GtkSignalFunc) xsane_viewer_dialog_cancel, (void *) v);
+ gtk_signal_connect_object(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
+ gtk_container_add(GTK_CONTAINER(hbox), button);
+ gtk_widget_show(button);
+
+ gtk_widget_show(selection_dialog);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_blur_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+ GtkWidget *selection_dialog;
+ GtkWidget *hbox, *vbox;
+ GtkWidget *label, *spinbutton, *button;
+ GtkAdjustment *adjustment;
+ char buf[256];
+
+ DBG(DBG_proc, "xsane_viewer_blur_callback\n");
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ if (v->output_filename)
+ {
+ snprintf(buf, sizeof(buf), "%s: %s", WINDOW_BLUR, v->output_filename);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), WINDOW_BLUR);
+ }
+
+ selection_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_window_set_position(GTK_WINDOW(selection_dialog), GTK_WIN_POS_MOUSE);
+ gtk_window_set_title(GTK_WINDOW(selection_dialog), buf);
+ xsane_set_window_icon(selection_dialog, 0);
+
+ v->active_dialog = selection_dialog;
+
+ vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
+ gtk_container_add(GTK_CONTAINER(selection_dialog), vbox);
+ gtk_widget_show(vbox);
+
+ /* Blur radius: <-> */
+
+ v->filter_radius = 2;
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
+ gtk_widget_show(hbox);
+
+ label = gtk_label_new(TEXT_BLUR_RADIUS);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
+ gtk_widget_show(label);
+
+ adjustment = (GtkAdjustment *) gtk_adjustment_new(2.0, 2.0, 20.0, 1.0, 5.0, 0.0);
+ spinbutton = gtk_spin_button_new(adjustment, 0, 0);
+ gtk_signal_connect(GTK_OBJECT(spinbutton), "changed", (GtkSignalFunc) xsane_viewer_spinbutton_int_changed, (void *) &v->filter_radius);
+ gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), TRUE);
+ gtk_spin_button_set_shadow_type(GTK_SPIN_BUTTON(spinbutton), GTK_SHADOW_OUT);
+ gtk_box_pack_end(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 10);
+ gtk_widget_show(spinbutton);
+
+ /* Apply Cancel */
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
+ gtk_widget_show(hbox);
+
+ button = gtk_button_new_with_label(BUTTON_APPLY);
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_viewer_blur_image, (void *) v);
+ gtk_container_add(GTK_CONTAINER(hbox), 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", (GtkSignalFunc) xsane_viewer_dialog_cancel, (void *) v);
+ gtk_signal_connect_object(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
+ gtk_container_add(GTK_CONTAINER(hbox), button);
+ gtk_widget_show(button);
+
+ gtk_widget_show(selection_dialog);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_scale_image(GtkWidget *window, gpointer data)
+{
+ FILE *outfile;
+ FILE *infile;
+ char outfilename[256];
+ Viewer *v = (Viewer *) data;
+ Image_info image_info;
+
+ DBG(DBG_proc, "xsane_viewer_scale_image\n");
+
+ gtk_widget_destroy(v->active_dialog);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ infile = fopen(v->filename, "rb");
+ if (!infile)
+ {
+ DBG(DBG_error, "could not load file %s\n", v->filename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ xsane_read_pnm_header(infile, &image_info);
+
+ DBG(DBG_info, "scaling image %s with geometry: %d x %d x %d, %d colors\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors);
+
+ xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
+
+ outfile = fopen(outfilename, "wb");
+ if (!outfile)
+ {
+ DBG(DBG_error, "could not save file %s\n", outfilename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_SCALING_DATA);
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ xsane_save_scaled_image(outfile, infile, &image_info, v->x_scale_factor, v->y_scale_factor, v->progress_bar, &v->cancel_save);
+
+ fclose(infile);
+ fclose(outfile);
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ DBG(DBG_info, "removing file %s\n", v->filename);
+ remove(v->filename);
+ free(v->filename);
+
+ v->filename = strdup(outfilename);
+ v->image_saved = FALSE;
+
+ xsane_viewer_read_image(v);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_despeckle_image(GtkWidget *window, gpointer data)
+{
+ FILE *outfile;
+ FILE *infile;
+ char outfilename[256];
+ Viewer *v = (Viewer *) data;
+ Image_info image_info;
+
+ DBG(DBG_proc, "xsane_viewer_despeckle_image\n");
+
+ gtk_widget_destroy(v->active_dialog);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ infile = fopen(v->filename, "rb");
+ if (!infile)
+ {
+ DBG(DBG_error, "could not load file %s\n", v->filename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ xsane_read_pnm_header(infile, &image_info);
+
+ DBG(DBG_info, "despeckling image %s with geometry: %d x %d x %d, %d colors\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors);
+
+ xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
+
+ outfile = fopen(outfilename, "wb");
+ if (!outfile)
+ {
+ DBG(DBG_error, "could not save file %s\n", outfilename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_DESPECKLING_DATA);
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ xsane_save_despeckle_image(outfile, infile, &image_info, v->filter_radius, v->progress_bar, &v->cancel_save);
+
+ fclose(infile);
+ fclose(outfile);
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ DBG(DBG_info, "removing file %s\n", v->filename);
+ remove(v->filename);
+ free(v->filename);
+
+ v->filename = strdup(outfilename);
+ v->image_saved = FALSE;
+
+ xsane_viewer_read_image(v);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_blur_image(GtkWidget *window, gpointer data)
+{
+ FILE *outfile;
+ FILE *infile;
+ char outfilename[256];
+ Viewer *v = (Viewer *) data;
+ Image_info image_info;
+
+ DBG(DBG_proc, "xsane_viewer_blur_image\n");
+
+ gtk_widget_destroy(v->active_dialog);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ infile = fopen(v->filename, "rb");
+ if (!infile)
+ {
+ DBG(DBG_error, "could not load file %s\n", v->filename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ xsane_read_pnm_header(infile, &image_info);
+
+ DBG(DBG_info, "bluring image %s with geometry: %d x %d x %d, %d colors\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors);
+
+ xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
+
+ outfile = fopen(outfilename, "wb");
+ if (!outfile)
+ {
+ DBG(DBG_error, "could not save file %s\n", outfilename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_BLURING_DATA);
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ xsane_save_blur_image(outfile, infile, &image_info, v->filter_radius, v->progress_bar, &v->cancel_save);
+
+ fclose(infile);
+ fclose(outfile);
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ DBG(DBG_info, "removing file %s\n", v->filename);
+ remove(v->filename);
+ free(v->filename);
+
+ v->filename = strdup(outfilename);
+ v->image_saved = FALSE;
+
+ xsane_viewer_read_image(v);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_rotate(Viewer *v, int rotation)
+{
+ FILE *outfile;
+ FILE *infile;
+ char outfilename[256];
+ Image_info image_info;
+
+ DBG(DBG_proc, "xsane_viewer_rotate(%d)\n", rotation);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), FALSE);
+
+ infile = fopen(v->filename, "rb");
+ if (!infile)
+ {
+ DBG(DBG_error, "could not load file %s\n", v->filename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ xsane_read_pnm_header(infile, &image_info);
+
+ DBG(DBG_info, "rotating image %s with geometry: %d x %d x %d, %d colors\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors);
+
+ xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
+
+ outfile = fopen(outfilename, "wb");
+ if (!outfile)
+ {
+ DBG(DBG_error, "could not save file %s\n", outfilename);
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+
+ return;
+ }
+
+ if (rotation <4)
+ {
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_ROTATING_DATA);
+ }
+ else
+ {
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_MIRRORING_DATA);
+ }
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ xsane_save_rotate_image(outfile, infile, &image_info, rotation, v->progress_bar, &v->cancel_save);
+
+ fclose(infile);
+ fclose(outfile);
+
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
+
+ DBG(DBG_info, "removing file %s\n", v->filename);
+ remove(v->filename);
+ free(v->filename);
+
+ v->filename = strdup(outfilename);
+ v->image_saved = FALSE;
+
+ xsane_viewer_read_image(v);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_rotate90_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+
+ DBG(DBG_proc, "xsane_viewer_rotate90_callback\n");
+ xsane_viewer_rotate(v, 1);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_rotate180_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+
+ DBG(DBG_proc, "xsane_viewer_rotate180_callback\n");
+ xsane_viewer_rotate(v, 2);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_rotate270_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+
+ DBG(DBG_proc, "xsane_viewer_rotate270_callback\n");
+ xsane_viewer_rotate(v, 3);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_mirror_x_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+
+ DBG(DBG_proc, "xsane_viewer_mirror_x_callback\n");
+ xsane_viewer_rotate(v, 4);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_mirror_y_callback(GtkWidget *window, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+
+ DBG(DBG_proc, "xsane_viewer_mirror_y_callback\n");
+ xsane_viewer_rotate(v, 6);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_viewer_zoom_callback(GtkWidget *widget, gpointer data)
+{
+ Viewer *v = (Viewer *) data;
+ int val;
+
+ DBG(DBG_proc, "xsane_viewer_zoom_callback\n");
+
+ val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection");
+ v->zoom = (float) val / 100;
+ DBG(DBG_info, "setting zoom factor to %f\n", v->zoom);
+ xsane_viewer_read_image(v);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static GtkWidget *xsane_viewer_files_build_menu(Viewer *v)
+{
+ GtkWidget *menu, *item;
+
+ DBG(DBG_proc, "xsane_viewer_files_build_menu\n");
+
+ menu = gtk_menu_new();
+ gtk_accel_group_attach(xsane.accelerator_group, GTK_OBJECT(menu));
+
+ /* XSane save dialog */
+
+ item = gtk_menu_item_new_with_label(MENU_ITEM_SAVE_IMAGE);
+#if 0
+ gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
+#endif
+ gtk_menu_append(GTK_MENU(menu), item);
+ gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_save_callback, v);
+ gtk_widget_show(item);
+
+
+ /* Clone */
+
+ item = gtk_menu_item_new_with_label(MENU_ITEM_CLONE);
+#if 0
+ gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
+#endif
+ gtk_menu_append(GTK_MENU(menu), item);
+ gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_clone_callback, v);
+ gtk_widget_show(item);
+
+
+ /* Scale */
+
+ item = gtk_menu_item_new_with_label(MENU_ITEM_SCALE);
+#if 0
+ gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
+#endif
+ gtk_menu_append(GTK_MENU(menu), item);
+ gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_scale_callback, v);
+ gtk_widget_show(item);
+
+
+ /* Close */
+
+ item = gtk_menu_item_new_with_label(MENU_ITEM_CLOSE);
+#if 0
+ gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_Q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
+#endif
+ gtk_container_add(GTK_CONTAINER(menu), item);
+ gtk_object_set_data(GTK_OBJECT(item), "Viewer", (void *) v);
+ gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_close_callback, v);
+ gtk_widget_show(item);
+
+ return menu;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static GtkWidget *xsane_viewer_filters_build_menu(Viewer *v)
+{
+ GtkWidget *menu, *item;
+
+ DBG(DBG_proc, "xsane_viewer_filters_build_menu\n");
+
+ menu = gtk_menu_new();
+ gtk_accel_group_attach(xsane.accelerator_group, GTK_OBJECT(menu));
+
+ /* Despeckle */
+
+ item = gtk_menu_item_new_with_label(MENU_ITEM_DESPECKLE);
+#if 0
+ gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
+#endif
+ gtk_menu_append(GTK_MENU(menu), item);
+ gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_despeckle_callback, v);
+ gtk_widget_show(item);
+
+
+ /* Blur */
+
+ item = gtk_menu_item_new_with_label(MENU_ITEM_BLUR);
+#if 0
+ gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_Q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
+#endif
+ gtk_container_add(GTK_CONTAINER(menu), item);
+ gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_blur_callback, v);
+ gtk_widget_show(item);
+
+ return menu;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_viewer_read_image(Viewer *v)
+{
+ unsigned char *row, *src_row;
+ int x, y;
+ int last_y;
+ int nread;
+ int pos0;
+ FILE *infile;
+ Image_info image_info;
+ char buf[256];
+ float size;
+ char *size_unit;
+ int width, height;
+
+ infile = fopen(v->filename, "rb");
+ if (!infile)
+ {
+ DBG(DBG_error, "could not load file %s\n", v->filename);
+ return -1;
+ }
+
+ xsane_read_pnm_header(infile, &image_info);
+
+ pos0 = ftell(infile);
+
+ if (!image_info.colors) /* == 0 (grayscale) ? */
+ {
+ image_info.colors = 1; /* we have one color component */
+ }
+
+ DBG(DBG_info, "reading image %s with geometry: %d x %d x %d, %d colors\n", v->filename,
+ image_info.image_width, image_info.image_height, image_info.depth, image_info.colors);
+ /* open infile */
+
+ if (v->window) /* we already have an existing viewer preview window? */
+ {
+ gtk_widget_destroy(v->window);
+ }
+
+ /* the preview area */
+ if (image_info.colors == 3) /* RGB */
+ {
+ v->window = gtk_preview_new(GTK_PREVIEW_COLOR);
+ }
+ else /* grayscale */
+ {
+ v->window = gtk_preview_new(GTK_PREVIEW_GRAYSCALE);
+ }
+
+ gtk_preview_size(GTK_PREVIEW(v->window), image_info.image_width * v->zoom, image_info.image_height * v->zoom);
+ gtk_container_add(GTK_CONTAINER(v->viewport), v->window);
+ gtk_widget_show(v->window);
+
+
+
+ /* get memory for one row of the image */
+ src_row = malloc(image_info.image_width * image_info.colors * image_info.depth / 8);
+ row = malloc(((int) image_info.image_width * v->zoom) * image_info.colors);
+
+ if (!row || !src_row)
+ {
+ if (src_row)
+ {
+ free(src_row);
+ }
+
+ if (row)
+ {
+ free(row);
+ }
+
+ fclose(infile);
+ DBG(DBG_error, "could not allocate memory\n");
+ return -1;
+ }
+
+
+ last_y = -99999;
+
+ /* read the image from file */
+ for (y = 0; y < (int) (image_info.image_height * v->zoom); y++)
+ {
+ if ((int) (last_y / v->zoom) != (int) (y / v->zoom))
+ {
+ last_y = y;
+
+ if (image_info.depth == 8) /* 8 bits/pixel */
+ {
+ fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.colors, SEEK_SET);
+ nread = fread(src_row, image_info.colors, image_info.image_width, infile);
+
+ if (image_info.colors > 1)
+ {
+ for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
+ {
+ int xoff = ((int) (x / v->zoom)) * image_info.colors;
+
+ row[3*x+0] = src_row[xoff + 0];
+ row[3*x+1] = src_row[xoff + 1];
+ row[3*x+2] = src_row[xoff + 2];
+ }
+ }
+ else
+ {
+ for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
+ {
+ row[x] = src_row[((int) (x / v->zoom))];
+ }
+ }
+ }
+ else /* 16 bits/pixel => reduce to 8 bits/pixel */
+ {
+ guint16 *src_row16 = (guint16 *) src_row;
+
+ fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.colors * 2, SEEK_SET);
+ nread = fread(src_row, 2 * image_info.colors, image_info.image_width, infile);
+
+ if (image_info.colors > 1)
+ {
+ for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
+ {
+ int xoff = ((int) (x / v->zoom)) * image_info.colors;
+
+ row[3*x+0] = (unsigned char) (src_row16[xoff + 0] / 256);
+ row[3*x+1] = (unsigned char) (src_row16[xoff + 1] / 256);
+ row[3*x+2] = (unsigned char) (src_row16[xoff + 2] / 256);
+ }
+ }
+ else
+ {
+ for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
+ {
+ row[x] = (unsigned char) (src_row16[(int) (x / v->zoom)] / 256);
+ }
+ }
+ }
+ }
+
+ gtk_preview_draw_row(GTK_PREVIEW(v->window), row, 0, y, image_info.image_width * v->zoom);
+ }
+
+ gtk_preview_put(GTK_PREVIEW(v->window), v->window->window, v->window->style->black_gc, 0, 0, 0, 0,
+ image_info.image_width * v->zoom, image_info.image_height * v->zoom);
+
+ size = (float) image_info.image_width * image_info.image_height * image_info.colors;
+ if (image_info.depth == 16)
+ {
+ size *= 2.0;
+ }
+
+ size_unit = "B";
+
+ if (size >= 1024 * 1024)
+ {
+ size /= (1024.0 * 1024.0);
+ size_unit = "MB";
+ }
+ else if (size >= 1024)
+ {
+ size /= 1024.0;
+ size_unit = "KB";
+ }
+
+ if (v->reduce_to_lineart)
+ {
+ snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, 1, image_info.colors,
+ image_info.resolution_x, image_info.resolution_y, size, size_unit);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, image_info.depth, image_info.colors,
+ image_info.resolution_x, image_info.resolution_y, size, size_unit);
+ }
+ gtk_label_set(GTK_LABEL(v->image_info_label), buf);
+
+ width = image_info.image_width + 26;
+ height = image_info.image_height + 136;
+
+ if (width > gdk_screen_width())
+ {
+ width = gdk_screen_width();
+ }
+
+ if (height > gdk_screen_height())
+ {
+ height = gdk_screen_height();
+ }
+
+ gtk_window_set_default_size(GTK_WINDOW(v->top), width, height);
+
+ free(row);
+ free(src_row);
+ fclose(infile);
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+Viewer *xsane_viewer_new(char *filename, int reduce_to_lineart, char *output_filename)
+{
+ char buf[256];
+ Viewer *v;
+ GtkWidget *vbox, *hbox;
+ GtkWidget *menubar, *menubar_item;
+ GtkWidget *scrolled_window;
+ GtkWidget *zoom_option_menu, *zoom_menu, *zoom_menu_item;
+ int i, selection;
+
+ DBG(DBG_proc, "viewer_new(%s)\n", filename);
+
+ /* create viewer structure v */
+ v = malloc(sizeof(*v));
+ if (!v)
+ {
+ DBG(DBG_error, "could not allocate memory\n");
+ return 0;
+ }
+ memset(v, 0, sizeof(*v));
+
+ v->filename = strdup(filename);
+ v->reduce_to_lineart = reduce_to_lineart;
+ v->zoom = 1.0;
+ v->image_saved = FALSE;
+ v->next_viewer = xsane.viewer_list;
+ xsane.viewer_list = v;
+
+ if (output_filename)
+ {
+ v->output_filename = strdup(output_filename);
+ snprintf(buf, sizeof(buf), "%s %s - %s", WINDOW_VIEWER, v->output_filename, xsane.device_text);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), "%s %s", WINDOW_VIEWER, xsane.device_text);
+ }
+
+ v->top = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(v->top), buf);
+ xsane_set_window_icon(v->top, 0);
+ gtk_accel_group_attach(xsane.accelerator_group, GTK_OBJECT(v->top));
+ gtk_object_set_data(GTK_OBJECT(v->top), "Viewer", (void *) v);
+ gtk_signal_connect(GTK_OBJECT(v->top), "delete_event", GTK_SIGNAL_FUNC(xsane_viewer_close_callback), NULL);
+
+ /* set the main vbox */
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 0);
+ gtk_container_add(GTK_CONTAINER(v->top), vbox);
+ gtk_widget_show(vbox);
+
+
+ /* create the menubar */
+ menubar = gtk_menu_bar_new();
+ gtk_box_pack_start(GTK_BOX(vbox), 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_viewer_files_build_menu(v));
+/* gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED); */
+ gtk_widget_show(menubar_item);
+
+ /* "Filters" submenu: */
+ menubar_item = gtk_menu_item_new_with_label(MENU_FILTERS);
+ gtk_container_add(GTK_CONTAINER(menubar), menubar_item);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_viewer_filters_build_menu(v));
+/* gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED); */
+ gtk_widget_show(menubar_item);
+
+ gtk_widget_show(menubar);
+
+
+ /* set the main hbox */
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
+ gtk_widget_show(hbox);
+
+
+ /* top hbox for icons */
+ v->button_box = gtk_hbox_new(FALSE, 1);
+ gtk_container_set_border_width(GTK_CONTAINER(v->button_box), 1);
+ gtk_box_pack_start(GTK_BOX(vbox), v->button_box, FALSE, FALSE, 0);
+ gtk_widget_show(v->button_box);
+
+ v->save = xsane_button_new_with_pixmap(v->top->window, v->button_box, file_xpm, DESC_VIEWER_SAVE, (GtkSignalFunc) xsane_viewer_save_callback, v);
+ v->ocr = xsane_button_new_with_pixmap(v->top->window, v->button_box, ocr_xpm, DESC_VIEWER_OCR, (GtkSignalFunc) xsane_viewer_ocr_callback, v);
+ v->clone = xsane_button_new_with_pixmap(v->top->window, v->button_box, clone_xpm, DESC_VIEWER_CLONE, (GtkSignalFunc) xsane_viewer_clone_callback, v);
+ v->scale = xsane_button_new_with_pixmap(v->top->window, v->button_box, scale_xpm, DESC_VIEWER_SCALE, (GtkSignalFunc) xsane_viewer_scale_callback, v);
+ v->despeckle = xsane_button_new_with_pixmap(v->top->window, v->button_box, despeckle_xpm, DESC_VIEWER_DESPECKLE, (GtkSignalFunc) xsane_viewer_despeckle_callback, v);
+ v->blur = xsane_button_new_with_pixmap(v->top->window, v->button_box, blur_xpm, DESC_VIEWER_BLUR, (GtkSignalFunc) xsane_viewer_blur_callback, v);
+ v->rotate90 = xsane_button_new_with_pixmap(v->top->window, v->button_box, rotate90_xpm, DESC_VIEWER_ROTATE90, (GtkSignalFunc) xsane_viewer_rotate90_callback, v);
+ v->rotate180 = xsane_button_new_with_pixmap(v->top->window, v->button_box, rotate180_xpm, DESC_VIEWER_ROTATE180, (GtkSignalFunc) xsane_viewer_rotate180_callback, v);
+ v->rotate270 = xsane_button_new_with_pixmap(v->top->window, v->button_box, rotate270_xpm, DESC_VIEWER_ROTATE270, (GtkSignalFunc) xsane_viewer_rotate270_callback, v);
+ v->mirror_x = xsane_button_new_with_pixmap(v->top->window, v->button_box, mirror_x_xpm, DESC_VIEWER_MIRROR_X, (GtkSignalFunc) xsane_viewer_mirror_x_callback, v);
+ v->mirror_y = xsane_button_new_with_pixmap(v->top->window, v->button_box, mirror_y_xpm, DESC_VIEWER_MIRROR_Y, (GtkSignalFunc) xsane_viewer_mirror_y_callback, v);
+
+
+ /* "Zoom" submenu: */
+ zoom_option_menu = gtk_option_menu_new();
+ xsane_back_gtk_set_tooltip(xsane.tooltips, zoom_option_menu, DESC_VIEWER_ZOOM);
+ gtk_box_pack_start(GTK_BOX(v->button_box), zoom_option_menu, FALSE, FALSE, 0);
+ gtk_widget_show(zoom_option_menu);
+
+ zoom_menu = gtk_menu_new();
+ selection = 0;
+ for (i = 0; i < XSANE_VIEWER_ZOOM_ITEMS; i++)
+ {
+ snprintf(buf, sizeof(buf), "%d %%", xsane_viewer_zoom[i]);
+ zoom_menu_item = gtk_menu_item_new_with_label(buf);
+ gtk_menu_append(GTK_MENU(zoom_menu), zoom_menu_item);
+ gtk_signal_connect(GTK_OBJECT(zoom_menu_item), "activate", (GtkSignalFunc) xsane_viewer_zoom_callback, v);
+ gtk_object_set_data(GTK_OBJECT(zoom_menu_item), "Selection", (void *) xsane_viewer_zoom[i]);
+ gtk_widget_show(zoom_menu_item);
+ if (v->zoom*100 == xsane_viewer_zoom[i])
+ {
+ selection = i;
+ }
+ }
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(zoom_option_menu), zoom_menu);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(zoom_option_menu), selection);
+/* gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED); */
+ gtk_widget_show(zoom_menu);
+
+
+
+ scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
+ gtk_widget_show(scrolled_window);
+
+
+ /* the viewport */
+ v->viewport = gtk_frame_new(/* label */ 0);
+ gtk_frame_set_shadow_type(GTK_FRAME(v->viewport), GTK_SHADOW_IN);
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), v->viewport);
+ gtk_widget_show(v->viewport);
+
+
+ /* image info label */
+ hbox = gtk_hbox_new(FALSE, 1);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 1);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show(hbox);
+ v->image_info_label = gtk_label_new("");
+ gtk_box_pack_start(GTK_BOX(hbox), v->image_info_label, FALSE, FALSE, 2);
+ gtk_widget_show(v->image_info_label);
+
+ gtk_widget_show(v->top);
+
+ if (xsane_viewer_read_image(v)) /* read image and add preview to the viewport */
+ {
+ /* error */
+ }
+
+ v->progress_bar = (GtkProgressBar *) gtk_progress_bar_new();
+#if 0
+ gtk_widget_set_usize(v->progress_bar, 0, 25);
+#endif
+ gtk_box_pack_start(GTK_BOX(vbox), (GtkWidget *) v->progress_bar, FALSE, FALSE, 0);
+ gtk_progress_set_show_text(GTK_PROGRESS(v->progress_bar), TRUE);
+ gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
+ gtk_widget_show(GTK_WIDGET(v->progress_bar));
+
+ return v;
+}
+
+