1 /* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend
2 
3    xsane-viewer.c
4 
5    Oliver Rauch <Oliver.Rauch@rauch-domain.de>
6    Copyright (C) 1998-2010 Oliver Rauch
7    This file is part of the XSANE package.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
22 
23 /* ---------------------------------------------------------------------------------------------------------------------- */
24 
25 #include "xsane.h"
26 #include "xsane-back-gtk.h"
27 #include "xsane-front-gtk.h"
28 #include "xsane-preferences.h"
29 #include "xsane-viewer.h"
30 #include "xsane-gamma.h"
31 #include "xsane-icons.h"
32 #include "xsane-save.h"
33 #include <gdk/gdkkeysyms.h>
34 #include <sys/wait.h>
35 
36 #ifndef PATH_MAX
37 # define PATH_MAX       1024
38 #endif
39 
40 /* ---------------------------------------------------------------------------------------------------------------------- */
41 
42 static int xsane_viewer_zoom[] = {9, 13, 18, 25, 35, 50, 71, 100, 141, 200, 282, 400 };
43 
44 /* ---------------------------------------------------------------------------------------------------------------------- */
45 
46 static void xsane_viewer_set_sensitivity(Viewer *v, int sensitivity);
47 static gint xsane_viewer_close_callback(GtkWidget *window, gpointer data);
48 static void xsane_viewer_dialog_cancel(GtkWidget *window, gpointer data);
49 static void xsane_viewer_save_callback(GtkWidget *window, gpointer data);
50 static void xsane_viewer_ocr_callback(GtkWidget *window, gpointer data);
51 static void xsane_viewer_clone_callback(GtkWidget *window, gpointer data);
52 static void xsane_viewer_despeckle_callback(GtkWidget *window, gpointer data);
53 static void xsane_viewer_blur_callback(GtkWidget *window, gpointer data);
54 static void xsane_viewer_scale_image(GtkWidget *window, gpointer data);
55 static void xsane_viewer_despeckle_image(GtkWidget *window, gpointer data);
56 static void xsane_viewer_blur_image(GtkWidget *window, gpointer data);
57 static void xsane_viewer_rotate(Viewer *v, int rotation);
58 static void xsane_viewer_rotate90_callback(GtkWidget *window, gpointer data);
59 static void xsane_viewer_rotate180_callback(GtkWidget *window, gpointer data);
60 static void xsane_viewer_rotate270_callback(GtkWidget *window, gpointer data);
61 static void xsane_viewer_mirror_x_callback(GtkWidget *window, gpointer data);
62 static void xsane_viewer_mirror_y_callback(GtkWidget *window, gpointer data);
63 static GtkWidget *xsane_viewer_file_build_menu(Viewer *v);
64 static GtkWidget *xsane_viewer_edit_build_menu(Viewer *v);
65 static GtkWidget *xsane_viewer_filters_build_menu(Viewer *v);
66 static int xsane_viewer_read_image(Viewer *v);
67 Viewer *xsane_viewer_new(char *filename, char *selection_filetype, int allow_reduction_to_lineart,
68                          char *output_filename, viewer_modification allow_modification, int image_saved);
69 
70 /* ---------------------------------------------------------------------------------------------------------------------- */
71 
xsane_viewer_set_sensitivity(Viewer * v,int sensitivity)72 static void xsane_viewer_set_sensitivity(Viewer *v, int sensitivity)
73 {
74   if (sensitivity)
75   {
76     v->block_actions = FALSE;
77     gtk_widget_set_sensitive(GTK_WIDGET(v->file_menu), TRUE);
78     gtk_widget_set_sensitive(GTK_WIDGET(v->button_box), TRUE);
79 
80     switch (v->allow_modification)
81     {
82       case VIEWER_NO_MODIFICATION:
83         gtk_widget_set_sensitive(GTK_WIDGET(v->save_menu_item),       FALSE);
84         gtk_widget_set_sensitive(GTK_WIDGET(v->ocr_menu_item),        FALSE);
85         gtk_widget_set_sensitive(GTK_WIDGET(v->clone_menu_item),      FALSE);
86         gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu),            FALSE);
87         gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu),         FALSE);
88         gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu),        FALSE);
89         gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu), v->enable_color_management);
90 
91         gtk_widget_set_sensitive(GTK_WIDGET(v->save),                 FALSE);
92         gtk_widget_set_sensitive(GTK_WIDGET(v->ocr),                  FALSE);
93         gtk_widget_set_sensitive(GTK_WIDGET(v->clone),                FALSE);
94         gtk_widget_set_sensitive(GTK_WIDGET(v->edit_button_box),      FALSE);
95         gtk_widget_set_sensitive(GTK_WIDGET(v->filters_button_box),   FALSE);
96         gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_button_box),  FALSE);
97        break;
98 
99       case VIEWER_NO_NAME_AND_SIZE_MODIFICATION:
100         gtk_widget_set_sensitive(GTK_WIDGET(v->save_menu_item),       TRUE);
101         gtk_widget_set_sensitive(GTK_WIDGET(v->ocr_menu_item),        FALSE);
102         gtk_widget_set_sensitive(GTK_WIDGET(v->clone_menu_item),      FALSE);
103         gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu),            TRUE);
104         gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu),         TRUE);
105         gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu),        FALSE);
106         gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu), v->enable_color_management);
107 
108         gtk_widget_set_sensitive(GTK_WIDGET(v->save),                 TRUE);
109         gtk_widget_set_sensitive(GTK_WIDGET(v->ocr),                  FALSE);
110         gtk_widget_set_sensitive(GTK_WIDGET(v->clone),                FALSE);
111         gtk_widget_set_sensitive(GTK_WIDGET(v->edit_button_box),      TRUE);
112         gtk_widget_set_sensitive(GTK_WIDGET(v->filters_button_box),   TRUE);
113         gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_button_box),  FALSE);
114        break;
115 
116       case VIEWER_NO_NAME_MODIFICATION:
117         gtk_widget_set_sensitive(GTK_WIDGET(v->ocr_menu_item),   FALSE);
118         gtk_widget_set_sensitive(GTK_WIDGET(v->clone_menu_item), FALSE);
119         gtk_widget_set_sensitive(GTK_WIDGET(v->ocr),             FALSE);
120         gtk_widget_set_sensitive(GTK_WIDGET(v->clone),           FALSE);
121         /* fall through */
122 
123       case VIEWER_FULL_MODIFICATION:
124       default:
125         gtk_widget_set_sensitive(GTK_WIDGET(v->save_menu_item),       TRUE);
126         gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu),            TRUE);
127         gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu),         TRUE);
128         gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu),        TRUE);
129         gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu), v->enable_color_management);
130 
131         gtk_widget_set_sensitive(GTK_WIDGET(v->save),                 TRUE);
132         gtk_widget_set_sensitive(GTK_WIDGET(v->edit_button_box),      TRUE);
133         gtk_widget_set_sensitive(GTK_WIDGET(v->filters_button_box),   TRUE);
134         gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_button_box),  TRUE);
135        break;
136     }
137   }
138   else
139   {
140     v->block_actions = TRUE;
141     gtk_widget_set_sensitive(GTK_WIDGET(v->file_menu),            FALSE);
142     gtk_widget_set_sensitive(GTK_WIDGET(v->edit_menu),            FALSE);
143     gtk_widget_set_sensitive(GTK_WIDGET(v->filters_menu),         FALSE);
144     gtk_widget_set_sensitive(GTK_WIDGET(v->geometry_menu),        FALSE);
145     gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu),FALSE);
146     gtk_widget_set_sensitive(GTK_WIDGET(v->button_box),           FALSE);
147   }
148 }
149 
150 /* ---------------------------------------------------------------------------------------------------------------------- */
151 
xsane_viewer_close_callback(GtkWidget * widget,gpointer data)152 static gint xsane_viewer_close_callback(GtkWidget *widget, gpointer data)
153 {
154  Viewer *v, *list, **prev_list;
155 
156   DBG(DBG_proc, "xsane_viewer_close_callback\n");
157 
158   v = (Viewer*) gtk_object_get_data(GTK_OBJECT(widget), "Viewer");
159 
160   if (v->block_actions) /* actions blocked: return */
161   {
162     gdk_beep();
163     DBG(DBG_info, "xsane_viewer_close_callback: actions are blocked\n");
164    return TRUE;
165   }
166 
167   if (!v->image_saved)
168   {
169    char buf[TEXTBUFSIZE];
170 
171     snprintf(buf, sizeof(buf), WARN_VIEWER_IMAGE_NOT_SAVED);
172     xsane_viewer_set_sensitivity(v, FALSE);
173     if (xsane_back_gtk_decision(ERR_HEADER_WARNING, (gchar **) warning_xpm, buf, BUTTON_DO_NOT_CLOSE, BUTTON_DISCARD_IMAGE, TRUE /* wait */))
174     {
175       xsane_viewer_set_sensitivity(v, TRUE);
176       return TRUE;
177     }
178   }
179 
180   /* when no modification is allowed then we work with the original file */
181   /* so we should not erase it */
182   if (v->allow_modification != VIEWER_NO_MODIFICATION)
183   {
184     remove(v->filename);
185   }
186 
187   if (v->undo_filename)
188   {
189     remove(v->undo_filename);
190   }
191 
192   gtk_widget_destroy(v->top);
193 
194 
195   list = xsane.viewer_list;
196   prev_list = &xsane.viewer_list;
197 
198   while (list)
199   {
200     if (list == v)
201     {
202       DBG(DBG_info, "removing viewer from viewer list\n");
203       *prev_list = list->next_viewer;
204       break;
205     }
206 
207     prev_list = &list->next_viewer;
208     list = list->next_viewer;
209   }
210 
211   if (v->active_dialog)
212   {
213     gtk_widget_destroy(v->active_dialog);
214   }
215 
216   if (v->filename)
217   {
218     free(v->filename);
219   }
220 
221   if (v->undo_filename)
222   {
223     free(v->undo_filename);
224   }
225 
226   if (v->output_filename)
227   {
228     free(v->output_filename);
229   }
230 
231   if (v->last_saved_filename)
232   {
233     free(v->last_saved_filename);
234   }
235 
236   free(v);
237 
238  return TRUE;
239 }
240 
241 /* ---------------------------------------------------------------------------------------------------------------------- */
242 
xsane_viewer_dialog_cancel(GtkWidget * window,gpointer data)243 static void xsane_viewer_dialog_cancel(GtkWidget *window, gpointer data)
244 {
245  Viewer *v = (Viewer *) data;
246 
247   xsane_viewer_set_sensitivity(v, TRUE);
248   v->active_dialog = NULL;
249 }
250 
251 /* ---------------------------------------------------------------------------------------------------------------------- */
252 
xsane_viewer_save_callback(GtkWidget * window,gpointer data)253 static void xsane_viewer_save_callback(GtkWidget *window, gpointer data)
254 {
255  Viewer *v = (Viewer *) data;
256  char outputfilename[1024];
257  char *inputfilename;
258  char windowname[TEXTBUFSIZE];
259  int output_format;
260  int abort = 0;
261  int show_extra_widgets;
262  char buf[TEXTBUFSIZE];
263 
264   if (v->block_actions) /* actions blocked: return */
265   {
266     gdk_beep();
267     DBG(DBG_info, "xsane_viewer_save_callback: actions are blocked\n");
268    return;
269   }
270 
271   DBG(DBG_proc, "xsane_viewer_save_callback\n");
272 
273   xsane_viewer_set_sensitivity(v, FALSE);
274 
275   if (v->output_filename)
276   {
277     strncpy(outputfilename, v->output_filename, sizeof(outputfilename));
278   }
279   else
280   {
281     strncpy(outputfilename, preferences.filename, sizeof(outputfilename));
282   }
283 
284   if (v->allow_modification == VIEWER_FULL_MODIFICATION) /* it is allowed to rename the image */
285   {
286     snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_VIEWER_OUTPUT_FILENAME, xsane.device_text);
287 
288     show_extra_widgets = XSANE_GET_FILENAME_SHOW_FILETYPE;
289     if (v->cms_enable)
290     {
291       show_extra_widgets |= XSANE_GET_FILENAME_SHOW_CMS_FUNCTION;
292     }
293 
294     umask((mode_t) preferences.directory_umask); /* define new file permissions */
295     abort = xsane_back_gtk_get_filename(windowname, outputfilename, sizeof(outputfilename), outputfilename, &v->selection_filetype, &v->cms_function, XSANE_FILE_CHOOSER_ACTION_SAVE, show_extra_widgets, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_IMAGES, XSANE_FILE_FILTER_IMAGES);
296     umask(XSANE_DEFAULT_UMASK); /* define new file permissions */
297 
298     if (abort)
299     {
300       xsane_viewer_set_sensitivity(v, TRUE);
301      return;
302     }
303   }
304 
305   if (v->output_filename)
306   {
307     free(v->output_filename);
308   }
309 
310   v->output_filename = strdup(outputfilename);
311 
312 #if 0
313   /* to be removed */
314   xsane_update_counter_in_filename(&v->output_filename, FALSE, 0, preferences.filename_counter_len); /* set correct counter length */
315 #endif
316 
317 
318   if ((preferences.overwrite_warning) && (!v->keep_viewer_pnm_format))  /* test if filename already used when filename can be changed by user */
319   {
320    FILE *testfile;
321 
322     testfile = fopen(v->output_filename, "rb"); /* read binary (b for win32) */
323     if (testfile) /* filename used: skip */
324     {
325      char buf[TEXTBUFSIZE];
326 
327       fclose(testfile);
328       snprintf(buf, sizeof(buf), WARN_FILE_EXISTS, v->output_filename);
329       if (xsane_back_gtk_decision(ERR_HEADER_WARNING, (gchar **) warning_xpm, buf, BUTTON_OVERWRITE, BUTTON_CANCEL, TRUE /* wait */) == FALSE)
330       {
331         xsane_viewer_set_sensitivity(v, TRUE);
332        return;
333       }
334     }
335   }
336 
337   inputfilename = strdup(v->filename);
338 
339   output_format = xsane_identify_output_format(v->output_filename, v->selection_filetype, 0);
340 
341   if (((!v->allow_reduction_to_lineart) && (output_format == XSANE_PNM)) || /* save PNM but do not reduce to lineart (if lineart) */
342       (v->keep_viewer_pnm_format)) /* we have to make sure that we save in viewer pnm format */
343   {
344     if (xsane_create_secure_file(v->output_filename)) /* remove possibly existing symbolic links for security */
345     {
346      char buf[TEXTBUFSIZE];
347 
348       snprintf(buf, sizeof(buf), "%s %s %s\n", ERR_DURING_SAVE, ERR_CREATE_SECURE_FILE, v->output_filename);
349       xsane_back_gtk_error(buf, TRUE);
350       xsane_viewer_set_sensitivity(v, TRUE);
351      return; /* error */
352     }
353 
354     snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_SAVING_DATA, v->output_filename);
355     gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), buf);
356 
357     xsane_copy_file_by_name(v->output_filename, v->filename, v->progress_bar, &v->cancel_save);
358   }
359   else
360   {
361     xsane_save_image_as(v->output_filename, inputfilename, output_format, v->cms_enable, v->cms_function, v->cms_intent, v->cms_bpc, v->progress_bar, &v->cancel_save);
362   }
363 
364   free(inputfilename);
365 
366   v->image_saved = TRUE;
367 
368   v->last_saved_filename = strdup(v->output_filename);
369   snprintf(buf, sizeof(buf), "%s %s - %s", WINDOW_VIEWER, v->last_saved_filename, xsane.device_text);
370   gtk_window_set_title(GTK_WINDOW(v->top), buf);
371 
372   if (xsane.print_filenames) /* print created filenames to stdout? */
373   {
374     if (v->output_filename[0] != '/') /* relative path */
375     {
376      char pathname[512];
377       getcwd(pathname, sizeof(pathname));
378       printf("XSANE_IMAGE_FILENAME: %s/%s\n", pathname, v->output_filename);
379       fflush(stdout);
380     }
381     else /* absolute path */
382     {
383       printf("XSANE_IMAGE_FILENAME: %s\n", v->output_filename);
384       fflush(stdout);
385     }
386   }
387 
388   xsane_viewer_set_sensitivity(v, TRUE);
389 }
390 
391 /* ---------------------------------------------------------------------------------------------------------------------- */
392 
xsane_viewer_ocr_callback(GtkWidget * window,gpointer data)393 static void xsane_viewer_ocr_callback(GtkWidget *window, gpointer data)
394 {
395  Viewer *v = (Viewer *) data;
396  char outputfilename[1024];
397  char *extensionptr;
398  char windowname[TEXTBUFSIZE];
399  int abort = 0;
400 
401   if (v->block_actions) /* actions blocked: return */
402   {
403     gdk_beep();
404     DBG(DBG_info, "xsane_viewer_ocr_callback: actions are blocked\n");
405    return;
406   }
407 
408   DBG(DBG_proc, "xsane_viewer_ocr_callback\n");
409 
410   xsane_viewer_set_sensitivity(v, FALSE);
411 
412   strncpy(outputfilename, preferences.filename, sizeof(outputfilename)-5);
413 
414   extensionptr = strchr(outputfilename, '.');
415   if (!extensionptr)
416   {
417     extensionptr=outputfilename + strlen(outputfilename);
418   }
419   strcpy(extensionptr, ".txt");
420 
421   snprintf(windowname, sizeof(windowname), "%s %s %s", xsane.prog_name, WINDOW_OCR_OUTPUT_FILENAME, xsane.device_text);
422 
423   umask((mode_t) preferences.directory_umask); /* define new file permissions */
424   abort = xsane_back_gtk_get_filename(windowname, outputfilename, sizeof(outputfilename), outputfilename, NULL, NULL, XSANE_FILE_CHOOSER_ACTION_SAVE, XSANE_GET_FILENAME_SHOW_FILETYPE, XSANE_FILE_FILTER_ALL | XSANE_FILE_FILTER_IMAGES, XSANE_FILE_FILTER_IMAGES);
425   umask(XSANE_DEFAULT_UMASK); /* define new file permissions */
426 
427   if (abort)
428   {
429     xsane_viewer_set_sensitivity(v, TRUE);
430    return;
431   }
432 
433   while (gtk_events_pending()) /* give gtk the chance to remove the file selection dialog */
434   {
435     gtk_main_iteration();
436   }
437 
438   xsane_save_image_as_text(outputfilename, v->filename, v->progress_bar, &v->cancel_save);
439 
440   xsane_viewer_set_sensitivity(v, TRUE);
441 }
442 
443 /* ---------------------------------------------------------------------------------------------------------------------- */
444 
xsane_viewer_clone_callback(GtkWidget * window,gpointer data)445 static void xsane_viewer_clone_callback(GtkWidget *window, gpointer data)
446 {
447  Viewer *v = (Viewer *) data;
448  char outfilename[PATH_MAX];
449 
450   if (v->block_actions) /* actions blocked: return */
451   {
452     gdk_beep();
453     DBG(DBG_info, "xsane_viewer_clone_callback: actions are blocked\n");
454    return;
455   }
456 
457   DBG(DBG_proc, "xsane_viewer_clone_callback\n");
458 
459   xsane_viewer_set_sensitivity(v, FALSE);
460 
461   xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
462   gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_CLONING_DATA);
463   xsane_copy_file_by_name(outfilename, v->filename, v->progress_bar, &v->cancel_save);
464 
465   xsane_viewer_set_sensitivity(v, TRUE);
466 
467   if (v->last_saved_filename)
468   {
469    char buf[TEXTBUFSIZE];
470     snprintf(buf, sizeof(buf), "%s%s", FILENAME_PREFIX_CLONE_OF, v->last_saved_filename);
471     xsane_viewer_new(outfilename, v->selection_filetype, v->allow_reduction_to_lineart, buf, v->allow_modification, v->image_saved);
472   }
473   else
474   {
475     xsane_viewer_new(outfilename, v->selection_filetype, v->allow_reduction_to_lineart, NULL, v->allow_modification, v->image_saved);
476   }
477 }
478 
479 /* ---------------------------------------------------------------------------------------------------------------------- */
480 
xsane_viewer_adjustment_float_changed(GtkAdjustment * adj_data,float * val)481 static void xsane_viewer_adjustment_float_changed(GtkAdjustment *adj_data, float *val)
482 {
483   *val = (float) adj_data->value;
484 }
485 
486 /* ---------------------------------------------------------------------------------------------------------------------- */
487 
xsane_viewer_adjustment_int_changed(GtkAdjustment * adj_data,int * val)488 static void xsane_viewer_adjustment_int_changed(GtkAdjustment *adj_data, int *val)
489 {
490   *val = (int) adj_data->value;
491 }
492 
493 /* ---------------------------------------------------------------------------------------------------------------------- */
494 
xsane_viewer_button_changed(GtkWidget * button,int * val)495 static void xsane_viewer_button_changed(GtkWidget *button, int *val)
496 {
497   *val = GTK_TOGGLE_BUTTON(button)->active;
498 }
499 
500 /* ---------------------------------------------------------------------------------------------------------------------- */
501 
xsane_viewer_scale_set_scale_value_and_adjustments(GtkAdjustment * adj_data,double * scale_val)502 static void xsane_viewer_scale_set_scale_value_and_adjustments(GtkAdjustment *adj_data, double *scale_val)
503 {
504  GtkAdjustment *adj;
505  int image_width, image_height;
506 
507   *scale_val = adj_data->value;
508 
509   image_width  = (int) gtk_object_get_data(GTK_OBJECT(adj_data), "image_width");
510   image_height = (int) gtk_object_get_data(GTK_OBJECT(adj_data), "image_height");
511 
512   adj = (GtkAdjustment*) gtk_object_get_data(GTK_OBJECT(adj_data), "size-x-adjustment");
513   if ((adj) && (image_width))
514   {
515     gtk_adjustment_set_value(adj, (*scale_val) * image_width);
516   }
517 
518   adj = (GtkAdjustment*) gtk_object_get_data(GTK_OBJECT(adj_data), "size-y-adjustment");
519   if ((adj) && (image_height))
520   {
521     gtk_adjustment_set_value(adj, (*scale_val) * image_height);
522   }
523 }
524 
525 /* ---------------------------------------------------------------------------------------------------------------------- */
526 
xsane_viewer_scale_set_size_x_value_and_adjustments(GtkAdjustment * adj_data,double * scale_val)527 static void xsane_viewer_scale_set_size_x_value_and_adjustments(GtkAdjustment *adj_data, double *scale_val)
528 {
529  GtkAdjustment *adj;
530  int image_width, image_height;
531 
532   image_width  = (int) gtk_object_get_data(GTK_OBJECT(adj_data), "image_width");
533   image_height = (int) gtk_object_get_data(GTK_OBJECT(adj_data), "image_height");
534 
535   if (!image_width)
536   {
537     return; /* we are not able to calulate the scale value */
538   }
539 
540   *scale_val = adj_data->value / image_width;
541 
542   adj = (GtkAdjustment*) gtk_object_get_data(GTK_OBJECT(adj_data), "scale-adjustment");
543   if (adj)
544   {
545     gtk_adjustment_set_value(adj, *scale_val);
546   }
547 }
548 
549 /* ---------------------------------------------------------------------------------------------------------------------- */
550 
xsane_viewer_scale_set_size_y_value_and_adjustments(GtkAdjustment * adj_data,double * scale_val)551 static void xsane_viewer_scale_set_size_y_value_and_adjustments(GtkAdjustment *adj_data, double *scale_val)
552 {
553  GtkAdjustment *adj;
554  int image_width, image_height;
555 
556   image_width  = (int) gtk_object_get_data(GTK_OBJECT(adj_data), "image_width");
557   image_height = (int) gtk_object_get_data(GTK_OBJECT(adj_data), "image_height");
558 
559   if (!image_height)
560   {
561     return; /* we are not able to calulate the scale value */
562   }
563 
564   *scale_val = adj_data->value / image_height;
565 
566   adj = (GtkAdjustment*) gtk_object_get_data(GTK_OBJECT(adj_data), "scale-adjustment");
567   if (adj)
568   {
569     gtk_adjustment_set_value(adj, *scale_val);
570   }
571 }
572 
573 /* ---------------------------------------------------------------------------------------------------------------------- */
574 
xsane_viewer_scale_callback(GtkWidget * window,gpointer data)575 static void xsane_viewer_scale_callback(GtkWidget *window, gpointer data)
576 {
577  Viewer *v = (Viewer *) data;
578  GtkWidget *selection_dialog;
579  GtkWidget *frame;
580  GtkWidget *hbox, *vbox;
581  GtkWidget *button;
582  GtkWidget *scale_widget, *scalex_widget, *scaley_widget;
583  GtkAdjustment *adjustment_size_x;
584  GtkAdjustment *adjustment_size_y;
585  GtkWidget *spinbutton;
586  GdkPixmap *pixmap;
587  GdkBitmap *mask;
588  GtkWidget *pixmapwidget;
589  char buf[TEXTBUFSIZE];
590  FILE *infile;
591  Image_info image_info;
592 
593   if (v->block_actions == TRUE) /* actions blocked: return */
594   {
595     gdk_beep();
596     DBG(DBG_info, "xsane_viewer_scale_callback: actions are blocked\n");
597    return;
598   }
599 
600   DBG(DBG_proc, "xsane_viewer_scale_callback\n");
601 
602   xsane_viewer_set_sensitivity(v, FALSE);
603   v->block_actions = 2; /* do not set it to TRUE because we have to recall this dialog! */
604 
605   infile = fopen(v->filename, "rb");
606   if (!infile)
607   {
608     DBG(DBG_error, "could not load file %s\n", v->filename);
609     xsane_viewer_set_sensitivity(v, TRUE);
610    return;
611   }
612 
613   xsane_read_pnm_header(infile, &image_info);
614 
615   fclose(infile);
616 
617 
618   if (v->output_filename)
619   {
620     snprintf(buf, sizeof(buf), "%s: %s", WINDOW_SCALE, v->output_filename);
621   }
622   else
623   {
624     snprintf(buf, sizeof(buf), WINDOW_SCALE);
625   }
626 
627   if (v->active_dialog) /* use active dialog */
628   {
629     selection_dialog = v->active_dialog;
630     gtk_container_foreach(GTK_CONTAINER(selection_dialog), (GtkCallback) gtk_widget_destroy, NULL);
631     if (!v->bind_scale)
632     {
633       v->y_scale_factor = v->x_scale_factor;
634     }
635   }
636   else /* first time the dialog is opened */
637   {
638     selection_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
639     gtk_window_set_resizable(GTK_WINDOW(selection_dialog), FALSE);
640     gtk_window_set_position(GTK_WINDOW(selection_dialog), GTK_WIN_POS_MOUSE);
641     gtk_window_set_title(GTK_WINDOW(selection_dialog), buf);
642     xsane_set_window_icon(selection_dialog, 0);
643     g_signal_connect(GTK_OBJECT(selection_dialog), "destroy", (GtkSignalFunc) xsane_viewer_dialog_cancel, (void *) v);
644 
645     v->active_dialog = selection_dialog;
646     v->x_scale_factor = 1.0;
647     v->y_scale_factor = 1.0;
648     v->bind_scale = TRUE;
649   }
650 
651   frame = gtk_frame_new(0);
652   gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
653   gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
654   gtk_container_add(GTK_CONTAINER(selection_dialog), frame);
655   gtk_widget_show(frame);
656 
657   vbox = gtk_vbox_new(FALSE, 5);
658   gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
659   gtk_container_add(GTK_CONTAINER(frame), vbox);
660   gtk_widget_show(vbox);
661 
662   /* bind scale */
663   button = gtk_check_button_new_with_label(BUTTON_SCALE_BIND);
664   gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 5);
665   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), v->bind_scale);
666   g_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_viewer_button_changed, (void *) &v->bind_scale);
667   g_signal_connect_after(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_viewer_scale_callback, (void *) v);
668   gtk_widget_show(button);
669 
670   if (v->bind_scale)
671   {
672     hbox = gtk_hbox_new(FALSE, 0);
673     gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
674     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
675     gtk_widget_show(hbox);
676 
677     /* scale factor: <-> */
678     xsane_range_new_with_pixmap(xsane.xsane_window->window, GTK_BOX(hbox), zoom_xpm,
679                                 DESC_SCALE_FACTOR,
680                                 0.01, 4.0, 0.01, 0.1, 2, &v->x_scale_factor, &scale_widget,
681                                 0, xsane_viewer_scale_set_scale_value_and_adjustments,
682                                 TRUE);
683 
684     /* x-size */
685     pixmap = gdk_pixmap_create_from_xpm_d(selection_dialog->window, &mask, xsane.bg_trans, (gchar **) size_x_xpm);
686     pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask);
687     gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 20);
688     gtk_widget_show(pixmapwidget);
689     gdk_drawable_unref(pixmap);
690     gdk_drawable_unref(mask);
691 
692     adjustment_size_x = (GtkAdjustment *) gtk_adjustment_new(v->x_scale_factor * image_info.image_width , 0.01 * image_info.image_width, 4.0 * image_info.image_width, 1.0, 5.0, 0.0);
693     spinbutton = gtk_spin_button_new(adjustment_size_x, 0, 0);
694     g_signal_connect(GTK_OBJECT(adjustment_size_x), "value_changed", (GtkSignalFunc) xsane_viewer_scale_set_size_x_value_and_adjustments, (void *) &v->x_scale_factor);
695     gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), FALSE);
696     gtk_widget_set_size_request(spinbutton, 80, -1);
697     gtk_box_pack_start(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 0);
698     gtk_widget_show(spinbutton);
699     xsane_back_gtk_set_tooltip(xsane.tooltips, spinbutton, DESC_SCALE_WIDTH);
700 
701     /* y-size */
702     pixmap = gdk_pixmap_create_from_xpm_d(selection_dialog->window, &mask, xsane.bg_trans, (gchar **) size_y_xpm);
703     pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask);
704     gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 20);
705     gtk_widget_show(pixmapwidget);
706     gdk_drawable_unref(pixmap);
707     gdk_drawable_unref(mask);
708 
709     adjustment_size_y = (GtkAdjustment *) gtk_adjustment_new(v->x_scale_factor * image_info.image_height , 0.01 * image_info.image_height, 4.0 * image_info.image_height, 1.0, 5.0, 0.0);
710     spinbutton = gtk_spin_button_new(adjustment_size_y, 0, 0);
711     g_signal_connect(GTK_OBJECT(adjustment_size_y), "value_changed", (GtkSignalFunc) xsane_viewer_scale_set_size_y_value_and_adjustments, (void *) &v->x_scale_factor);
712     gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), FALSE);
713     gtk_widget_set_size_request(spinbutton, 80, -1);
714     gtk_box_pack_start(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 0);
715     gtk_widget_show(spinbutton);
716     xsane_back_gtk_set_tooltip(xsane.tooltips, spinbutton, DESC_SCALE_HEIGHT);
717 
718     gtk_object_set_data(GTK_OBJECT(scale_widget), "size-x-adjustment", (void *) adjustment_size_x);
719     gtk_object_set_data(GTK_OBJECT(scale_widget), "size-y-adjustment", (void *) adjustment_size_y);
720     gtk_object_set_data(GTK_OBJECT(scale_widget), "image_width",       (void *) image_info.image_width);
721     gtk_object_set_data(GTK_OBJECT(scale_widget), "image_height",      (void *) image_info.image_height);
722 
723     gtk_object_set_data(GTK_OBJECT(adjustment_size_x), "scale-adjustment",   (void *) scale_widget);
724     gtk_object_set_data(GTK_OBJECT(adjustment_size_x), "size-y-adjustment",  (void *) adjustment_size_y);
725     gtk_object_set_data(GTK_OBJECT(adjustment_size_x), "image_width",        (void *) image_info.image_width);
726     gtk_object_set_data(GTK_OBJECT(adjustment_size_x), "image_height",       (void *) image_info.image_height);
727 
728     gtk_object_set_data(GTK_OBJECT(adjustment_size_y), "scale-adjustment",   (void *) scale_widget);
729     gtk_object_set_data(GTK_OBJECT(adjustment_size_y), "size-x-adjustment",  (void *) adjustment_size_x);
730     gtk_object_set_data(GTK_OBJECT(adjustment_size_y), "image_width",        (void *) image_info.image_width);
731     gtk_object_set_data(GTK_OBJECT(adjustment_size_y), "image_height",       (void *) image_info.image_height);
732   }
733   else
734   {
735     /* X */
736     hbox = gtk_hbox_new(FALSE, 0);
737     gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
738     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
739     gtk_widget_show(hbox);
740 
741     /* x_scale factor: <-> */
742     xsane_range_new_with_pixmap(xsane.xsane_window->window, GTK_BOX(hbox), zoom_x_xpm,
743                                 DESC_X_SCALE_FACTOR,
744                                 0.01, 4.0, 0.01, 0.1, 2, &v->x_scale_factor, &scalex_widget,
745                                 0, xsane_viewer_scale_set_scale_value_and_adjustments,
746                                 TRUE);
747 
748     /* x-size */
749     pixmap = gdk_pixmap_create_from_xpm_d(selection_dialog->window, &mask, xsane.bg_trans, (gchar **) size_x_xpm);
750     pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask);
751     gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 20);
752     gtk_widget_show(pixmapwidget);
753     gdk_drawable_unref(pixmap);
754     gdk_drawable_unref(mask);
755 
756     adjustment_size_x = (GtkAdjustment *) gtk_adjustment_new(v->x_scale_factor * image_info.image_width , 0.01 * image_info.image_width, 4.0 * image_info.image_width, 1.0, 5.0, 0.0);
757     spinbutton = gtk_spin_button_new(adjustment_size_x, 0, 0);
758     g_signal_connect(GTK_OBJECT(adjustment_size_x), "value_changed", (GtkSignalFunc) xsane_viewer_scale_set_size_x_value_and_adjustments, (void *) &v->x_scale_factor);
759     gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), FALSE);
760     gtk_widget_set_size_request(spinbutton, 80, -1);
761     gtk_box_pack_start(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 0);
762     gtk_widget_show(spinbutton);
763     xsane_back_gtk_set_tooltip(xsane.tooltips, spinbutton, DESC_SCALE_WIDTH);
764 
765     gtk_object_set_data(GTK_OBJECT(scalex_widget), "size-x-adjustment",  (void *) adjustment_size_x);
766     gtk_object_set_data(GTK_OBJECT(scalex_widget), "image_width",        (void *) image_info.image_width);
767     gtk_object_set_data(GTK_OBJECT(scalex_widget), "image_height",       (void *) image_info.image_height);
768 
769     gtk_object_set_data(GTK_OBJECT(adjustment_size_x), "scale-adjustment",   (void *) scalex_widget);
770     gtk_object_set_data(GTK_OBJECT(adjustment_size_x), "image_width",        (void *) image_info.image_width);
771     gtk_object_set_data(GTK_OBJECT(adjustment_size_x), "image_height",       (void *) image_info.image_height);
772 
773 
774     /* Y */
775     hbox = gtk_hbox_new(FALSE, 0);
776     gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
777     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
778     gtk_widget_show(hbox);
779 
780     /* y_scale factor: <-> */
781     xsane_range_new_with_pixmap(xsane.xsane_window->window, GTK_BOX(hbox), zoom_y_xpm,
782                                 DESC_Y_SCALE_FACTOR,
783                                 0.01, 4.0, 0.01, 0.1, 2, &v->y_scale_factor, &scaley_widget,
784                                 0, xsane_viewer_scale_set_scale_value_and_adjustments,
785                                 TRUE);
786 
787     /* y-size */
788     pixmap = gdk_pixmap_create_from_xpm_d(selection_dialog->window, &mask, xsane.bg_trans, (gchar **) size_y_xpm);
789     pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask);
790     gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 20);
791     gtk_widget_show(pixmapwidget);
792     gdk_drawable_unref(pixmap);
793     gdk_drawable_unref(mask);
794 
795     adjustment_size_y = (GtkAdjustment *) gtk_adjustment_new(v->y_scale_factor * image_info.image_height , 0.01 * image_info.image_height, 4.0 * image_info.image_height, 1.0, 5.0, 0.0);
796     spinbutton = gtk_spin_button_new(adjustment_size_y, 0, 0);
797     g_signal_connect(GTK_OBJECT(adjustment_size_y), "value_changed", (GtkSignalFunc) xsane_viewer_scale_set_size_y_value_and_adjustments, (void *) &v->y_scale_factor);
798     gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), FALSE);
799     gtk_widget_set_size_request(spinbutton, 80, -1);
800     gtk_box_pack_start(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 0);
801     gtk_widget_show(spinbutton);
802     xsane_back_gtk_set_tooltip(xsane.tooltips, spinbutton, DESC_SCALE_HEIGHT);
803 
804     gtk_object_set_data(GTK_OBJECT(scaley_widget), "size-y-adjustment", (void *) adjustment_size_y);
805     gtk_object_set_data(GTK_OBJECT(scaley_widget), "image_width",       (void *) image_info.image_width);
806     gtk_object_set_data(GTK_OBJECT(scaley_widget), "image_height",      (void *) image_info.image_height);
807 
808     gtk_object_set_data(GTK_OBJECT(adjustment_size_y), "scale-adjustment",   (void *) scaley_widget);
809     gtk_object_set_data(GTK_OBJECT(adjustment_size_y), "image_width",        (void *) image_info.image_width);
810     gtk_object_set_data(GTK_OBJECT(adjustment_size_y), "image_height",       (void *) image_info.image_height);
811   }
812 
813   /* Apply Cancel */
814 
815   hbox = gtk_hbox_new(FALSE, 0);
816   gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
817   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
818   gtk_widget_show(hbox);
819 
820   button = gtk_button_new_with_label(BUTTON_APPLY);
821   GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
822   g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_viewer_scale_image, (void *) v);
823   g_signal_connect_swapped(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
824 
825   gtk_container_add(GTK_CONTAINER(hbox), button);
826   gtk_widget_grab_default(button);
827   gtk_widget_show(button);
828 
829   button = gtk_button_new_with_label(BUTTON_CANCEL);
830   g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_viewer_dialog_cancel, (void *) v);
831   g_signal_connect_swapped(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
832   gtk_container_add(GTK_CONTAINER(hbox), button);
833   gtk_widget_show(button);
834 
835   gtk_widget_show(selection_dialog);
836 }
837 
838 /* ---------------------------------------------------------------------------------------------------------------------- */
839 
xsane_viewer_despeckle_callback(GtkWidget * window,gpointer data)840 static void xsane_viewer_despeckle_callback(GtkWidget *window, gpointer data)
841 {
842  Viewer *v = (Viewer *) data;
843  GtkWidget *selection_dialog;
844  GtkWidget *frame;
845  GtkWidget *hbox, *vbox;
846  GtkWidget *label, *spinbutton, *button;
847  GtkAdjustment *adjustment;
848  char buf[TEXTBUFSIZE];
849 
850   if (v->block_actions) /* actions blocked: return */
851   {
852     gdk_beep();
853     DBG(DBG_info, "xsane_viewer_despeckle_callback: actions are blocked\n");
854    return;
855   }
856 
857   DBG(DBG_proc, "xsane_viewer_despeckle_callback\n");
858 
859   xsane_viewer_set_sensitivity(v, FALSE);
860 
861   if (v->output_filename)
862   {
863     snprintf(buf, sizeof(buf), "%s: %s", WINDOW_DESPECKLE, v->output_filename);
864   }
865   else
866   {
867     snprintf(buf, sizeof(buf), WINDOW_DESPECKLE);
868   }
869 
870   selection_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
871   gtk_window_set_position(GTK_WINDOW(selection_dialog), GTK_WIN_POS_MOUSE);
872   gtk_window_set_title(GTK_WINDOW(selection_dialog), buf);
873   xsane_set_window_icon(selection_dialog, 0);
874   g_signal_connect(GTK_OBJECT(selection_dialog), "destroy", (GtkSignalFunc) xsane_viewer_dialog_cancel, (void *) v);
875 
876   v->active_dialog = selection_dialog;
877 
878   frame = gtk_frame_new(0);
879   gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
880   gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
881   gtk_container_add(GTK_CONTAINER(selection_dialog), frame);
882   gtk_widget_show(frame);
883 
884   vbox = gtk_vbox_new(FALSE, 5);
885   gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
886   gtk_container_add(GTK_CONTAINER(frame), vbox);
887   gtk_widget_show(vbox);
888 
889   /* Despeckle radius: <-> */
890 
891   v->despeckle_radius = 2;
892 
893   hbox = gtk_hbox_new(FALSE, 2);
894   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
895   gtk_widget_show(hbox);
896 
897   label = gtk_label_new(TEXT_DESPECKLE_RADIUS);
898   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
899   gtk_widget_show(label);
900 
901   adjustment = (GtkAdjustment *) gtk_adjustment_new(2.0, 2.0, 10.0, 1.0, 5.0, 0.0);
902   spinbutton = gtk_spin_button_new(adjustment, 0, 0);
903   g_signal_connect(GTK_OBJECT(adjustment), "value_changed", (GtkSignalFunc) xsane_viewer_adjustment_int_changed, (void *) &v->despeckle_radius);
904   gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), TRUE);
905   gtk_box_pack_end(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 10);
906   gtk_widget_show(spinbutton);
907 
908   /* Apply Cancel */
909 
910   hbox = gtk_hbox_new(FALSE, 0);
911   gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
912   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
913   gtk_widget_show(hbox);
914 
915   button = gtk_button_new_with_label(BUTTON_APPLY);
916   GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
917   g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_viewer_despeckle_image, (void *) v);
918   g_signal_connect_swapped(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
919   gtk_container_add(GTK_CONTAINER(hbox), button);
920   gtk_widget_grab_default(button);
921   gtk_widget_show(button);
922 
923   button = gtk_button_new_with_label(BUTTON_CANCEL);
924   g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_viewer_dialog_cancel, (void *) v);
925   g_signal_connect_swapped(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
926   gtk_container_add(GTK_CONTAINER(hbox), button);
927   gtk_widget_show(button);
928 
929   gtk_widget_show(selection_dialog);
930 }
931 
932 /* ---------------------------------------------------------------------------------------------------------------------- */
933 
xsane_viewer_blur_callback(GtkWidget * window,gpointer data)934 static void xsane_viewer_blur_callback(GtkWidget *window, gpointer data)
935 {
936  Viewer *v = (Viewer *) data;
937  GtkWidget *selection_dialog;
938  GtkWidget *frame;
939  GtkWidget *hbox, *vbox;
940  GtkWidget *label, *spinbutton, *button;
941  GtkAdjustment *adjustment;
942  char buf[TEXTBUFSIZE];
943 
944   if (v->block_actions) /* actions blocked: return */
945   {
946     gdk_beep();
947     DBG(DBG_info, "xsane_viewer_blur_callback: actions are blocked\n");
948    return;
949   }
950 
951   DBG(DBG_proc, "xsane_viewer_blur_callback\n");
952 
953   xsane_viewer_set_sensitivity(v, FALSE);
954 
955   if (v->output_filename)
956   {
957     snprintf(buf, sizeof(buf), "%s: %s", WINDOW_BLUR, v->output_filename);
958   }
959   else
960   {
961     snprintf(buf, sizeof(buf), WINDOW_BLUR);
962   }
963 
964   selection_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
965   gtk_window_set_position(GTK_WINDOW(selection_dialog), GTK_WIN_POS_MOUSE);
966   gtk_window_set_title(GTK_WINDOW(selection_dialog), buf);
967   xsane_set_window_icon(selection_dialog, 0);
968   g_signal_connect(GTK_OBJECT(selection_dialog), "destroy", (GtkSignalFunc) xsane_viewer_dialog_cancel, (void *) v);
969 
970   v->active_dialog = selection_dialog;
971 
972   frame = gtk_frame_new(0);
973   gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
974   gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
975   gtk_container_add(GTK_CONTAINER(selection_dialog), frame);
976   gtk_widget_show(frame);
977 
978   vbox = gtk_vbox_new(FALSE, 5);
979   gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
980   gtk_container_add(GTK_CONTAINER(frame), vbox);
981   gtk_widget_show(vbox);
982 
983 
984   /* Blur radius: <-> */
985 
986   v->blur_radius = 1.0;
987 
988   hbox = gtk_hbox_new(FALSE, 2);
989   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
990   gtk_widget_show(hbox);
991 
992   label = gtk_label_new(TEXT_BLUR_RADIUS);
993   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
994   gtk_widget_show(label);
995 
996   adjustment = (GtkAdjustment *) gtk_adjustment_new(1.0, 1.0, 20.0, 0.1, 1.0, 0.0);
997   spinbutton = gtk_spin_button_new(adjustment, 0, 2);
998   g_signal_connect(GTK_OBJECT(adjustment), "value_changed", (GtkSignalFunc) xsane_viewer_adjustment_float_changed, (void *) &v->blur_radius);
999   gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), TRUE);
1000   gtk_box_pack_end(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 10);
1001   gtk_widget_show(spinbutton);
1002 
1003   /* Apply Cancel */
1004 
1005   hbox = gtk_hbox_new(FALSE, 0);
1006   gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
1007   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
1008   gtk_widget_show(hbox);
1009 
1010   button = gtk_button_new_with_label(BUTTON_APPLY);
1011   GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1012   g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_viewer_blur_image, (void *) v);
1013   gtk_container_add(GTK_CONTAINER(hbox), button);
1014   gtk_widget_grab_default(button);
1015   gtk_widget_show(button);
1016 
1017   button = gtk_button_new_with_label(BUTTON_CANCEL);
1018   g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_viewer_dialog_cancel, (void *) v);
1019   g_signal_connect_swapped(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (GtkObject *) selection_dialog);
1020   gtk_container_add(GTK_CONTAINER(hbox), button);
1021   gtk_widget_show(button);
1022 
1023   gtk_widget_show(selection_dialog);
1024 }
1025 
1026 /* ---------------------------------------------------------------------------------------------------------------------- */
1027 
xsane_viewer_undo_callback(GtkWidget * window,gpointer data)1028 static void xsane_viewer_undo_callback(GtkWidget *window, gpointer data)
1029 {
1030  Viewer *v = (Viewer *) data;
1031 
1032   DBG(DBG_proc, "xsane_viewer_undo_callback\n");
1033 
1034   if (!v->undo_filename)
1035   {
1036     DBG(DBG_info, "no undo file\n");
1037    return;
1038   }
1039 
1040   DBG(DBG_info, "removing file %s\n", v->filename);
1041   remove(v->filename);
1042 
1043   DBG(DBG_info, "using undo file %s\n", v->undo_filename);
1044   v->filename = v->undo_filename;
1045 
1046   v->undo_filename = NULL;
1047   v->image_saved = FALSE;
1048 
1049   xsane_viewer_read_image(v);
1050 
1051   if (v->last_saved_filename)
1052   {
1053    char buf[TEXTBUFSIZE];
1054     snprintf(buf, sizeof(buf), "%s (%s) - %s", WINDOW_VIEWER, v->last_saved_filename, xsane.device_text);
1055     gtk_window_set_title(GTK_WINDOW(v->top), buf);
1056   }
1057 
1058   gtk_widget_set_sensitive(GTK_WIDGET(v->undo), FALSE);
1059   gtk_widget_set_sensitive(GTK_WIDGET(v->undo_menu_item), FALSE);
1060 }
1061 
1062 /* ---------------------------------------------------------------------------------------------------------------------- */
1063 
xsane_viewer_scale_image(GtkWidget * window,gpointer data)1064 static void xsane_viewer_scale_image(GtkWidget *window, gpointer data)
1065 {
1066  FILE *outfile;
1067  FILE *infile;
1068  char outfilename[PATH_MAX];
1069  Viewer *v = (Viewer *) data;
1070  Image_info image_info;
1071 
1072   DBG(DBG_proc, "xsane_viewer_scale_image\n");
1073 
1074   gtk_widget_destroy(v->active_dialog);
1075 
1076   xsane_viewer_set_sensitivity(v, FALSE);
1077 
1078   infile = fopen(v->filename, "rb");
1079   if (!infile)
1080   {
1081     DBG(DBG_error, "could not load file %s\n", v->filename);
1082     xsane_viewer_set_sensitivity(v, TRUE);
1083    return;
1084   }
1085 
1086   xsane_read_pnm_header(infile, &image_info);
1087 
1088   DBG(DBG_info, "scaling image %s with geometry: %d x %d x %d, %d channels\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels);
1089 
1090   xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
1091 
1092   outfile = fopen(outfilename, "wb");
1093   if (!outfile)
1094   {
1095     DBG(DBG_error, "could not save file %s\n", outfilename);
1096     xsane_viewer_set_sensitivity(v, TRUE);
1097    return;
1098   }
1099 
1100   gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_SCALING_DATA);
1101 
1102   xsane_progress_bar_set_fraction(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
1103 
1104   if (v->bind_scale)
1105   {
1106     v->y_scale_factor = v->x_scale_factor;
1107   }
1108 
1109   xsane_save_scaled_image(outfile, infile, &image_info, v->x_scale_factor, v->y_scale_factor, v->progress_bar, &v->cancel_save);
1110 
1111   fclose(infile);
1112   fclose(outfile);
1113 
1114   gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
1115   xsane_progress_bar_set_fraction(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
1116 
1117   if (v->undo_filename)
1118   {
1119     DBG(DBG_info, "removing file %s\n", v->undo_filename);
1120     remove(v->undo_filename);
1121     free(v->undo_filename);
1122   }
1123 
1124   v->undo_filename = v->filename;
1125   DBG(DBG_info, "undo file is %s\n", v->undo_filename);
1126   gtk_widget_set_sensitive(GTK_WIDGET(v->undo), TRUE);
1127   gtk_widget_set_sensitive(GTK_WIDGET(v->undo_menu_item), TRUE);
1128 
1129   v->filename = strdup(outfilename);
1130   v->image_saved = FALSE;
1131 
1132   xsane_viewer_read_image(v);
1133 
1134   if (v->last_saved_filename)
1135   {
1136    char buf[TEXTBUFSIZE];
1137     snprintf(buf, sizeof(buf), "%s (%s) - %s", WINDOW_VIEWER, v->last_saved_filename, xsane.device_text);
1138     gtk_window_set_title(GTK_WINDOW(v->top), buf);
1139   }
1140 
1141   xsane_viewer_set_sensitivity(v, TRUE);
1142 }
1143 
1144 /* ---------------------------------------------------------------------------------------------------------------------- */
1145 
xsane_viewer_despeckle_image(GtkWidget * window,gpointer data)1146 static void xsane_viewer_despeckle_image(GtkWidget *window, gpointer data)
1147 {
1148  FILE *outfile;
1149  FILE *infile;
1150  char outfilename[PATH_MAX];
1151  Viewer *v = (Viewer *) data;
1152  Image_info image_info;
1153 
1154   DBG(DBG_proc, "xsane_viewer_despeckle_image\n");
1155 
1156   gtk_widget_destroy(v->active_dialog);
1157 
1158   xsane_viewer_set_sensitivity(v, FALSE);
1159 
1160   infile = fopen(v->filename, "rb");
1161   if (!infile)
1162   {
1163     DBG(DBG_error, "could not load file %s\n", v->filename);
1164     xsane_viewer_set_sensitivity(v, TRUE);
1165    return;
1166   }
1167 
1168   xsane_read_pnm_header(infile, &image_info);
1169 
1170   DBG(DBG_info, "despeckling image %s with geometry: %d x %d x %d, %d channels\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels);
1171 
1172   xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
1173 
1174   outfile = fopen(outfilename, "wb");
1175   if (!outfile)
1176   {
1177     DBG(DBG_error, "could not save file %s\n", outfilename);
1178     xsane_viewer_set_sensitivity(v, TRUE);
1179    return;
1180   }
1181 
1182   gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_DESPECKLING_DATA);
1183 
1184   xsane_progress_bar_set_fraction(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
1185 
1186   xsane_save_despeckle_image(outfile, infile, &image_info, v->despeckle_radius, v->progress_bar, &v->cancel_save);
1187 
1188   fclose(infile);
1189   fclose(outfile);
1190 
1191   gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
1192   xsane_progress_bar_set_fraction(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
1193 
1194   if (v->undo_filename)
1195   {
1196     DBG(DBG_info, "removing file %s\n", v->undo_filename);
1197     remove(v->undo_filename);
1198     free(v->undo_filename);
1199   }
1200 
1201   v->undo_filename = v->filename;
1202   DBG(DBG_info, "undo file is %s\n", v->undo_filename);
1203   gtk_widget_set_sensitive(GTK_WIDGET(v->undo), TRUE);
1204   gtk_widget_set_sensitive(GTK_WIDGET(v->undo_menu_item), TRUE);
1205 
1206   v->filename = strdup(outfilename);
1207   v->image_saved = FALSE;
1208 
1209   xsane_viewer_read_image(v);
1210 
1211   if (v->last_saved_filename)
1212   {
1213    char buf[TEXTBUFSIZE];
1214     snprintf(buf, sizeof(buf), "%s (%s) - %s", WINDOW_VIEWER, v->last_saved_filename, xsane.device_text);
1215     gtk_window_set_title(GTK_WINDOW(v->top), buf);
1216   }
1217 
1218   xsane_viewer_set_sensitivity(v, TRUE);
1219 }
1220 
1221 /* ---------------------------------------------------------------------------------------------------------------------- */
1222 
xsane_viewer_blur_image(GtkWidget * window,gpointer data)1223 static void xsane_viewer_blur_image(GtkWidget *window, gpointer data)
1224 {
1225  FILE *outfile;
1226  FILE *infile;
1227  char outfilename[PATH_MAX];
1228  Viewer *v = (Viewer *) data;
1229  Image_info image_info;
1230 
1231   DBG(DBG_proc, "xsane_viewer_blur_image\n");
1232 
1233   gtk_widget_destroy(v->active_dialog);
1234 
1235   xsane_viewer_set_sensitivity(v, FALSE);
1236 
1237   infile = fopen(v->filename, "rb");
1238   if (!infile)
1239   {
1240     DBG(DBG_error, "could not load file %s\n", v->filename);
1241     xsane_viewer_set_sensitivity(v, TRUE);
1242    return;
1243   }
1244 
1245   xsane_read_pnm_header(infile, &image_info);
1246 
1247   DBG(DBG_info, "bluring image %s with geometry: %d x %d x %d, %d channels\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels);
1248 
1249   xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
1250 
1251   outfile = fopen(outfilename, "wb");
1252   if (!outfile)
1253   {
1254     DBG(DBG_error, "could not save file %s\n", outfilename);
1255     xsane_viewer_set_sensitivity(v, TRUE);
1256    return;
1257   }
1258 
1259   gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_BLURING_DATA);
1260 
1261   xsane_progress_bar_set_fraction(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
1262 
1263   xsane_save_blur_image(outfile, infile, &image_info, v->blur_radius, v->progress_bar, &v->cancel_save);
1264 
1265   fclose(infile);
1266   fclose(outfile);
1267 
1268   gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
1269   xsane_progress_bar_set_fraction(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
1270 
1271   if (v->undo_filename)
1272   {
1273     DBG(DBG_info, "removing file %s\n", v->undo_filename);
1274     remove(v->undo_filename);
1275     free(v->undo_filename);
1276   }
1277 
1278   v->undo_filename = v->filename;
1279   DBG(DBG_info, "undo file is %s\n", v->undo_filename);
1280   gtk_widget_set_sensitive(GTK_WIDGET(v->undo), TRUE);
1281   gtk_widget_set_sensitive(GTK_WIDGET(v->undo_menu_item), TRUE);
1282 
1283   v->filename = strdup(outfilename);
1284   v->image_saved = FALSE;
1285 
1286   xsane_viewer_read_image(v);
1287 
1288   if (v->last_saved_filename)
1289   {
1290    char buf[TEXTBUFSIZE];
1291     snprintf(buf, sizeof(buf), "%s (%s) - %s", WINDOW_VIEWER, v->last_saved_filename, xsane.device_text);
1292     gtk_window_set_title(GTK_WINDOW(v->top), buf);
1293   }
1294 
1295   xsane_viewer_set_sensitivity(v, TRUE);
1296 }
1297 
1298 /* ---------------------------------------------------------------------------------------------------------------------- */
1299 
xsane_viewer_rotate(Viewer * v,int rotation)1300 static void xsane_viewer_rotate(Viewer *v, int rotation)
1301 {
1302  FILE *outfile;
1303  FILE *infile;
1304  char outfilename[PATH_MAX];
1305  Image_info image_info;
1306 
1307   if (v->block_actions) /* actions blocked: return */
1308   {
1309     gdk_beep();
1310     DBG(DBG_info, "xsane_viewer_rotate: actions are blocked\n");
1311    return;
1312   }
1313 
1314   DBG(DBG_proc, "xsane_viewer_rotate(%d)\n", rotation);
1315 
1316   xsane_viewer_set_sensitivity(v, FALSE);
1317 
1318   infile = fopen(v->filename, "rb");
1319   if (!infile)
1320   {
1321     DBG(DBG_error, "could not load file %s\n", v->filename);
1322     xsane_viewer_set_sensitivity(v, TRUE);
1323 
1324    return;
1325   }
1326 
1327   xsane_read_pnm_header(infile, &image_info);
1328 
1329   DBG(DBG_info, "rotating image %s with geometry: %d x %d x %d, %d channels\n", v->filename, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels);
1330 
1331   xsane_back_gtk_make_path(sizeof(outfilename), outfilename, 0, 0, "xsane-viewer-", xsane.dev_name, ".ppm", XSANE_PATH_TMP);
1332 
1333   outfile = fopen(outfilename, "wb");
1334   if (!outfile)
1335   {
1336     DBG(DBG_error, "could not save file %s\n", outfilename);
1337     xsane_viewer_set_sensitivity(v, TRUE);
1338 
1339    return;
1340   }
1341 
1342   if (rotation <4)
1343   {
1344     gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_ROTATING_DATA);
1345   }
1346   else
1347   {
1348     gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), PROGRESS_MIRRORING_DATA);
1349   }
1350 
1351   xsane_progress_bar_set_fraction(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
1352 
1353   xsane_save_rotate_image(outfile, infile, &image_info, rotation, v->progress_bar, &v->cancel_save);
1354 
1355   fclose(infile);
1356   fclose(outfile);
1357 
1358   gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
1359   xsane_progress_bar_set_fraction(GTK_PROGRESS_BAR(v->progress_bar), 0.0);
1360 
1361   if (v->undo_filename)
1362   {
1363     DBG(DBG_info, "removing file %s\n", v->undo_filename);
1364     remove(v->undo_filename);
1365     free(v->undo_filename);
1366   }
1367 
1368   v->undo_filename = v->filename;
1369   DBG(DBG_info, "undo file is %s\n", v->undo_filename);
1370   gtk_widget_set_sensitive(GTK_WIDGET(v->undo), TRUE);
1371   gtk_widget_set_sensitive(GTK_WIDGET(v->undo_menu_item), TRUE);
1372 
1373   v->filename = strdup(outfilename);
1374   v->image_saved = FALSE;
1375 
1376   xsane_viewer_read_image(v);
1377 
1378   if (v->last_saved_filename)
1379   {
1380    char buf[TEXTBUFSIZE];
1381     snprintf(buf, sizeof(buf), "%s (%s) - %s", WINDOW_VIEWER, v->last_saved_filename, xsane.device_text);
1382     gtk_window_set_title(GTK_WINDOW(v->top), buf);
1383   }
1384 
1385   xsane_viewer_set_sensitivity(v, TRUE);
1386 }
1387 
1388 /* ---------------------------------------------------------------------------------------------------------------------- */
1389 
xsane_viewer_rotate90_callback(GtkWidget * window,gpointer data)1390 static void xsane_viewer_rotate90_callback(GtkWidget *window, gpointer data)
1391 {
1392  Viewer *v = (Viewer *) data;
1393 
1394   DBG(DBG_proc, "xsane_viewer_rotate90_callback\n");
1395   xsane_viewer_rotate(v, 1);
1396 }
1397 
1398 /* ---------------------------------------------------------------------------------------------------------------------- */
1399 
xsane_viewer_rotate180_callback(GtkWidget * window,gpointer data)1400 static void xsane_viewer_rotate180_callback(GtkWidget *window, gpointer data)
1401 {
1402  Viewer *v = (Viewer *) data;
1403 
1404   DBG(DBG_proc, "xsane_viewer_rotate180_callback\n");
1405   xsane_viewer_rotate(v, 2);
1406 }
1407 
1408 /* ---------------------------------------------------------------------------------------------------------------------- */
1409 
xsane_viewer_rotate270_callback(GtkWidget * window,gpointer data)1410 static void xsane_viewer_rotate270_callback(GtkWidget *window, gpointer data)
1411 {
1412  Viewer *v = (Viewer *) data;
1413 
1414   DBG(DBG_proc, "xsane_viewer_rotate270_callback\n");
1415   xsane_viewer_rotate(v, 3);
1416 }
1417 
1418 /* ---------------------------------------------------------------------------------------------------------------------- */
1419 
xsane_viewer_mirror_x_callback(GtkWidget * window,gpointer data)1420 static void xsane_viewer_mirror_x_callback(GtkWidget *window, gpointer data)
1421 {
1422  Viewer *v = (Viewer *) data;
1423 
1424   DBG(DBG_proc, "xsane_viewer_mirror_x_callback\n");
1425   xsane_viewer_rotate(v, 4);
1426 }
1427 
1428 /* ---------------------------------------------------------------------------------------------------------------------- */
1429 
xsane_viewer_mirror_y_callback(GtkWidget * window,gpointer data)1430 static void xsane_viewer_mirror_y_callback(GtkWidget *window, gpointer data)
1431 {
1432  Viewer *v = (Viewer *) data;
1433 
1434   DBG(DBG_proc, "xsane_viewer_mirror_y_callback\n");
1435   xsane_viewer_rotate(v, 6);
1436 }
1437 
1438 /* ---------------------------------------------------------------------------------------------------------------------- */
1439 
xsane_viewer_zoom_callback(GtkWidget * widget,gpointer data)1440 static void xsane_viewer_zoom_callback(GtkWidget *widget, gpointer data)
1441 {
1442  Viewer *v = (Viewer *) data;
1443  int val;
1444 
1445   DBG(DBG_proc, "xsane_viewer_zoom_callback\n");
1446 
1447   val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection");
1448   v->zoom = (float) val / 100;
1449   DBG(DBG_info, "setting zoom factor to %f\n", v->zoom);
1450   xsane_viewer_read_image(v);
1451 }
1452 
1453 /* ---------------------------------------------------------------------------------------------------------------------- */
1454 
xsane_viewer_file_build_menu(Viewer * v)1455 static GtkWidget *xsane_viewer_file_build_menu(Viewer *v)
1456 {
1457  GtkWidget *menu, *item;
1458 
1459   DBG(DBG_proc, "xsane_viewer_file_build_menu\n");
1460 
1461   menu = gtk_menu_new();
1462   gtk_menu_set_accel_group(GTK_MENU(menu), xsane.accelerator_group);
1463 
1464   /* XSane save dialog */
1465 
1466   item = gtk_menu_item_new_with_label(MENU_ITEM_SAVE_IMAGE);
1467 #if 0
1468   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1469 #endif
1470   gtk_menu_append(GTK_MENU(menu), item);
1471   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_save_callback, v);
1472   gtk_widget_show(item);
1473   v->save_menu_item = item;
1474 
1475   /* XSane save as text (ocr) */
1476 
1477   item = gtk_menu_item_new_with_label(MENU_ITEM_OCR);
1478 #if 0
1479   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1480 #endif
1481   gtk_menu_append(GTK_MENU(menu), item);
1482   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_ocr_callback, v);
1483   gtk_widget_show(item);
1484   v->ocr_menu_item = item;
1485 
1486   /* Clone */
1487 
1488   item = gtk_menu_item_new_with_label(MENU_ITEM_CLONE);
1489 #if 0
1490   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1491 #endif
1492   gtk_menu_append(GTK_MENU(menu), item);
1493   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_clone_callback, v);
1494   gtk_widget_show(item);
1495   v->clone_menu_item = item;
1496 
1497 
1498   /* Close */
1499 
1500   item = gtk_menu_item_new_with_label(MENU_ITEM_CLOSE);
1501 #if 0
1502   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_Q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1503 #endif
1504   gtk_container_add(GTK_CONTAINER(menu), item);
1505   gtk_object_set_data(GTK_OBJECT(item), "Viewer", (void *) v);
1506   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_close_callback, v);
1507   gtk_widget_show(item);
1508 
1509   return menu;
1510 }
1511 
1512 /* ---------------------------------------------------------------------------------------------------------------------- */
1513 
xsane_viewer_edit_build_menu(Viewer * v)1514 static GtkWidget *xsane_viewer_edit_build_menu(Viewer *v)
1515 {
1516  GtkWidget *menu, *item;
1517 
1518   DBG(DBG_proc, "xsane_viewer_edit_build_menu\n");
1519 
1520   menu = gtk_menu_new();
1521   gtk_menu_set_accel_group(GTK_MENU(menu), xsane.accelerator_group);
1522 
1523   /* undo  */
1524 
1525   item = gtk_menu_item_new_with_label(MENU_ITEM_UNDO);
1526 #if 0
1527   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1528 #endif
1529   gtk_menu_append(GTK_MENU(menu), item);
1530   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_undo_callback, v);
1531   gtk_widget_show(item);
1532   v->undo_menu_item = item;
1533 
1534  return menu;
1535 }
1536 
1537 /* ---------------------------------------------------------------------------------------------------------------------- */
1538 
xsane_viewer_filters_build_menu(Viewer * v)1539 static GtkWidget *xsane_viewer_filters_build_menu(Viewer *v)
1540 {
1541  GtkWidget *menu, *item;
1542 
1543   DBG(DBG_proc, "xsane_viewer_filters_build_menu\n");
1544 
1545   menu = gtk_menu_new();
1546   gtk_menu_set_accel_group(GTK_MENU(menu), xsane.accelerator_group);
1547 
1548   /* Despeckle */
1549 
1550   item = gtk_menu_item_new_with_label(MENU_ITEM_DESPECKLE);
1551 #if 0
1552   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1553 #endif
1554   gtk_menu_append(GTK_MENU(menu), item);
1555   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_despeckle_callback, v);
1556   gtk_widget_show(item);
1557   v->despeckle_menu_item = item;
1558 
1559 
1560   /* Blur */
1561 
1562   item = gtk_menu_item_new_with_label(MENU_ITEM_BLUR);
1563 #if 0
1564   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_Q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1565 #endif
1566   gtk_container_add(GTK_CONTAINER(menu), item);
1567   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_blur_callback, v);
1568   gtk_widget_show(item);
1569   v->blur_menu_item = item;
1570 
1571  return menu;
1572 }
1573 
1574 /* ---------------------------------------------------------------------------------------------------------------------- */
1575 
xsane_viewer_geometry_build_menu(Viewer * v)1576 static GtkWidget *xsane_viewer_geometry_build_menu(Viewer *v)
1577 {
1578  GtkWidget *menu, *item;
1579 
1580   DBG(DBG_proc, "xsane_viewer_geometry_build_menu\n");
1581 
1582   menu = gtk_menu_new();
1583   gtk_menu_set_accel_group(GTK_MENU(menu), xsane.accelerator_group);
1584 
1585 
1586   /* Scale */
1587 
1588   item = gtk_menu_item_new_with_label(MENU_ITEM_SCALE);
1589 #if 0
1590   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_I, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1591 #endif
1592   gtk_menu_append(GTK_MENU(menu), item);
1593   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_scale_callback, v);
1594   gtk_widget_show(item);
1595 
1596 
1597   /* insert separator: */
1598 
1599   item = gtk_menu_item_new();
1600   gtk_menu_append(GTK_MENU(menu), item);
1601   gtk_widget_show(item);
1602 
1603 
1604   /* rotate90 */
1605 
1606   item = gtk_menu_item_new_with_label(MENU_ITEM_ROTATE90);
1607 #if 0
1608   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_1, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1609 #endif
1610   gtk_menu_append(GTK_MENU(menu), item);
1611   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_rotate90_callback, v);
1612   gtk_widget_show(item);
1613 
1614 
1615   /* rotate180 */
1616 
1617   item = gtk_menu_item_new_with_label(MENU_ITEM_ROTATE180);
1618 #if 0
1619   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_2, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1620 #endif
1621   gtk_container_add(GTK_CONTAINER(menu), item);
1622   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_rotate180_callback, v);
1623   gtk_widget_show(item);
1624 
1625 
1626   /* rotate270 */
1627 
1628   item = gtk_menu_item_new_with_label(MENU_ITEM_ROTATE270);
1629 #if 0
1630   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_3, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1631 #endif
1632   gtk_container_add(GTK_CONTAINER(menu), item);
1633   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_rotate270_callback, v);
1634   gtk_widget_show(item);
1635 
1636 
1637   /* insert separator: */
1638 
1639   item = gtk_menu_item_new();
1640   gtk_menu_append(GTK_MENU(menu), item);
1641   gtk_widget_show(item);
1642 
1643 
1644   /* mirror_x */
1645 
1646   item = gtk_menu_item_new_with_label(MENU_ITEM_MIRROR_X);
1647 #if 0
1648   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_X, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1649 #endif
1650   gtk_container_add(GTK_CONTAINER(menu), item);
1651   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_mirror_x_callback, v);
1652   gtk_widget_show(item);
1653 
1654 
1655   /* mirror_y */
1656 
1657   item = gtk_menu_item_new_with_label(MENU_ITEM_MIRROR_Y);
1658 #if 0
1659   gtk_widget_add_accelerator(item, "activate", xsane.accelerator_group, GDK_Y, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED);
1660 #endif
1661   gtk_container_add(GTK_CONTAINER(menu), item);
1662   g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_viewer_mirror_y_callback, v);
1663   gtk_widget_show(item);
1664 
1665 
1666  return menu;
1667 }
1668 
1669 /* ---------------------------------------------------------------------------------------------------------------------- */
1670 
1671 #ifdef HAVE_LIBLCMS
1672 #define INTENT_PERCEPTUAL                 0
1673 #define INTENT_RELATIVE_COLORIMETRIC      1
1674 #define INTENT_SATURATION                 2
1675 #define INTENT_ABSOLUTE_COLORIMETRIC      3
1676 
1677 /* ---------------------------------------------------------------------------------------------------------------------- */
1678 
xsane_viewer_set_cms_enable_callback(GtkWidget * widget,gpointer data)1679 static void xsane_viewer_set_cms_enable_callback(GtkWidget *widget, gpointer data)
1680 {
1681  Viewer *v = (Viewer *) data;
1682 
1683   v->cms_enable = (GTK_CHECK_MENU_ITEM(widget)->active != 0);
1684   DBG(DBG_proc, "xsane_viewer_set_cms_enable_callback (%d)\n", v->cms_enable);
1685 
1686   xsane_viewer_read_image(v);
1687 }
1688 
1689 /* ---------------------------------------------------------------------------------------------------------------------- */
1690 
xsane_viewer_set_cms_black_point_compensation_callback(GtkWidget * widget,gpointer data)1691 static void xsane_viewer_set_cms_black_point_compensation_callback(GtkWidget *widget, gpointer data)
1692 {
1693  Viewer *v = (Viewer *) data;
1694 
1695   v->cms_bpc = (GTK_CHECK_MENU_ITEM(widget)->active != 0);
1696   DBG(DBG_proc, "xsane_viewer_set_cms_black_point_compensation_callback (%d)\n", v->cms_bpc);
1697 
1698   xsane_viewer_read_image(v);
1699 }
1700 
1701 /* ---------------------------------------------------------------------------------------------------------------------- */
1702 
xsane_viewer_set_cms_gamut_check_callback(GtkWidget * widget,gpointer data)1703 static void xsane_viewer_set_cms_gamut_check_callback(GtkWidget *widget, gpointer data)
1704 {
1705  Viewer *v = (Viewer *) data;
1706 
1707   v->cms_gamut_check = (GTK_CHECK_MENU_ITEM(widget)->active != 0);
1708   DBG(DBG_proc, "xsane_viewer_set_cms_gamut_check_callback (%d)\n", v->cms_gamut_check);
1709 
1710   xsane_viewer_read_image(v);
1711 }
1712 
1713 /* ---------------------------------------------------------------------------------------------------------------------- */
1714 
xsane_viewer_set_cms_proofing_callback(GtkWidget * widget,gpointer data)1715 static void xsane_viewer_set_cms_proofing_callback(GtkWidget *widget, gpointer data)
1716 {
1717  Viewer *v = (Viewer *) data;
1718  int val;
1719 
1720   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v);
1721   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v);
1722   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v);
1723 
1724   val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection");
1725 
1726   DBG(DBG_proc, "xsane_viewer_set_cms_proofing_callback (%d)\n", val);
1727 
1728   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_proofing_widget[v->cms_proofing]), FALSE);
1729   v->cms_proofing = val;
1730   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_proofing_widget[v->cms_proofing]), TRUE);
1731 
1732   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v);
1733   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v);
1734   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v);
1735 
1736   xsane_viewer_read_image(v);
1737 }
1738 
1739 /* ---------------------------------------------------------------------------------------------------------------------- */
1740 
xsane_viewer_set_cms_intent_callback(GtkWidget * widget,gpointer data)1741 static void xsane_viewer_set_cms_intent_callback(GtkWidget *widget, gpointer data)
1742 {
1743  Viewer *v = (Viewer *) data;
1744  int val;
1745 
1746   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_intent_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1747   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_intent_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1748   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_intent_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1749   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_intent_widget[3]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1750 
1751   val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection");
1752 
1753   DBG(DBG_proc, "xsane_viewer_set_cms_intent_callback (%d)\n", val);
1754 
1755   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_intent_widget[v->cms_intent]), FALSE);
1756   v->cms_intent = val;
1757   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_intent_widget[v->cms_intent]), TRUE);
1758 
1759   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_intent_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1760   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_intent_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1761   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_intent_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1762   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_intent_widget[3]), (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1763 
1764   xsane_viewer_read_image(v);
1765 }
1766 
1767 /* ---------------------------------------------------------------------------------------------------------------------- */
1768 
xsane_viewer_set_cms_proofing_intent_callback(GtkWidget * widget,gpointer data)1769 static void xsane_viewer_set_cms_proofing_intent_callback(GtkWidget *widget, gpointer data)
1770 {
1771  Viewer *v = (Viewer *) data;
1772  int val;
1773 
1774   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_intent_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v);
1775   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_proofing_intent_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v);
1776 
1777   val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection");
1778 
1779   DBG(DBG_proc, "xsane_viewer_set_cms_proofing_intent_callback (%d)\n", val);
1780 
1781   /* we have cms_proofing_intent = 1 and 3 and widget[0] and widget[1] => widget[(cms_proofing_intent-1)/2] */
1782   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_proofing_intent_widget[(v->cms_proofing_intent-1)/2]), FALSE);
1783   v->cms_proofing_intent = val;
1784   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_proofing_intent_widget[(v->cms_proofing_intent-1)/2]), TRUE);
1785 
1786   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_intent_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v);
1787   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_proofing_intent_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v);
1788 
1789   xsane_viewer_read_image(v);
1790 }
1791 
1792 /* ---------------------------------------------------------------------------------------------------------------------- */
1793 
xsane_viewer_set_cms_gamut_alarm_color_callback(GtkWidget * widget,gpointer data)1794 static void xsane_viewer_set_cms_gamut_alarm_color_callback(GtkWidget *widget, gpointer data)
1795 {
1796  Viewer *v = (Viewer *) data;
1797  int val;
1798 
1799   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1800   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1801   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1802   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[3]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1803   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[4]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1804   g_signal_handlers_block_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[5]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1805 
1806   val = (int) gtk_object_get_data(GTK_OBJECT(widget), "Selection");
1807 
1808   DBG(DBG_proc, "xsane_viewer_set_cms_gamut_alarm_color_callback (%d)\n", val);
1809 
1810   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_gamut_alarm_color_widget[v->cms_gamut_alarm_color]), FALSE);
1811   v->cms_gamut_alarm_color = val;
1812   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(v->cms_gamut_alarm_color_widget[v->cms_gamut_alarm_color]), TRUE);
1813 
1814   switch(v->cms_gamut_alarm_color)
1815   {
1816     default:
1817     case 0: /* black */
1818       cmsSetAlarmCodes(0, 0, 0);
1819      break;
1820 
1821     case 1: /* gray */
1822       cmsSetAlarmCodes(128, 128, 128);
1823      break;
1824 
1825     case 2: /* white */
1826       cmsSetAlarmCodes(255, 255, 255);
1827      break;
1828 
1829     case 3: /* red */
1830       cmsSetAlarmCodes(255, 0, 0);
1831      break;
1832 
1833     case 4: /* green */
1834       cmsSetAlarmCodes(0, 255, 0);
1835      break;
1836 
1837     case 5: /* blue */
1838       cmsSetAlarmCodes(0, 0, 255);
1839      break;
1840   }
1841 
1842   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[0]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1843   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[1]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1844   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[2]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1845   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[3]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1846   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[4]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1847   g_signal_handlers_unblock_by_func(GTK_OBJECT(v->cms_gamut_alarm_color_widget[5]), (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
1848 
1849   if (v->cms_gamut_check)
1850   {
1851     xsane_viewer_read_image(v);
1852   }
1853 }
1854 
1855 /* ---------------------------------------------------------------------------------------------------------------------- */
1856 
xsane_viewer_color_management_build_menu(Viewer * v)1857 static GtkWidget *xsane_viewer_color_management_build_menu(Viewer *v)
1858 {
1859  GtkWidget *menu, *item, *submenu, *subitem;
1860 
1861   DBG(DBG_proc, "xsane_viewer_color_management_build_menu\n");
1862 
1863   menu = gtk_menu_new();
1864   gtk_menu_set_accel_group(GTK_MENU(menu), xsane.accelerator_group);
1865 
1866   /* cms enable */
1867   item = gtk_check_menu_item_new_with_label(MENU_ITEM_CMS_ENABLE_COLOR_MANAGEMENT);
1868   gtk_menu_append(GTK_MENU(menu), item);
1869   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), v->cms_enable);
1870   g_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_enable_callback, v);
1871   gtk_widget_show(item);
1872 
1873   /* black point compensation */
1874   item = gtk_check_menu_item_new_with_label(MENU_ITEM_CMS_BLACK_POINT_COMPENSATION);
1875   gtk_menu_append(GTK_MENU(menu), item);
1876   if (v->cms_bpc)
1877   {
1878     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1879   }
1880   g_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_black_point_compensation_callback, v);
1881   gtk_widget_show(item);
1882 
1883 
1884   /* Output Device submenu */
1885   item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_PROOFING);
1886   gtk_menu_append(GTK_MENU(menu), item);
1887   gtk_widget_show(item);
1888 
1889   submenu = gtk_menu_new();
1890 
1891   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_PROOF_OFF);
1892   gtk_menu_append(GTK_MENU(submenu), subitem);
1893   if (v->cms_proofing == 0)
1894   {
1895     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
1896   }
1897   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v);
1898   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 0);
1899   gtk_widget_show(subitem);
1900   v->cms_proofing_widget[0] = subitem;
1901 
1902   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_PROOF_PRINTER);
1903   gtk_menu_append(GTK_MENU(submenu), subitem);
1904   if (v->cms_proofing == 1)
1905   {
1906     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
1907   }
1908   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v);
1909   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 1);
1910   gtk_widget_show(subitem);
1911   v->cms_proofing_widget[1] = subitem;
1912 
1913   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_PROOF_CUSTOM);
1914   gtk_menu_append(GTK_MENU(submenu), subitem);
1915   if (v->cms_proofing == 2)
1916   {
1917     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
1918   }
1919   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_callback, v);
1920   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 2);
1921   gtk_widget_show(subitem);
1922   v->cms_proofing_widget[2] = subitem;
1923 
1924   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
1925 
1926 
1927   /* Intent submenu */
1928   item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_RENDERING_INTENT);
1929   gtk_menu_append(GTK_MENU(menu), item);
1930   gtk_widget_show(item);
1931 
1932   submenu = gtk_menu_new();
1933 
1934   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_PERCEPTUAL);
1935   gtk_menu_append(GTK_MENU(submenu), subitem);
1936   if (v->cms_intent == INTENT_PERCEPTUAL)
1937   {
1938     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
1939   }
1940   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1941   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_PERCEPTUAL);
1942   gtk_widget_show(subitem);
1943   v->cms_intent_widget[INTENT_PERCEPTUAL] = subitem;
1944 
1945   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_RELATIVE_COLORIMETRIC);
1946   gtk_menu_append(GTK_MENU(submenu), subitem);
1947   if (v->cms_intent == INTENT_RELATIVE_COLORIMETRIC)
1948   {
1949     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
1950   }
1951   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1952   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_RELATIVE_COLORIMETRIC);
1953   gtk_widget_show(subitem);
1954   v->cms_intent_widget[INTENT_RELATIVE_COLORIMETRIC] = subitem;
1955 
1956   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_ABSOLUTE_COLORIMETRIC);
1957   gtk_menu_append(GTK_MENU(submenu), subitem);
1958   if (v->cms_intent == INTENT_ABSOLUTE_COLORIMETRIC)
1959   {
1960     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
1961   }
1962   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1963   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_ABSOLUTE_COLORIMETRIC);
1964   gtk_widget_show(subitem);
1965   v->cms_intent_widget[INTENT_ABSOLUTE_COLORIMETRIC] = subitem;
1966 
1967   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_SATURATION);
1968   gtk_menu_append(GTK_MENU(submenu), subitem);
1969   if (v->cms_intent == INTENT_SATURATION)
1970   {
1971     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
1972   }
1973   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_intent_callback, v);
1974   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_SATURATION);
1975   gtk_widget_show(subitem);
1976   v->cms_intent_widget[INTENT_SATURATION] = subitem;
1977 
1978   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
1979 
1980 
1981   /* proofing_intent submenu */
1982   item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_PROOFING_INTENT);
1983   gtk_menu_append(GTK_MENU(menu), item);
1984   gtk_widget_show(item);
1985 
1986   submenu = gtk_menu_new();
1987 
1988   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_RELATIVE_COLORIMETRIC);
1989   gtk_menu_append(GTK_MENU(submenu), subitem);
1990   if (v->cms_proofing_intent == INTENT_RELATIVE_COLORIMETRIC)
1991   {
1992     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
1993   }
1994   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v);
1995   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_RELATIVE_COLORIMETRIC);
1996   gtk_widget_show(subitem);
1997   v->cms_proofing_intent_widget[0] = subitem;
1998 
1999   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_INTENT_ABSOLUTE_COLORIMETRIC);
2000   gtk_menu_append(GTK_MENU(submenu), subitem);
2001   if (v->cms_proofing_intent == INTENT_ABSOLUTE_COLORIMETRIC)
2002   {
2003     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
2004   }
2005   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_proofing_intent_callback, v);
2006   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) INTENT_ABSOLUTE_COLORIMETRIC);
2007   gtk_widget_show(subitem);
2008   v->cms_proofing_intent_widget[1] = subitem;
2009 
2010   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
2011 
2012 
2013   /* cms gamut check */
2014   item = gtk_check_menu_item_new_with_label(MENU_ITEM_CMS_GAMUT_CHECK);
2015   gtk_menu_append(GTK_MENU(menu), item);
2016   g_signal_connect(GTK_OBJECT(item), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_check_callback, v);
2017   gtk_widget_show(item);
2018 
2019 
2020   /* gamut alarm color */
2021   item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_GAMUT_ALARM_COLOR);
2022   gtk_menu_append(GTK_MENU(menu), item);
2023   gtk_widget_show(item);
2024 
2025   submenu = gtk_menu_new();
2026 
2027   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_BLACK);
2028   gtk_menu_append(GTK_MENU(submenu), subitem);
2029   if (v->cms_gamut_alarm_color == 0)
2030   {
2031     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
2032   }
2033   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
2034   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 0);
2035   gtk_widget_show(subitem);
2036   v->cms_gamut_alarm_color_widget[0] = subitem;
2037 
2038   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_GRAY);
2039   gtk_menu_append(GTK_MENU(submenu), subitem);
2040   if (v->cms_gamut_alarm_color == 1)
2041   {
2042     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
2043   }
2044   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
2045   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 1);
2046   gtk_widget_show(subitem);
2047   v->cms_gamut_alarm_color_widget[1] = subitem;
2048 
2049   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_WHITE);
2050   gtk_menu_append(GTK_MENU(submenu), subitem);
2051   if (v->cms_gamut_alarm_color == 2)
2052   {
2053     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
2054   }
2055   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
2056   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 2);
2057   gtk_widget_show(subitem);
2058   v->cms_gamut_alarm_color_widget[2] = subitem;
2059 
2060   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_RED);
2061   gtk_menu_append(GTK_MENU(submenu), subitem);
2062   if (v->cms_gamut_alarm_color == 3)
2063   {
2064     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
2065   }
2066   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
2067   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 3);
2068   gtk_widget_show(subitem);
2069   v->cms_gamut_alarm_color_widget[3] = subitem;
2070 
2071   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_GREEN);
2072   gtk_menu_append(GTK_MENU(submenu), subitem);
2073   if (v->cms_gamut_alarm_color == 4)
2074   {
2075     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
2076   }
2077   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
2078   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 4);
2079   gtk_widget_show(subitem);
2080   v->cms_gamut_alarm_color_widget[4] = subitem;
2081 
2082   subitem = gtk_check_menu_item_new_with_label(SUBMENU_ITEM_CMS_COLOR_BLUE);
2083   gtk_menu_append(GTK_MENU(submenu), subitem);
2084   if (v->cms_gamut_alarm_color == 5)
2085   {
2086     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem), TRUE);
2087   }
2088   g_signal_connect(GTK_OBJECT(subitem), "toggled", (GtkSignalFunc) xsane_viewer_set_cms_gamut_alarm_color_callback, v);
2089   gtk_object_set_data(GTK_OBJECT(subitem), "Selection", (void *) 5);
2090   gtk_widget_show(subitem);
2091   v->cms_gamut_alarm_color_widget[5] = subitem;
2092 
2093   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
2094 
2095  return menu;
2096 }
2097 #endif
2098 
2099 /* ---------------------------------------------------------------------------------------------------------------------- */
2100 
2101 
xsane_viewer_read_image_header(Viewer * v)2102 static int xsane_viewer_read_image_header(Viewer *v)
2103 {
2104  int pos0;
2105  FILE *infile;
2106  Image_info image_info;
2107 
2108   /* open imagefile */
2109 
2110   infile = fopen(v->filename, "rb");
2111   if (!infile)
2112   {
2113     DBG(DBG_error, "could not load file %s\n", v->filename);
2114    return -1;
2115   }
2116 
2117   xsane_read_pnm_header(infile, &image_info);
2118 
2119   pos0 = ftell(infile);
2120 
2121   if (!image_info.channels) /* == 0 (grayscale) ? */
2122   {
2123     image_info.channels = 1; /* we have one color component */
2124   }
2125 
2126   DBG(DBG_info, "reading image header %s with  geometry: %d x %d x %d, %d channels\n", v->filename,
2127                  image_info.image_width, image_info.image_height, image_info.depth, image_info.channels);
2128 
2129   /* init color management */
2130   v->enable_color_management = image_info.enable_color_management;
2131   if (!image_info.enable_color_management)
2132   {
2133     v->cms_enable = FALSE;
2134   }
2135 
2136   v->cms_function = image_info.cms_function;
2137   v->cms_intent   = image_info.cms_intent;
2138   v->cms_bpc      = image_info.cms_bpc;
2139 
2140   if ((v->enable_color_management) && (image_info.reduce_to_lineart))
2141   {
2142     v->enable_color_management = FALSE;
2143     v->cms_enable = FALSE;
2144   }
2145 
2146   fclose(infile);
2147 
2148  return 0;
2149 }
2150 
2151 /* ---------------------------------------------------------------------------------------------------------------------- */
2152 
2153 
xsane_viewer_read_image(Viewer * v)2154 static int xsane_viewer_read_image(Viewer *v)
2155 {
2156  unsigned char *cms_row, *row, *src_row;
2157  int x, y;
2158  int last_y;
2159  int nread;
2160  int pos0;
2161  FILE *infile;
2162  Image_info image_info;
2163  char buf[TEXTBUFSIZE];
2164  float size;
2165  char *size_unit;
2166  int width, height;
2167 
2168 #ifdef HAVE_LIBLCMS
2169  cmsHPROFILE hInProfile = NULL;
2170  cmsHPROFILE hOutProfile = NULL;
2171  cmsHPROFILE hProofProfile = NULL;
2172  cmsHTRANSFORM hTransform = NULL;
2173  int proof = 0;
2174  char *cms_proof_icm_profile = NULL;
2175  DWORD cms_input_format;
2176  DWORD cms_output_format;
2177  DWORD cms_flags = 0;
2178 #endif
2179 
2180   /* open imagefile */
2181 
2182   infile = fopen(v->filename, "rb");
2183   if (!infile)
2184   {
2185     DBG(DBG_error, "could not load file %s\n", v->filename);
2186    return -1;
2187   }
2188 
2189   xsane_read_pnm_header(infile, &image_info);
2190 
2191   pos0 = ftell(infile);
2192 
2193   if (!image_info.channels) /* == 0 (grayscale) ? */
2194   {
2195     image_info.channels = 1; /* we have one color component */
2196   }
2197 
2198   DBG(DBG_info, "reading image %s with  geometry: %d x %d x %d, %d channels\n", v->filename,
2199                  image_info.image_width, image_info.image_height, image_info.depth, image_info.channels);
2200 
2201 #ifdef HAVE_LIBLCMS
2202   /* init color management */
2203 
2204   if ((v->enable_color_management) && (v->cms_enable))
2205   {
2206     cmsErrorAction(LCMS_ERROR_SHOW);
2207 
2208     if (v->cms_bpc)
2209     {
2210       cms_flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
2211     }
2212 
2213     if (image_info.channels == 1) /* == 1 (grayscale) */
2214     {
2215       if (image_info.depth == 8)
2216       {
2217         cms_input_format  = TYPE_GRAY_8;
2218         cms_output_format = TYPE_GRAY_8;
2219       }
2220       else
2221       {
2222         cms_input_format  = TYPE_GRAY_16;
2223         cms_output_format = TYPE_GRAY_8;
2224       }
2225     }
2226     else /* color */
2227     {
2228       if (image_info.depth == 8)
2229       {
2230         cms_input_format  = TYPE_RGB_8;
2231         cms_output_format = TYPE_RGB_8;
2232       }
2233       else
2234       {
2235         cms_input_format  = TYPE_RGB_16;
2236         cms_output_format = TYPE_RGB_8;
2237       }
2238     }
2239 
2240     switch (v->cms_proofing)
2241     {
2242       default:
2243       case 0: /* display */
2244         proof = 0;
2245        break;
2246 
2247       case 1: /* proof printer */
2248         cms_proof_icm_profile  = preferences.printer[preferences.printernr]->icm_profile;
2249         proof = 1;
2250        break;
2251 
2252       case 2: /* proof custom proofing */
2253         cms_proof_icm_profile  = preferences.custom_proofing_icm_profile;
2254         proof = 1;
2255        break;
2256     }
2257 
2258     hInProfile  = cmsOpenProfileFromFile(image_info.icm_profile, "r");
2259     if (!hInProfile)
2260     {
2261      char buf[TEXTBUFSIZE];
2262 
2263       snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_SCANNER_ICM, image_info.icm_profile);
2264       xsane_back_gtk_error(buf, TRUE);
2265      return -1;
2266     }
2267 
2268     hOutProfile = cmsOpenProfileFromFile(preferences.display_icm_profile, "r");
2269     if (!hOutProfile)
2270     {
2271      char buf[TEXTBUFSIZE];
2272 
2273       cmsCloseProfile(hInProfile);
2274 
2275       snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_DISPLAY_ICM, preferences.display_icm_profile);
2276       xsane_back_gtk_error(buf, TRUE);
2277      return -1;
2278     }
2279 
2280 
2281     if (proof == 0)
2282     {
2283       hTransform = cmsCreateTransform(hInProfile, cms_input_format,
2284                                       hOutProfile, cms_output_format,
2285                                       v->cms_intent, cms_flags);
2286     }
2287     else /* proof */
2288     {
2289       cms_flags |= cmsFLAGS_SOFTPROOFING;
2290 
2291       if (v->cms_gamut_check)
2292       {
2293         cms_flags |= cmsFLAGS_GAMUTCHECK;
2294       }
2295 
2296       hProofProfile = cmsOpenProfileFromFile(cms_proof_icm_profile, "r");
2297       if (!hProofProfile)
2298       {
2299        char buf[TEXTBUFSIZE];
2300 
2301         cmsCloseProfile(hInProfile);
2302         cmsCloseProfile(hOutProfile);
2303 
2304         snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_PROOF_ICM, cms_proof_icm_profile);
2305         xsane_back_gtk_error(buf, TRUE);
2306        return -1;
2307       }
2308 
2309       hTransform = cmsCreateProofingTransform(hInProfile, cms_input_format,
2310                                               hOutProfile, cms_output_format,
2311                                               hProofProfile,
2312                                               v->cms_intent, v->cms_proofing_intent, cms_flags);
2313     }
2314 
2315     cmsCloseProfile(hInProfile);
2316     cmsCloseProfile(hOutProfile);
2317     if (proof)
2318     {
2319       cmsCloseProfile(hProofProfile);
2320     }
2321 
2322     if (!hTransform)
2323     {
2324      char buf[TEXTBUFSIZE];
2325 
2326       snprintf(buf, sizeof(buf), "%s\n%s\n", ERR_CMS_CONVERSION, ERR_CMS_CREATE_TRANSFORM);
2327       xsane_back_gtk_error(buf, TRUE);
2328      return -1;
2329     }
2330   }
2331 #endif
2332 
2333   /* open infile */
2334 
2335   if (v->window) /* we already have an existing viewer preview window? */
2336   {
2337     gtk_widget_destroy(v->window);
2338   }
2339 
2340   /* the preview area */
2341   if (image_info.channels == 3) /* RGB */
2342   {
2343     v->window = gtk_preview_new(GTK_PREVIEW_COLOR);
2344   }
2345   else /* grayscale */
2346   {
2347     v->window = gtk_preview_new(GTK_PREVIEW_GRAYSCALE);
2348   }
2349 
2350   gtk_preview_size(GTK_PREVIEW(v->window), image_info.image_width * v->zoom, image_info.image_height * v->zoom);
2351   gtk_container_add(GTK_CONTAINER(v->viewport), v->window);
2352   gtk_widget_show(v->window);
2353 
2354 
2355 
2356   /* get memory for one row of the image */
2357   src_row = malloc(image_info.image_width * image_info.channels * image_info.depth / 8);
2358 
2359   if ((v->enable_color_management) && (v->cms_enable))
2360   {
2361     row     = malloc(((int) image_info.image_width * v->zoom) * image_info.channels * image_info.depth / 8);
2362   }
2363   else
2364   {
2365     row     = malloc(((int) image_info.image_width * v->zoom) * image_info.channels);
2366   }
2367 
2368 #ifdef HAVE_LIBLCMS
2369   if ((v->enable_color_management) && (v->cms_enable))
2370   {
2371     cms_row = malloc(((int) image_info.image_width * v->zoom) * image_info.channels);
2372   }
2373   else
2374 #endif
2375   {
2376     cms_row = row;
2377   }
2378 
2379   if (!row || !src_row || !cms_row)
2380   {
2381     if (src_row)
2382     {
2383       free(src_row);
2384     }
2385 
2386     if (row)
2387     {
2388       free(row);
2389     }
2390 
2391 #ifdef HAVE_LIBLCMS
2392     if ((cms_row) && (v->enable_color_management) && (v->cms_enable))
2393     {
2394       free(cms_row);
2395     }
2396 #endif
2397 
2398     fclose(infile);
2399     DBG(DBG_error, "could not allocate memory\n");
2400    return -1;
2401   }
2402 
2403 
2404   last_y = -99999;
2405 
2406   /* read the image from file */
2407   for (y = 0; y < (int) (image_info.image_height * v->zoom); y++)
2408   {
2409     if ((int) (last_y / v->zoom) != (int) (y / v->zoom))
2410     {
2411       last_y = y;
2412 
2413       if (image_info.depth == 8) /* 8 bits/pixel */
2414       {
2415         fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels, SEEK_SET);
2416         nread = fread(src_row, image_info.channels, image_info.image_width, infile);
2417 
2418         if (image_info.channels > 1)
2419         {
2420           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2421           {
2422            int xoff = ((int) (x / v->zoom)) * image_info.channels;
2423 
2424             row[3*x+0] = src_row[xoff + 0];
2425             row[3*x+1] = src_row[xoff + 1];
2426             row[3*x+2] = src_row[xoff + 2];
2427           }
2428         }
2429         else
2430         {
2431           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2432           {
2433             row[x] = src_row[((int) (x / v->zoom))];
2434           }
2435         }
2436       }
2437       else if ((!v->enable_color_management) || (!v->cms_enable)) /* 16 bits/pixel => reduce to 8 bits/pixel */
2438       {
2439        guint16 *src_row16 = (guint16 *) src_row;
2440 
2441         fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels * 2, SEEK_SET);
2442         nread = fread(src_row, 2 * image_info.channels, image_info.image_width, infile);
2443 
2444         if (image_info.channels > 1)
2445         {
2446           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2447           {
2448            int xoff = ((int) (x / v->zoom)) * image_info.channels;
2449 
2450             row[3*x+0] = (unsigned char) (src_row16[xoff + 0] / 256);
2451             row[3*x+1] = (unsigned char) (src_row16[xoff + 1] / 256);
2452             row[3*x+2] = (unsigned char) (src_row16[xoff + 2] / 256);
2453           }
2454         }
2455         else
2456         {
2457           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2458           {
2459             row[x] = (unsigned char) (src_row16[(int) (x / v->zoom)] / 256);
2460           }
2461         }
2462       }
2463       else /* 16 bits/pixel with color management enabled, cms does 16->8 conversion */
2464       {
2465        guint16 *src_row16 = (guint16 *) src_row;
2466        guint16 *dst_row16 = (guint16 *) row;
2467 
2468         fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels * 2, SEEK_SET);
2469         nread = fread(src_row, 2 * image_info.channels, image_info.image_width, infile);
2470 
2471         if (image_info.channels > 1)
2472         {
2473           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2474           {
2475            int xoff = ((int) (x / v->zoom)) * image_info.channels;
2476 
2477             dst_row16[3*x+0] = src_row16[xoff + 0];
2478             dst_row16[3*x+1] = src_row16[xoff + 1];
2479             dst_row16[3*x+2] = src_row16[xoff + 2];
2480           }
2481         }
2482         else
2483         {
2484           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2485           {
2486             dst_row16[x] = src_row16[(int) (x / v->zoom)];
2487           }
2488         }
2489       }
2490     }
2491 
2492 #ifdef HAVE_LIBLCMS
2493     if ((v->enable_color_management) && (v->cms_enable))
2494     {
2495       cmsDoTransform(hTransform, row, cms_row, image_info.image_width * v->zoom);
2496     }
2497 #endif
2498     gtk_preview_draw_row(GTK_PREVIEW(v->window), cms_row, 0, y, image_info.image_width * v->zoom);
2499   }
2500 
2501   gtk_preview_put(GTK_PREVIEW(v->window), v->window->window, v->window->style->black_gc, 0, 0, 0, 0,
2502                   image_info.image_width * v->zoom, image_info.image_height * v->zoom);
2503 
2504   size = (float) image_info.image_width * image_info.image_height * image_info.channels;
2505   if (image_info.depth == 16)
2506   {
2507     size *= 2.0;
2508   }
2509 
2510   if (image_info.reduce_to_lineart)
2511   {
2512     size /= 8.0;
2513   }
2514 
2515   size_unit = "B";
2516 
2517   if (size >= 1024 * 1024)
2518   {
2519     size /= (1024.0 * 1024.0);
2520     size_unit = "MB";
2521   }
2522   else if (size >= 1024)
2523   {
2524     size /= 1024.0;
2525     size_unit = "KB";
2526   }
2527 
2528   if (image_info.reduce_to_lineart)
2529   {
2530     snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, 1, image_info.channels,
2531              image_info.resolution_x, image_info.resolution_y, size, size_unit);
2532   }
2533   else
2534   {
2535     snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels,
2536              image_info.resolution_x, image_info.resolution_y, size, size_unit);
2537   }
2538   gtk_label_set(GTK_LABEL(v->image_info_label), buf);
2539 
2540   width = image_info.image_width * v->zoom + 26;
2541   height = image_info.image_height * v->zoom + 136;
2542 
2543   if (width >= gdk_screen_width())
2544   {
2545     width = gdk_screen_width()-1;
2546   }
2547 
2548   if (height >= gdk_screen_height())
2549   {
2550     height = gdk_screen_height()-1;
2551   }
2552 
2553 #ifdef HAVE_GTK2
2554   if (GTK_WIDGET_REALIZED(v->top))
2555   {
2556     gtk_window_resize(GTK_WINDOW(v->top), width, height);
2557   }
2558   else
2559 #endif
2560   {
2561     gtk_window_set_default_size(GTK_WINDOW(v->top), width, height);
2562   }
2563 
2564   free(row);
2565   free(src_row);
2566   fclose(infile);
2567 
2568 #ifdef HAVE_LIBLCMS
2569   if ((v->enable_color_management) && (v->cms_enable))
2570   {
2571     cmsDeleteTransform(hTransform);
2572   }
2573 #endif
2574 
2575  return 0;
2576 }
2577 
2578 #if 0 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2579 
2580 static int xsane_viewer_read_image(Viewer *v)
2581 {
2582  unsigned char *row, *src_row;
2583  int x, y;
2584  int last_y;
2585  int nread;
2586  int pos0;
2587  FILE *infile;
2588  Image_info image_info;
2589  char buf[TEXTBUFSIZE];
2590  float size;
2591  char *size_unit;
2592  int width, height;
2593 
2594   infile = fopen(v->filename, "rb");
2595   if (!infile)
2596   {
2597     DBG(DBG_error, "could not load file %s\n", v->filename);
2598    return -1;
2599   }
2600 
2601   xsane_read_pnm_header(infile, &image_info);
2602 
2603   pos0 = ftell(infile);
2604 
2605   if (!image_info.channels) /* == 0 (grayscale) ? */
2606   {
2607     image_info.channels = 1; /* we have one color component */
2608   }
2609 
2610   DBG(DBG_info, "reading image %s with  geometry: %d x %d x %d, %d channels\n", v->filename,
2611                  image_info.image_width, image_info.image_height, image_info.depth, image_info.channels);
2612   /* open infile */
2613 
2614   if (v->window) /* we already have an existing viewer preview window? */
2615   {
2616     gtk_widget_destroy(v->window);
2617   }
2618 
2619   /* the preview area */
2620   if (image_info.channels == 3) /* RGB */
2621   {
2622     v->window = gtk_preview_new(GTK_PREVIEW_COLOR);
2623   }
2624   else /* grayscale */
2625   {
2626     v->window = gtk_preview_new(GTK_PREVIEW_GRAYSCALE);
2627   }
2628 
2629   gtk_preview_size(GTK_PREVIEW(v->window), image_info.image_width * v->zoom, image_info.image_height * v->zoom);
2630   gtk_container_add(GTK_CONTAINER(v->viewport), v->window);
2631   gtk_widget_show(v->window);
2632 
2633 
2634 
2635   /* get memory for one row of the image */
2636   src_row = malloc(image_info.image_width * image_info.channels * image_info.depth / 8);
2637   row = malloc(((int) image_info.image_width * v->zoom) * image_info.channels);
2638 
2639   if (!row || !src_row)
2640   {
2641     if (src_row)
2642     {
2643       free(src_row);
2644     }
2645 
2646     if (row)
2647     {
2648       free(row);
2649     }
2650 
2651     fclose(infile);
2652     DBG(DBG_error, "could not allocate memory\n");
2653    return -1;
2654   }
2655 
2656 
2657   last_y = -99999;
2658 
2659   /* read the image from file */
2660   for (y = 0; y < (int) (image_info.image_height * v->zoom); y++)
2661   {
2662     if ((int) (last_y / v->zoom) != (int) (y / v->zoom))
2663     {
2664       last_y = y;
2665 
2666       if (image_info.depth == 8) /* 8 bits/pixel */
2667       {
2668         fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels, SEEK_SET);
2669         nread = fread(src_row, image_info.channels, image_info.image_width, infile);
2670 
2671         if (image_info.channels > 1)
2672         {
2673           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2674           {
2675            int xoff = ((int) (x / v->zoom)) * image_info.channels;
2676 
2677             row[3*x+0] = src_row[xoff + 0];
2678             row[3*x+1] = src_row[xoff + 1];
2679             row[3*x+2] = src_row[xoff + 2];
2680           }
2681         }
2682         else
2683         {
2684           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2685           {
2686             row[x] = src_row[((int) (x / v->zoom))];
2687           }
2688         }
2689       }
2690       else /* 16 bits/pixel => reduce to 8 bits/pixel */
2691       {
2692        guint16 *src_row16 = (guint16 *) src_row;
2693 
2694         fseek(infile, pos0 + (((int) (y / v->zoom)) * image_info.image_width) * image_info.channels * 2, SEEK_SET);
2695         nread = fread(src_row, 2 * image_info.channels, image_info.image_width, infile);
2696 
2697         if (image_info.channels > 1)
2698         {
2699           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2700           {
2701            int xoff = ((int) (x / v->zoom)) * image_info.channels;
2702 
2703             row[3*x+0] = (unsigned char) (src_row16[xoff + 0] / 256);
2704             row[3*x+1] = (unsigned char) (src_row16[xoff + 1] / 256);
2705             row[3*x+2] = (unsigned char) (src_row16[xoff + 2] / 256);
2706           }
2707         }
2708         else
2709         {
2710           for (x=0; x < (int) (image_info.image_width * v->zoom); x++)
2711           {
2712             row[x] = (unsigned char) (src_row16[(int) (x / v->zoom)] / 256);
2713           }
2714         }
2715       }
2716     }
2717 
2718     gtk_preview_draw_row(GTK_PREVIEW(v->window), row, 0, y, image_info.image_width * v->zoom);
2719   }
2720 
2721   gtk_preview_put(GTK_PREVIEW(v->window), v->window->window, v->window->style->black_gc, 0, 0, 0, 0,
2722                   image_info.image_width * v->zoom, image_info.image_height * v->zoom);
2723 
2724   size = (float) image_info.image_width * image_info.image_height * image_info.channels;
2725   if (image_info.depth == 16)
2726   {
2727     size *= 2.0;
2728   }
2729 
2730   if (image_info.reduce_to_lineart)
2731   {
2732     size /= 8.0;
2733   }
2734 
2735   size_unit = "B";
2736 
2737   if (size >= 1024 * 1024)
2738   {
2739     size /= (1024.0 * 1024.0);
2740     size_unit = "MB";
2741   }
2742   else if (size >= 1024)
2743   {
2744     size /= 1024.0;
2745     size_unit = "KB";
2746   }
2747 
2748   if (image_info.reduce_to_lineart)
2749   {
2750     snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, 1, image_info.channels,
2751              image_info.resolution_x, image_info.resolution_y, size, size_unit);
2752   }
2753   else
2754   {
2755     snprintf(buf, sizeof(buf), TEXT_VIEWER_IMAGE_INFO, image_info.image_width, image_info.image_height, image_info.depth, image_info.channels,
2756              image_info.resolution_x, image_info.resolution_y, size, size_unit);
2757   }
2758   gtk_label_set(GTK_LABEL(v->image_info_label), buf);
2759 
2760   width = image_info.image_width * v->zoom + 26;
2761   height = image_info.image_height * v->zoom + 136;
2762 
2763   if (width >= gdk_screen_width())
2764   {
2765     width = gdk_screen_width()-1;
2766   }
2767 
2768   if (height >= gdk_screen_height())
2769   {
2770     height = gdk_screen_height()-1;
2771   }
2772 
2773 #ifdef HAVE_GTK2
2774   if (GTK_WIDGET_REALIZED(v->top))
2775   {
2776     gtk_window_resize(GTK_WINDOW(v->top), width, height);
2777   }
2778   else
2779 #endif
2780   {
2781     gtk_window_set_default_size(GTK_WINDOW(v->top), width, height);
2782   }
2783 
2784   free(row);
2785   free(src_row);
2786   fclose(infile);
2787 
2788  return 0;
2789 }
2790 #endif
2791 
2792 /* ---------------------------------------------------------------------------------------------------------------------- */
2793 
xsane_viewer_new(char * filename,char * selection_filetype,int allow_reduction_to_lineart,char * output_filename,viewer_modification allow_modification,int image_saved)2794 Viewer *xsane_viewer_new(char *filename, char *selection_filetype, int allow_reduction_to_lineart,
2795                          char *output_filename, viewer_modification allow_modification, int image_saved)
2796 {
2797  char buf[TEXTBUFSIZE];
2798  Viewer *v;
2799  GtkWidget *vbox, *hbox;
2800  GtkWidget *menubar, *menubar_item;
2801  GtkWidget *scrolled_window;
2802  GtkWidget *zoom_option_menu, *zoom_menu, *zoom_menu_item;
2803  int i, selection;
2804 
2805   DBG(DBG_proc, "viewer_new(%s)\n", filename);
2806 
2807   /* create viewer structure v */
2808   v = malloc(sizeof(*v));
2809   if (!v)
2810   {
2811     DBG(DBG_error, "could not allocate memory\n");
2812     return 0;
2813   }
2814   memset(v, 0, sizeof(*v));
2815 
2816   v->filename = strdup(filename);
2817   v->undo_filename = NULL;
2818   v->allow_reduction_to_lineart = allow_reduction_to_lineart;
2819   v->zoom = 1.0;
2820   v->image_saved = image_saved;
2821   v->keep_viewer_pnm_format = FALSE;
2822   v->allow_modification = allow_modification;
2823   v->next_viewer = xsane.viewer_list;
2824 #ifdef HAVE_LIBLCMS
2825   v->enable_color_management = FALSE;
2826   v->cms_enable = TRUE;
2827   v->cms_function = XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE;
2828   v->cms_intent = INTENT_PERCEPTUAL;
2829   v->cms_proofing = 0; /* display */
2830   v->cms_proofing_intent = INTENT_ABSOLUTE_COLORIMETRIC;
2831   v->cms_gamut_check = 0;
2832   v->cms_gamut_alarm_color = 3; /* red */
2833   cmsSetAlarmCodes(255, 0, 0);
2834 #endif
2835   if (selection_filetype)
2836   {
2837     v->selection_filetype = strdup(selection_filetype);
2838   }
2839   else
2840   {
2841     v->selection_filetype = NULL;
2842   }
2843 
2844   xsane.viewer_list = v;
2845 
2846   if (v->allow_modification != VIEWER_FULL_MODIFICATION)
2847   {
2848     v->keep_viewer_pnm_format = TRUE;
2849     v->last_saved_filename = strdup(output_filename); /* output_filename MUST be defined in this case */
2850   }
2851 
2852   if (output_filename)
2853   {
2854     v->output_filename = strdup(output_filename);
2855 
2856     if (v->image_saved)
2857     {
2858       snprintf(buf, sizeof(buf), "%s %s - %s", WINDOW_VIEWER, v->output_filename, xsane.device_text);
2859     }
2860     else
2861     {
2862       /* add brackets around filename because file is not saved */
2863       snprintf(buf, sizeof(buf), "%s (%s) - %s", WINDOW_VIEWER, v->output_filename, xsane.device_text);
2864     }
2865   }
2866   else
2867   {
2868     snprintf(buf, sizeof(buf), "%s %s", WINDOW_VIEWER, xsane.device_text);
2869   }
2870 
2871   xsane_viewer_read_image_header(v);
2872 
2873   v->top = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2874   gtk_window_set_title(GTK_WINDOW(v->top), buf);
2875   xsane_set_window_icon(v->top, 0);
2876   gtk_window_add_accel_group(GTK_WINDOW(v->top), xsane.accelerator_group);
2877   gtk_object_set_data(GTK_OBJECT(v->top), "Viewer", (void *) v);
2878   g_signal_connect(GTK_OBJECT(v->top), "delete_event", GTK_SIGNAL_FUNC(xsane_viewer_close_callback), NULL);
2879 
2880   /* set the main vbox */
2881   vbox = gtk_vbox_new(FALSE, 0);
2882   gtk_container_set_border_width(GTK_CONTAINER(vbox), 0);
2883   gtk_container_add(GTK_CONTAINER(v->top), vbox);
2884   gtk_widget_show(vbox);
2885 
2886 
2887   /* create the menubar */
2888   menubar = gtk_menu_bar_new();
2889   gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
2890 
2891   /* "File" submenu: */
2892   menubar_item = gtk_menu_item_new_with_label(MENU_FILE);
2893   gtk_container_add(GTK_CONTAINER(menubar), menubar_item);
2894   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_viewer_file_build_menu(v));
2895 /*  gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED); */
2896   gtk_widget_show(menubar_item);
2897   v->file_menu = menubar_item;
2898 
2899   /* "Edit" submenu: */
2900   menubar_item = gtk_menu_item_new_with_label(MENU_EDIT);
2901   gtk_container_add(GTK_CONTAINER(menubar), menubar_item);
2902   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_viewer_edit_build_menu(v));
2903 /*  gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED); */
2904   gtk_widget_show(menubar_item);
2905   v->edit_menu = menubar_item;
2906 
2907   /* "Filters" submenu: */
2908   menubar_item = gtk_menu_item_new_with_label(MENU_FILTERS);
2909   gtk_container_add(GTK_CONTAINER(menubar), menubar_item);
2910   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_viewer_filters_build_menu(v));
2911 /*  gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED); */
2912   gtk_widget_show(menubar_item);
2913   v->filters_menu = menubar_item;
2914 
2915   /* "Geometry" submenu: */
2916   menubar_item = gtk_menu_item_new_with_label(MENU_GEOMETRY);
2917   gtk_container_add(GTK_CONTAINER(menubar), menubar_item);
2918   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_viewer_geometry_build_menu(v));
2919 /*  gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED); */
2920   gtk_widget_show(menubar_item);
2921   v->geometry_menu = menubar_item;
2922 
2923 #ifdef HAVE_LIBLCMS
2924   /* "Color management" submenu: */
2925   menubar_item = gtk_menu_item_new_with_label(MENU_COLOR_MANAGEMENT);
2926   gtk_container_add(GTK_CONTAINER(menubar), menubar_item);
2927   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar_item), xsane_viewer_color_management_build_menu(v));
2928 /*  gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED); */
2929   gtk_widget_show(menubar_item);
2930   v->color_management_menu = menubar_item;
2931   gtk_widget_set_sensitive(GTK_WIDGET(v->color_management_menu), v->enable_color_management);
2932 #endif
2933 
2934   gtk_widget_show(menubar);
2935 
2936 
2937   /* set the main hbox */
2938   hbox = gtk_hbox_new(FALSE, 0);
2939   gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
2940   gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
2941   gtk_widget_show(hbox);
2942 
2943 
2944   /* top hbox for icons */
2945   v->button_box = gtk_hbox_new(FALSE, 1);
2946   gtk_container_set_border_width(GTK_CONTAINER(v->button_box), 1);
2947   gtk_box_pack_start(GTK_BOX(vbox), v->button_box, FALSE, FALSE, 0);
2948   gtk_widget_show(v->button_box);
2949 
2950 
2951   /* top hbox for file icons */
2952   v->file_button_box = gtk_hbox_new(FALSE, 0);
2953   gtk_container_set_border_width(GTK_CONTAINER(v->file_button_box), 0);
2954   gtk_box_pack_start(GTK_BOX(v->button_box), v->file_button_box, FALSE, FALSE, 0);
2955   gtk_widget_show(v->file_button_box);
2956 
2957   v->save      = xsane_button_new_with_pixmap(v->top->window, v->file_button_box, save_xpm,      DESC_VIEWER_SAVE,      (GtkSignalFunc) xsane_viewer_save_callback, v);
2958   v->ocr       = xsane_button_new_with_pixmap(v->top->window, v->file_button_box, ocr_xpm,       DESC_VIEWER_OCR,       (GtkSignalFunc) xsane_viewer_ocr_callback, v);
2959   v->clone     = xsane_button_new_with_pixmap(v->top->window, v->button_box, clone_xpm,     DESC_VIEWER_CLONE,     (GtkSignalFunc) xsane_viewer_clone_callback, v);
2960 
2961 
2962   /* top hbox for edit icons */
2963   v->edit_button_box = gtk_hbox_new(FALSE, 0);
2964   gtk_container_set_border_width(GTK_CONTAINER(v->edit_button_box), 0);
2965   gtk_box_pack_start(GTK_BOX(v->button_box), v->edit_button_box, FALSE, FALSE, 0);
2966   gtk_widget_show(v->edit_button_box);
2967 
2968   v->undo      = xsane_button_new_with_pixmap(v->top->window, v->edit_button_box, undo_xpm,      DESC_VIEWER_UNDO,      (GtkSignalFunc) xsane_viewer_undo_callback, v);
2969 
2970 
2971   /* top hbox for filter icons */
2972   v->filters_button_box = gtk_hbox_new(FALSE, 0);
2973   gtk_container_set_border_width(GTK_CONTAINER(v->filters_button_box), 0);
2974   gtk_box_pack_start(GTK_BOX(v->button_box), v->filters_button_box, FALSE, FALSE, 0);
2975   gtk_widget_show(v->filters_button_box);
2976 
2977   v->despeckle = xsane_button_new_with_pixmap(v->top->window, v->filters_button_box, despeckle_xpm, DESC_VIEWER_DESPECKLE, (GtkSignalFunc) xsane_viewer_despeckle_callback, v);
2978   v->blur      = xsane_button_new_with_pixmap(v->top->window, v->filters_button_box, blur_xpm,      DESC_VIEWER_BLUR,      (GtkSignalFunc) xsane_viewer_blur_callback, v);
2979 
2980 
2981   /* top hbox for geometry icons */
2982   v->geometry_button_box = gtk_hbox_new(FALSE, 0);
2983   gtk_container_set_border_width(GTK_CONTAINER(v->geometry_button_box), 0);
2984   gtk_box_pack_start(GTK_BOX(v->button_box), v->geometry_button_box, FALSE, FALSE, 0);
2985   gtk_widget_show(v->geometry_button_box);
2986 
2987   xsane_button_new_with_pixmap(v->top->window, v->geometry_button_box, scale_xpm,     DESC_VIEWER_SCALE,     (GtkSignalFunc) xsane_viewer_scale_callback, v);
2988   xsane_button_new_with_pixmap(v->top->window, v->geometry_button_box, rotate90_xpm,  DESC_ROTATE90,         (GtkSignalFunc) xsane_viewer_rotate90_callback, v);
2989   xsane_button_new_with_pixmap(v->top->window, v->geometry_button_box, rotate180_xpm, DESC_ROTATE180,        (GtkSignalFunc) xsane_viewer_rotate180_callback, v);
2990   xsane_button_new_with_pixmap(v->top->window, v->geometry_button_box, rotate270_xpm, DESC_ROTATE270,        (GtkSignalFunc) xsane_viewer_rotate270_callback, v);
2991   xsane_button_new_with_pixmap(v->top->window, v->geometry_button_box, mirror_x_xpm,  DESC_MIRROR_X,         (GtkSignalFunc) xsane_viewer_mirror_x_callback, v);
2992   xsane_button_new_with_pixmap(v->top->window, v->geometry_button_box, mirror_y_xpm,  DESC_MIRROR_Y,         (GtkSignalFunc) xsane_viewer_mirror_y_callback, v);
2993 
2994 
2995   /* "Zoom" submenu: */
2996   zoom_option_menu = gtk_option_menu_new();
2997   xsane_back_gtk_set_tooltip(xsane.tooltips, zoom_option_menu, DESC_VIEWER_ZOOM);
2998   gtk_box_pack_start(GTK_BOX(v->button_box), zoom_option_menu, FALSE, FALSE, 0);
2999   gtk_widget_show(zoom_option_menu);
3000 
3001   zoom_menu = gtk_menu_new();
3002   selection = 0;
3003 
3004   for (i = 0; i < sizeof(xsane_viewer_zoom) / sizeof(int); i++)
3005   {
3006     snprintf(buf, sizeof(buf), "%d %%", xsane_viewer_zoom[i]);
3007     zoom_menu_item = gtk_menu_item_new_with_label(buf);
3008     gtk_menu_append(GTK_MENU(zoom_menu), zoom_menu_item);
3009     g_signal_connect(GTK_OBJECT(zoom_menu_item), "activate", (GtkSignalFunc) xsane_viewer_zoom_callback, v);
3010     gtk_object_set_data(GTK_OBJECT(zoom_menu_item), "Selection", (void *) xsane_viewer_zoom[i]);
3011     gtk_widget_show(zoom_menu_item);
3012     if (v->zoom*100 == xsane_viewer_zoom[i])
3013     {
3014       selection = i;
3015     }
3016   }
3017   gtk_option_menu_set_menu(GTK_OPTION_MENU(zoom_option_menu), zoom_menu);
3018   gtk_option_menu_set_history(GTK_OPTION_MENU(zoom_option_menu), selection);
3019 /*  gtk_widget_add_accelerator(menubar_item, "select", xsane.accelerator_group, GDK_F, 0, GTK_ACCEL_VISIBLE | DEF_GTK_ACCEL_LOCKED); */
3020   gtk_widget_show(zoom_menu);
3021 
3022 
3023 
3024   scrolled_window = gtk_scrolled_window_new(NULL, NULL);
3025   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3026   gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
3027   gtk_widget_show(scrolled_window);
3028 
3029 
3030   /* the viewport */
3031   v->viewport = gtk_frame_new(/* label */ 0);
3032   gtk_frame_set_shadow_type(GTK_FRAME(v->viewport), GTK_SHADOW_IN);
3033   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), v->viewport);
3034   gtk_widget_show(v->viewport);
3035 
3036 
3037   /* image info label */
3038   hbox = gtk_hbox_new(FALSE, 1);
3039   gtk_container_set_border_width(GTK_CONTAINER(hbox), 1);
3040   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
3041   gtk_widget_show(hbox);
3042   v->image_info_label = gtk_label_new("");
3043   gtk_box_pack_start(GTK_BOX(hbox), v->image_info_label, FALSE, FALSE, 2);
3044   gtk_widget_show(v->image_info_label);
3045 
3046 
3047   if (xsane_viewer_read_image(v)) /* read image and add preview to the viewport */
3048   {
3049     /* error */
3050   }
3051   gtk_widget_show(v->top);
3052 
3053   v->progress_bar = (GtkProgressBar *) gtk_progress_bar_new();
3054 #if 0
3055   gtk_widget_set_size_request(v->progress_bar, 0, 25);
3056 #endif
3057   gtk_box_pack_start(GTK_BOX(vbox), (GtkWidget *) v->progress_bar, FALSE, FALSE, 0);
3058   gtk_progress_set_show_text(GTK_PROGRESS(v->progress_bar), TRUE);
3059   gtk_progress_set_format_string(GTK_PROGRESS(v->progress_bar), "");
3060   gtk_widget_show(GTK_WIDGET(v->progress_bar));
3061 
3062   xsane_viewer_set_sensitivity(v, TRUE);
3063 
3064   gtk_widget_set_sensitive(GTK_WIDGET(v->undo), FALSE);
3065   gtk_widget_set_sensitive(GTK_WIDGET(v->undo_menu_item), FALSE);
3066 
3067  return v;
3068 }
3069 
3070