summaryrefslogtreecommitdiff
path: root/src/xsane-preview.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xsane-preview.c')
-rw-r--r--src/xsane-preview.c2328
1 files changed, 1872 insertions, 456 deletions
diff --git a/src/xsane-preview.c b/src/xsane-preview.c
index da81e3f..879bc99 100644
--- a/src/xsane-preview.c
+++ b/src/xsane-preview.c
@@ -3,7 +3,7 @@
xsane-preview.c
Oliver Rauch <Oliver.Rauch@rauch-domain.de>
- Copyright (C) 1998-2002 Oliver Rauch
+ Copyright (C) 1998-2005 Oliver Rauch
This file is part of the XSANE package.
This program is free software; you can redistribute it and/or modify
@@ -76,6 +76,7 @@
/* #include <sys/param.h> */
#include "xsane-back-gtk.h"
#include "xsane-front-gtk.h"
+#include "xsane-batch-scan.h"
#include "xsane-preview.h"
#include "xsane-preferences.h"
#include "xsane-gamma.h"
@@ -102,6 +103,11 @@
/* ---------------------------------------------------------------------------------------------------------------------- */
+#define XSANE_ZOOM_SIZE 80
+#define XSANE_ZOOM_FACTOR 4
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
static u_char *preview_gamma_data_red = 0;
static u_char *preview_gamma_data_green = 0;
static u_char *preview_gamma_data_blue = 0;
@@ -117,6 +123,8 @@ static u_char *histogram_medium_gamma_data_blue = 0;
static int preview_gamma_input_bits;
+static char *ratio_string[] = { "free", " 2:1", "16:9", "15:10", " 4:3", " 1:1", " 3:4", " 9:16", "10:15", " 1:2"};
+static float ratio_value[] = { 0.0, 2.0, 16.0/9.0, 15.0/10.0, 4.0/3.0, 1.0, 0.75, 0.5625, 10.0/15.0, 0.5 };
/* ---------------------------------------------------------------------------------------------------------------------- */
/* forward declarations */
@@ -161,14 +169,18 @@ static void preview_cancel_button_clicked(GtkWidget *widget, gpointer data);
static void preview_area_correct(Preview *p);
static void preview_save_image(Preview *p);
static void preview_delete_images(Preview *p);
+static void preview_select_zoom_point(Preview *p, int preview_x, int preview_y);
static void preview_zoom_not(GtkWidget *window, gpointer data);
static void preview_zoom_out(GtkWidget *window, gpointer data);
static void preview_zoom_in(GtkWidget *window, gpointer data);
+static void preview_zoom_area(GtkWidget *window, gpointer data);
static void preview_zoom_undo(GtkWidget *window, gpointer data);
static void preview_get_color(Preview *p, int x, int y, int range, int *red, int *green, int *blue);
+static void preview_add_batch(GtkWidget *window, Preview *p);
static void preview_pipette_white(GtkWidget *window, gpointer data);
static void preview_pipette_gray(GtkWidget *window, gpointer data);
static void preview_pipette_black(GtkWidget *window, gpointer data);
+static void preview_init_autoraise_scanarea(GtkWidget *window, gpointer data);
void preview_select_full_preview_area(Preview *p);
static void preview_full_preview_area_callback(GtkWidget *widget, gpointer call_data);
static void preview_delete_images_callback(GtkWidget *widget, gpointer call_data);
@@ -178,8 +190,10 @@ static gint preview_preset_area_delete_callback(GtkWidget *widget, GtkWidget *pr
static gint preview_preset_area_move_up_callback(GtkWidget *widget, GtkWidget *preset_area_widget);
static gint preview_preset_area_move_down_callback(GtkWidget *widget, GtkWidget *preset_area_widget);
static gint preview_preset_area_context_menu_callback(GtkWidget *widget, GdkEvent *event);
-static void preview_preset_area_callback(GtkWidget *widget, gpointer call_data);
-static void preview_rotation_callback(GtkWidget *widget, gpointer call_data);
+static void preview_preset_area_callback(GtkWidget *widget, gpointer data);
+static void preview_rotation_callback(GtkWidget *widget, gpointer data);
+static void preview_establish_ratio(Preview *p);
+static void preview_ratio_callback(GtkWidget *widget, gpointer data);
static void preview_autoselect_scanarea_callback(GtkWidget *window, gpointer data);
void preview_do_gamma_correction(Preview *p);
@@ -192,7 +206,8 @@ void preview_gamma_correction(Preview *p, int gamma_input_bits,
void preview_area_resize(Preview *p);
gint preview_area_resize_handler(GtkWidget *widget, GdkEvent *event, gpointer data);
void preview_update_maximum_output_size(Preview *p);
-void preview_set_maximum_output_size(Preview *p, float width, float height);
+void preview_set_maximum_output_size(Preview *p, float width, float height, int paper_orientation);
+void preview_autoraise_scanarea(Preview *p, int preview_x, int preview_y, float *autoselect_coord);
void preview_autoselect_scanarea(Preview *p, float *autoselect_coord);
void preview_display_valid(Preview *p);
@@ -574,16 +589,17 @@ static void preview_bound_selection(Preview *p)
if (p->selection.active)
{
-#if 0
+#if 1
xsane_bound_float(&p->selection.coordinate[0], p->scanner_surface[0], p->scanner_surface[2]);
xsane_bound_float(&p->selection.coordinate[2], p->scanner_surface[0], p->scanner_surface[2]);
xsane_bound_float(&p->selection.coordinate[1], p->scanner_surface[1], p->scanner_surface[3]);
xsane_bound_float(&p->selection.coordinate[3], p->scanner_surface[1], p->scanner_surface[3]);
-#endif
+#else
xsane_bound_float(&p->selection.coordinate[0], p->surface[0], p->surface[2]);
xsane_bound_float(&p->selection.coordinate[2], p->surface[0], p->surface[2]);
xsane_bound_float(&p->selection.coordinate[1], p->surface[1], p->surface[3]);
xsane_bound_float(&p->selection.coordinate[3], p->surface[1], p->surface[3]);
+#endif
}
}
@@ -1304,7 +1320,14 @@ static void preview_restore_option(Preview *p, int option, void *saved_value, in
{
char buf[256];
opt = xsane_get_option_descriptor(dev, option);
- snprintf(buf, sizeof(buf), "%s %s: %s.", ERR_SET_OPTION, opt->name, XSANE_STRSTATUS(status));
+ if (opt && opt->name)
+ {
+ snprintf(buf, sizeof(buf), "%s %s: %s.", ERR_SET_OPTION, opt->name, XSANE_STRSTATUS(status));
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), "%s %d: %s.", ERR_SET_OPTION, option, XSANE_STRSTATUS(status));
+ }
xsane_back_gtk_error(buf, TRUE);
}
}
@@ -1413,8 +1436,8 @@ static int preview_increment_image_y(Preview *p)
if ( (!p->image_data_enh) || (!p->image_data_raw) )
{
- preview_scan_done(p, 0);
snprintf(buf, sizeof(buf), "%s %s.", ERR_FAILED_ALLOCATE_IMAGE, strerror(errno));
+ preview_scan_done(p, 0);
xsane_back_gtk_error(buf, TRUE);
return -1;
}
@@ -1435,8 +1458,6 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio
SANE_Handle dev;
SANE_Int len;
int i, j;
- int offset = 0;
- char last = 0;
DBG(DBG_proc, "preview_read_image_data\n");
@@ -1449,11 +1470,12 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio
}
else if (p->params.depth == 16)
{
- if (offset)
+ if (p->read_offset_16)
{
- buf16[0] = last; /* ATTENTION: that is wrong! */
- /* use sizeof(buf) here because sizeof(buf16) returns the size of a pointer */
- status = sane_read(dev, ((SANE_Byte *) buf16) + 1, sizeof(buf) - 1, &len);
+ buf[0] = p->last_offset_16_byte;
+ /* use buf and sizeof(buf) here because sizeof(buf16) returns the size of a pointer */
+ status = sane_read(dev, buf+1, sizeof(buf) - 1, &len);
+ len++;
}
else
{
@@ -1463,18 +1485,18 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio
if (len % 2) /* odd number of bytes */
{
len--;
- last = buf16[len];
- offset = 1;
+ p->last_offset_16_byte = buf16[len];
+ p->read_offset_16 = 1;
}
else /* even number of bytes */
{
- offset = 0;
+ p->read_offset_16 = 0;
}
}
else /* bad bitdepth */
{
- preview_scan_done(p, 0);
snprintf(buf, sizeof(buf), "%s %d.", ERR_PREVIEW_BAD_DEPTH, p->params.depth);
+ preview_scan_done(p, 0);
xsane_back_gtk_error(buf, TRUE);
return;
}
@@ -1526,7 +1548,19 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio
if (!len)
{
- break; /* out of data for now */
+ if (p->input_tag >= 0) /* we have a selecet fd */
+ {
+ break; /* leave preview_read_image_data, will be called by gdk when select_fd event occurs */
+ }
+ else
+ {
+ while (gtk_events_pending())
+ {
+ DBG(DBG_info, "preview_read_image_data: calling gtk_main_iteration\n");
+ gtk_main_iteration();
+ }
+ continue; /* we have to keep this loop running because it will never be called again */
+ }
}
switch (p->params.format)
@@ -1581,8 +1615,8 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio
break;
default:
- preview_scan_done(p, 0);
snprintf(buf, sizeof(buf), "%s %d.", ERR_PREVIEW_BAD_DEPTH, p->params.depth);
+ preview_scan_done(p, 0);
xsane_back_gtk_error(buf, TRUE);
return;
}
@@ -1678,8 +1712,8 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio
break;
default:
- preview_scan_done(p, 0);
snprintf(buf, sizeof(buf), "%s %d.", ERR_PREVIEW_BAD_DEPTH, p->params.depth);
+ preview_scan_done(p, 0);
xsane_back_gtk_error(buf, TRUE);
return;
}
@@ -1705,8 +1739,8 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio
u_char gl = (mask & 1) ? 0xff : 0x00;
mask >>= 1;
- p->image_data_raw[p->image_offset] = gl * 256;
- p->image_data_enh[p->image_offset++] = gl;
+ p->image_data_raw[p->image_offset] = gl * 256;
+ p->image_data_enh[p->image_offset] = gl;
p->image_offset += 3;
if (++p->image_x >= p->image_width && preview_increment_image_y(p) < 0)
@@ -1756,16 +1790,16 @@ static void preview_read_image_data(gpointer data, gint source, GdkInputConditio
break;
default:
- preview_scan_done(p, 0);
snprintf(buf, sizeof(buf), "%s %d.", ERR_PREVIEW_BAD_DEPTH, p->params.depth);
+ preview_scan_done(p, 0);
xsane_back_gtk_error(buf, TRUE);
return;
}
break;
default:
- preview_scan_done(p, 0);
snprintf(buf, sizeof(buf), "%s %d.", ERR_BAD_FRAME_FORMAT, p->params.format);
+ preview_scan_done(p, 0);
xsane_back_gtk_error(buf, TRUE);
return;
}
@@ -1839,7 +1873,7 @@ static void preview_scan_done(Preview *p, int save_image)
sane_get_parameters(xsane.dev, &xsane.param); /* update xsane.param */
- if ( (preferences.preselect_scanarea) && (!p->startimage))
+ if ((preferences.preselect_scanarea) && (!p->startimage) && (!xsane.medium_calibration))
{
preview_autoselect_scanarea(p, p->selection.coordinate); /* get autoselection coordinates */
preview_draw_selection(p);
@@ -1847,12 +1881,14 @@ static void preview_scan_done(Preview *p, int save_image)
xsane_update_histogram(TRUE /* update_raw */); /* update histogram (necessary because overwritten by preview_update_surface) */
}
- if (preferences.auto_correct_colors)
+ if ((preferences.auto_correct_colors) && (!xsane.medium_calibration))
{
xsane_calculate_raw_histogram();
xsane_set_auto_enhancement();
xsane_enhancement_by_histogram(preferences.auto_enhance_gamma);
}
+
+ xsane_batch_scan_update_icon_list();
}
/* ---------------------------------------------------------------------------------------------------------------------- */
@@ -1927,17 +1963,11 @@ static void preview_scan_start(Preview *p)
SANE_Status status;
char buf[256];
int fd, y;
- int gamma_gray_size = 256; /* set this values to image depth for more than 8bpp input support!!! */
- int gamma_red_size = 256;
- int gamma_green_size = 256;
- int gamma_blue_size = 256;
- int gamma_gray_max = 255; /* set this to to image depth for more than 8bpp output support */
- int gamma_red_max = 255;
- int gamma_green_max = 255;
- int gamma_blue_max = 255;
DBG(DBG_proc, "preview_scan_start\n");
+ p->read_offset_16 = 0;
+
xsane.medium_changed = FALSE;
preview_display_valid(p);
@@ -1966,95 +1996,6 @@ static void preview_scan_start(Preview *p)
p->input_tag = -1;
}
- if (xsane.well_known.gamma_vector >0)
- {
- const SANE_Option_Descriptor *opt;
-
- opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector);
- if (SANE_OPTION_IS_ACTIVE(opt->cap))
- {
- SANE_Int *gamma_data;
-
- opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector);
- gamma_gray_size = opt->size / sizeof(opt->type);
- gamma_gray_max = opt->constraint.range->max;
-
- gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int));
-
- if ((xsane.xsane_colors > 1) || (xsane.no_preview_medium_gamma)) /* color scan or medium preview gamma disabled */
- {
- xsane_create_gamma_curve(gamma_data, 0, 1.0, 0.0, 0.0, 0.0, 100.0, 1.0, gamma_gray_size, gamma_gray_max);
- }
- else /* grayscale scan */
- {
- xsane_create_gamma_curve(gamma_data, xsane.medium_negative, 1.0, 0.0, 0.0,
- xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
- gamma_gray_size, gamma_gray_max);
- }
-
- xsane_back_gtk_update_vector(xsane.well_known.gamma_vector, gamma_data);
- free(gamma_data);
- }
- }
-
- if (xsane.well_known.gamma_vector_r >0)
- {
- const SANE_Option_Descriptor *opt;
-
- opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_r);
- if (SANE_OPTION_IS_ACTIVE(opt->cap))
- {
- SANE_Int *gamma_data_red, *gamma_data_green, *gamma_data_blue;
-
- opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_r);
- gamma_red_size = opt->size / sizeof(opt->type);
- gamma_red_max = opt->constraint.range->max;
-
- opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_g);
- gamma_green_size = opt->size / sizeof(opt->type);
- gamma_green_max = opt->constraint.range->max;
-
- opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_b);
- gamma_blue_size = opt->size / sizeof(opt->type);
- gamma_blue_max = opt->constraint.range->max;
-
- gamma_data_red = malloc(gamma_red_size * sizeof(SANE_Int));
- gamma_data_green = malloc(gamma_green_size * sizeof(SANE_Int));
- gamma_data_blue = malloc(gamma_blue_size * sizeof(SANE_Int));
-
- if (xsane.no_preview_medium_gamma) /* do not use medium gamma for preview */
- {
- DBG(DBG_info, "preview: not using medium gamma table\n");
-
- xsane_create_gamma_curve(gamma_data_red, 0, 1.0, 0.0, 0.0, 0.0, 100.0, 1.0, gamma_red_size, gamma_red_max);
- xsane_create_gamma_curve(gamma_data_green, 0, 1.0, 0.0, 0.0, 0.0, 100.0, 1.0, gamma_green_size, gamma_green_max);
- xsane_create_gamma_curve(gamma_data_blue, 0, 1.0, 0.0, 0.0, 0.0, 100.0, 1.0, gamma_blue_size, gamma_blue_max);
- }
- else /* use medium gamma for preview */
- {
- DBG(DBG_info, "preview: using medium gamma table\n");
-
- xsane_create_gamma_curve(gamma_data_red, xsane.medium_negative, 1.0, 0.0, 0.0,
- xsane.medium_shadow_red, xsane.medium_highlight_red, xsane.medium_gamma_red,
- gamma_red_size, gamma_red_max);
- xsane_create_gamma_curve(gamma_data_green, xsane.medium_negative, 1.0, 0.0, 0.0,
- xsane.medium_shadow_green, xsane.medium_highlight_green, xsane.medium_gamma_green,
- gamma_green_size, gamma_green_max);
- xsane_create_gamma_curve(gamma_data_blue, xsane.medium_negative, 1.0, 0.0, 0.0,
- xsane.medium_shadow_blue, xsane.medium_highlight_blue, xsane.medium_gamma_blue,
- gamma_blue_size, gamma_blue_max);
- }
-
- xsane_back_gtk_update_vector(xsane.well_known.gamma_vector_r, gamma_data_red);
- xsane_back_gtk_update_vector(xsane.well_known.gamma_vector_g, gamma_data_green);
- xsane_back_gtk_update_vector(xsane.well_known.gamma_vector_b, gamma_data_blue);
-
- free(gamma_data_red);
- free(gamma_data_green);
- free(gamma_data_blue);
- }
- }
-
status = sane_start(dev);
if (status != SANE_STATUS_GOOD)
{
@@ -2110,15 +2051,11 @@ static void preview_scan_start(Preview *p)
p->previous_selection_maximum.active = FALSE;
#ifndef BUGGY_GDK_INPUT_EXCEPTION
- /* for unix */
if ((sane_set_io_mode(dev, SANE_TRUE) == SANE_STATUS_GOOD) && (sane_get_select_fd(dev, &fd) == SANE_STATUS_GOOD))
{
p->input_tag = gdk_input_add(fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, preview_read_image_data, p);
}
else
-#else
- /* for win32 */
- sane_set_io_mode(dev, SANE_FALSE);
#endif
{
preview_read_image_data(p, -1, GDK_INPUT_READ);
@@ -2133,12 +2070,370 @@ static int preview_make_image_path(Preview *p, size_t filename_size, char *filen
DBG(DBG_proc, "preview_make_image_path\n");
- snprintf(buf, sizeof(buf), "preview-level-%d-", level);
+ snprintf(buf, sizeof(buf), "xsane-preview-level-%d-", level);
return xsane_back_gtk_make_path(filename_size, filename, 0, 0, buf, xsane.dev_name, ".ppm", XSANE_PATH_TMP);
}
/* ---------------------------------------------------------------------------------------------------------------------- */
+int preview_create_batch_icon_from_file(Preview *p, FILE *in, Batch_Scan_Parameters *parameters, int min_quality, int *min_time)
+{
+ u_int psurface_type, psurface_unit;
+ int image_width, image_height;
+ int xoffset, yoffset, width, height;
+ int max_val;
+ int x, y, dx, dy;
+ int time;
+ float psurface[4];
+ float dsurface[4];
+ char buf[255];
+ float scale;
+ int header = 0;
+ int rotate16 = 16 - preview_gamma_input_bits;
+ int rotate8 = preview_gamma_input_bits - 8;
+ guint16 r,g,b;
+ int c;
+ int maximum_size;
+ int quality = 0;
+ int xx, yy;
+ int offset = 0;
+ guchar *data;
+
+ DBG(DBG_proc, "preview_create_batch_icon_from_file\n");
+
+ if (!in)
+ {
+ return min_quality;
+ }
+
+ /* See whether there is a saved preview and load it if present: */
+ if (fscanf(in, "P6\n"
+ "# surface: %g %g %g %g %u %u\n"
+ "# time: %d\n"
+ "%d %d\n%d",
+ psurface + 0, psurface + 1, psurface + 2, psurface + 3,
+ &psurface_type, &psurface_unit,
+ &time,
+ &image_width, &image_height,
+ &max_val) != 10)
+ {
+ DBG(DBG_info, "no preview image\n");
+ return min_quality;
+ }
+
+ fgets(buf, sizeof(buf), in); /* skip newline character. this made a lot of problems in the past, so I skip it this way */
+
+ header = ftell(in);
+
+ if (min_quality >= 0) /* read real preview */
+ {
+ if ((psurface_type != p->surface_type) || (psurface_unit != p->surface_unit))
+ {
+ DBG(DBG_info, "incompatible surface types %d <> %d\n", psurface_type, p->surface_type);
+ return min_quality;
+ }
+
+ preview_rotate_previewsurface_to_devicesurface(p->rotation, p->surface, dsurface);
+
+
+ DBG(DBG_info, "stored image surface = [%3.2f %3.2f %3.2f %3.2f]\n",
+ psurface[0], psurface[1], psurface[2], psurface[3]);
+ DBG(DBG_info, "batch selection = [%3.2f %3.2f %3.2f %3.2f]\n",
+ parameters->tl_x, parameters->tl_y, parameters->br_x, parameters->br_y);
+ DBG(DBG_info, "preview device surface = [%3.2f %3.2f %3.2f %3.2f]\n",
+ dsurface[0], dsurface[1], dsurface[2], dsurface[3]);
+
+ xoffset = (parameters->tl_x - psurface[0])/(psurface[2] - psurface[0]) * image_width;
+ yoffset = (parameters->tl_y - psurface[1])/(psurface[3] - psurface[1]) * image_height;
+ width = (parameters->br_x - parameters->tl_x)/(psurface[2] - psurface[0]) * image_width;
+ height = (parameters->br_y - parameters->tl_y)/(psurface[3] - psurface[1]) * image_height;
+
+ quality = width;
+
+ if ((xoffset < 0) || (yoffset < 0) ||
+ (xoffset+width > image_width) || (yoffset+height > image_height) ||
+ (width == 0) || (height == 0))
+ {
+ DBG(DBG_info, "image does not cover wanted surface part\n");
+ return min_quality;
+ }
+
+ DBG(DBG_info, "quality = %d\n", quality);
+
+ if ( ((float) min_quality / (quality+1)) > 1.05) /* already loaded image has better quality */
+ {
+ DBG(DBG_info, "already loaded image has higher quality\n");
+ return min_quality;
+ }
+
+ if ( ((float) min_quality / (quality+1)) > 0.95) /* qualities are comparable */
+ {
+ if (*min_time > time) /* take more recent scan */
+ {
+ DBG(DBG_info, "images have comparable quality, already loaded is more up to date\n");
+ return min_quality;
+ }
+ DBG(DBG_info, "images have comparable quality, this image is more up to date\n");
+ }
+ else
+ {
+ DBG(DBG_info, "image has best quality\n");
+ }
+ }
+ else
+ {
+ xoffset = 0;
+ yoffset = 0;
+ width = image_width;
+ height = image_height;
+ }
+
+
+ {
+ float xscale = (float)width / parameters->gtk_preview_size;
+ float yscale = (float)height / parameters->gtk_preview_size;
+
+ if (xscale > yscale)
+ {
+ scale = xscale;
+ }
+ else
+ {
+ scale = yscale;
+ }
+ }
+
+ width = width / scale;
+ height = height / scale;
+
+ if (width > parameters->gtk_preview_size)
+ {
+ width = parameters->gtk_preview_size;
+ }
+
+ if (height > parameters->gtk_preview_size)
+ {
+ height = parameters->gtk_preview_size;
+ }
+
+ maximum_size = parameters->gtk_preview_size -1;
+
+ dx = (parameters->gtk_preview_size - width) / 2;
+ dy = (parameters->gtk_preview_size - height) / 2;
+
+
+ data = malloc(parameters->gtk_preview_size * parameters->gtk_preview_size * 3);
+ if (!data)
+ {
+ DBG(DBG_error, "preview_create_batch_icon_from_file: out of memory\n");
+ return min_quality;
+ }
+
+ /* make unused parts white */
+ for (x = 0; x< parameters->gtk_preview_size * parameters->gtk_preview_size * 3; x++)
+ {
+ data[x] = 0xF0;
+ }
+
+ if (max_val == 65535)
+ {
+ for (y=0; y < height; y++)
+ {
+ for (x=0; x < width; x++)
+ {
+ fseek(in, header + (xoffset + (int)(x * scale) + (yoffset + (int)(y * scale)) * image_width) * 6, SEEK_SET);
+
+ fread(&r, 2, 1, in); /* read 16 bit value in machines byte order */
+ r = preview_gamma_data_red[r >> rotate16];
+
+ fread(&g, 2, 1, in);
+ g = preview_gamma_data_green[g >> rotate16];
+
+ fread(&b, 2, 1, in);
+ b = preview_gamma_data_blue[b >> rotate16];
+
+ c = r * 65536 + g * 256 + b;
+
+ switch (parameters->rotation)
+ {
+ case 0: /* 0 degree */
+ xx = x + dx;
+ yy = y + dy;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 1: /* 90 degree */
+ xx = maximum_size - y;
+ yy = x + dx;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 2: /* 180 degree */
+ xx = maximum_size - x - dx;
+ yy = maximum_size - y - dy;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 3: /* 270 degree */
+ xx = y + dy;
+ yy = maximum_size - x - dx;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 4: /* 0 degree, x-mirror */
+ xx = maximum_size - x - dx;
+ yy = y + dy;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 5: /* 90 degree, x-mirror */
+ xx = y + dy;
+ yy = x + dx;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 6: /* 180 degree, x-mirror */
+ xx = x + dx;
+ yy = maximum_size - y - dy;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 7: /* 270 degree, x-mirror */
+ xx = maximum_size - y - dy;
+ yy = maximum_size - x - dx;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+ }
+
+ data[offset + 0] = r;
+ data[offset + 1] = g;
+ data[offset + 2] = b;
+ }
+ }
+
+ for (y = 0; y < parameters->gtk_preview_size; y++)
+ {
+ gtk_preview_draw_row(GTK_PREVIEW(parameters->gtk_preview), data + 3 * parameters->gtk_preview_size * y,
+ 0, y, parameters->gtk_preview_size);
+ }
+ }
+ else /* depth = 8 */
+ {
+ for (y=0; y < height; y++)
+ {
+ for (x=0; x < width; x++)
+ {
+ fseek(in, header + (xoffset + (int)(x * scale) + (yoffset + (int)(y * scale)) * image_width) * 3, SEEK_SET);
+
+ r = fgetc(in);
+ r = preview_gamma_data_red[r << rotate8];
+
+ g = fgetc(in);
+ g = preview_gamma_data_green[g << rotate8];
+
+ b = fgetc(in);
+ b = preview_gamma_data_blue[b << rotate8];
+ switch (parameters->rotation)
+ {
+ case 0: /* 0 degree */
+ xx = x + dx;
+ yy = y + dy;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 1: /* 90 degree */
+ xx = maximum_size - y;
+ yy = x + dx;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 2: /* 180 degree */
+ xx = maximum_size - x - dx;
+ yy = maximum_size - y - dy;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 3: /* 270 degree */
+ xx = y + dy;
+ yy = maximum_size - x - dx;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 4: /* 0 degree, x-mirror */
+ xx = maximum_size - x - dx;
+ yy = y + dy;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 5: /* 90 degree, x-mirror */
+ xx = y + dy;
+ yy = x + dx;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 6: /* 180 degree, x-mirror */
+ xx = x + dx;
+ yy = maximum_size - y - dy;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+
+ case 7: /* 270 degree, x-mirror */
+ xx = maximum_size - y - dy;
+ yy = maximum_size - x - dx;
+ offset = parameters->gtk_preview_size * 3 * yy + 3*(xx);
+ break;
+ }
+
+ data[offset + 0] = r;
+ data[offset + 1] = g;
+ data[offset + 2] = b;
+ }
+ }
+
+ for (y = 0; y < parameters->gtk_preview_size; y++)
+ {
+ gtk_preview_draw_row(GTK_PREVIEW(parameters->gtk_preview), data + 3 * parameters->gtk_preview_size * y,
+ 0, y, parameters->gtk_preview_size);
+ }
+ }
+
+ free(data);
+
+ return quality;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void preview_create_batch_icon(Preview *p, Batch_Scan_Parameters *parameters)
+{
+ FILE *in;
+ int quality = 0;
+ int time = 0;
+
+ in = fopen(xsane.preview->filename[0], "rb");
+ quality = preview_create_batch_icon_from_file(xsane.preview, in, parameters, quality, &time);
+
+ if (quality <= 0)
+ {
+ char filename[PATH_MAX];
+
+ if (in)
+ {
+ fclose(in);
+ }
+
+ xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, "xsane-startimage", 0, ".pnm", XSANE_PATH_SYSTEM);
+ in = fopen(filename, "rb"); /* read binary (b for win32) */
+ if (in)
+ {
+ preview_create_batch_icon_from_file(xsane.preview, in, parameters, -1, &time);
+ }
+ }
+ fclose(in);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
static int preview_restore_image_from_file(Preview *p, FILE *in, int min_quality, int *min_time)
{
u_int psurface_type, psurface_unit;
@@ -2202,6 +2497,7 @@ static int preview_restore_image_from_file(Preview *p, FILE *in, int min_quality
yoffset = (dsurface[1] - psurface[1])/(psurface[3] - psurface[1]) * image_height;
width = (dsurface[2] - dsurface[0])/(psurface[2] - psurface[0]) * image_width;
height = (dsurface[3] - dsurface[1])/(psurface[3] - psurface[1]) * image_height;
+
quality = width;
if ((xoffset < 0) || (yoffset < 0) ||
@@ -2397,6 +2693,284 @@ static void preview_restore_image(Preview *p)
/* ---------------------------------------------------------------------------------------------------------------------- */
+static int preview_get_pixel_color(Preview *p, int x, int y, int *raw_red, int *raw_green, int *raw_blue,
+ int *enh_red, int *enh_green, int *enh_blue)
+{
+ int image_x, image_y;
+ int offset;
+ int rotate = 16 - preview_gamma_input_bits;
+
+ DBG(DBG_proc, "preview_get_pixel_color\n");
+
+ if (p->image_data_raw)
+ {
+ preview_transform_coordinate_window_to_image(p, x, y, &image_x, &image_y);
+
+ if ( (image_x >= 0) && (image_x < p->image_width) && (image_y >=0) && (image_y < p->image_height) )
+ {
+ offset = 3 * (image_y * p->image_width + image_x);
+
+ if (!xsane.negative) /* positive */
+ {
+ *raw_red = (p->image_data_raw[offset ]) >> 8;
+ *raw_green = (p->image_data_raw[offset + 1]) >> 8;
+ *raw_blue = (p->image_data_raw[offset + 2]) >> 8;
+ }
+ else /* negative */
+ {
+ *raw_red = 255 - ((p->image_data_raw[offset ]) >> 8);
+ *raw_green = 255 - ((p->image_data_raw[offset + 1]) >> 8);
+ *raw_blue = 255 - ((p->image_data_raw[offset + 2]) >> 8);
+ }
+
+ /* the enhanced pixels are already inverted when negative is selected */
+ /* do not use image_data_enh because the preview gamma value is applied to this */
+ *enh_red = histogram_gamma_data_red [(p->image_data_raw[offset ]) >> rotate];
+ *enh_green = histogram_gamma_data_green[(p->image_data_raw[offset + 1]) >> rotate];
+ *enh_blue = histogram_gamma_data_blue [(p->image_data_raw[offset + 2]) >> rotate];
+
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_swap_int(int *a, int *b)
+{
+ int i;
+ i = *a;
+ *a = *b;
+ *b = i;
+}
+
+static void preview_display_zoom(Preview *p, int x, int y, int zoom)
+{
+ int pointer_x, pointer_y;
+ int image_x, image_y;
+ int image_x_lof, image_x_rof;
+ int image_y_tof, image_y_bof;
+ int image_x_min, image_y_min;
+ int image_x_max, image_y_max;
+ int image_x_direction, image_y_direction;
+ int offset;
+ int r, g, b;
+ int px, py;
+ int i;
+ char *row;
+
+ DBG(DBG_proc, "preview_display_zoom");
+
+ if (!p->image_data_raw)
+ {
+ return;
+ }
+
+ row = calloc(XSANE_ZOOM_SIZE, 3);
+
+ if (row)
+ {
+ preview_transform_coordinate_window_to_image(p, x, y, &image_x, &image_y);
+ preview_transform_coordinate_window_to_image(p, x, y, &pointer_x, &pointer_y);
+
+ image_x_min = image_x - XSANE_ZOOM_SIZE/(zoom*2);
+ image_y_min = image_y - XSANE_ZOOM_SIZE/(zoom*2);
+
+ image_x_max = image_x_min + XSANE_ZOOM_SIZE/zoom + 1;
+ image_y_max = image_y_min + XSANE_ZOOM_SIZE/zoom + 1;
+
+ xsane_bound_int(&image_x_min, 0, p->image_width - 1);
+ xsane_bound_int(&image_x_max, 0, p->image_width - 1);
+ xsane_bound_int(&image_y_min, 0, p->image_height - 1);
+ xsane_bound_int(&image_y_max, 0, p->image_height - 1);
+
+ if ((image_x_max - image_x_min) && (image_y_max - image_y_min))
+ {
+ image_x_lof = image_x_min - (image_x - XSANE_ZOOM_SIZE/(zoom*2));
+ image_x_rof = image_x - XSANE_ZOOM_SIZE/(zoom*2) + XSANE_ZOOM_SIZE/zoom + 1 - image_x_max;
+ image_y_tof = image_y_min - (image_y - XSANE_ZOOM_SIZE/(zoom*2));
+ image_y_bof = image_y - XSANE_ZOOM_SIZE/(zoom*2) + XSANE_ZOOM_SIZE/zoom + 1 - image_y_max;
+
+ image_x_direction = 1;
+ image_y_direction = 1;
+
+ switch (p->rotation & 3)
+ {
+ case 0: /* do not rotate - 0 degree */
+ default:
+ break;
+
+ case 1: /* 90 degree */
+ xsane_swap_int(&image_y_min, &image_y_max);
+ xsane_swap_int(&image_y_tof, &image_y_bof);
+ image_y_direction *= -1;
+ break;
+
+ case 2: /* 180 degree */
+ xsane_swap_int(&image_x_min, &image_x_max);
+ xsane_swap_int(&image_x_lof, &image_x_rof);
+ xsane_swap_int(&image_y_min, &image_y_max);
+ xsane_swap_int(&image_y_tof, &image_y_bof);
+ image_x_direction *= -1;
+ image_y_direction *= -1;
+ break;
+
+ case 3: /* 270 degree */
+ xsane_swap_int(&image_x_min, &image_x_max);
+ xsane_swap_int(&image_x_lof, &image_x_rof);
+ image_x_direction *= -1;
+ break;
+ }
+
+
+ if ((p->rotation & 1) == 0)
+ {
+ if (p->rotation & 4) /* mirror */
+ {
+ xsane_swap_int(&image_x_min, &image_x_max);
+ xsane_swap_int(&image_x_lof, &image_x_rof);
+ image_x_direction *= -1;
+ }
+
+ py = image_y_tof * zoom;
+
+ for (i=0; i < py; i++)
+ {
+ gtk_preview_draw_row(GTK_PREVIEW(p->zoom), row, 0, i, XSANE_ZOOM_SIZE);
+ }
+
+ for (image_y = image_y_min; image_y != image_y_max + image_y_direction; image_y += image_y_direction)
+ {
+ px = image_x_lof * zoom;
+
+ for (image_x = image_x_min; image_x != image_x_max + image_x_direction; image_x += image_x_direction)
+ {
+ offset = 3 * (image_y * p->image_width + image_x);
+
+ r = (p->image_data_enh[offset ]);
+ g = (p->image_data_enh[offset+1]);
+ b = (p->image_data_enh[offset+2]);
+
+ if ( (image_x == pointer_x) && (image_y == pointer_y) )
+ {
+ r = g = b = (128 + (r+g+b) / 3) & 255; /* mark the cursor position */
+ }
+
+ for (i=0; (i<zoom) && (px < XSANE_ZOOM_SIZE); i++)
+ {
+ row[px*3+0] = r;
+ row[px*3+1] = g;
+ row[px*3+2] = b;
+ px++;
+ }
+ }
+
+ for (i=0; (i<zoom) && (py < XSANE_ZOOM_SIZE); i++)
+ {
+ gtk_preview_draw_row(GTK_PREVIEW(p->zoom), row, 0, py++, XSANE_ZOOM_SIZE);
+ }
+ }
+ }
+ else /* swap x and y */
+ {
+ if (p->rotation & 4) /* mirror */
+ {
+ xsane_swap_int(&image_y_min, &image_y_max);
+ xsane_swap_int(&image_y_tof, &image_y_bof);
+ image_y_direction *= -1;
+ }
+
+ py = image_x_lof * zoom;
+
+ for (i=0; i < py; i++)
+ {
+ gtk_preview_draw_row(GTK_PREVIEW(p->zoom), row, 0, i, XSANE_ZOOM_SIZE);
+ }
+
+ for (image_x = image_x_min; image_x != image_x_max + image_x_direction; image_x += image_x_direction)
+ {
+ px = image_y_tof * zoom;
+
+ for (image_y = image_y_min; image_y != image_y_max + image_y_direction; image_y += image_y_direction)
+ {
+ offset = 3 * (image_y * p->image_width + image_x);
+
+ r = (p->image_data_enh[offset ]);
+ g = (p->image_data_enh[offset+1]);
+ b = (p->image_data_enh[offset+2]);
+
+ if ( (image_x == pointer_x) && (image_y == pointer_y) )
+ {
+ r = g = b = (128 + (r+g+b) / 3) & 255; /* mark the cursor position */
+ }
+
+ for (i=0; (i<zoom) && (px < XSANE_ZOOM_SIZE); i++)
+ {
+ row[px*3+0] = r;
+ row[px*3+1] = g;
+ row[px*3+2] = b;
+ px++;
+ }
+ }
+
+ for (i=0; (i<zoom) && (py < XSANE_ZOOM_SIZE); i++)
+ {
+ gtk_preview_draw_row(GTK_PREVIEW(p->zoom), row, 0, py++, XSANE_ZOOM_SIZE);
+ }
+ }
+ }
+
+ for (i=0; i < XSANE_ZOOM_SIZE; i++)
+ {
+ row[i*3+0] = 0;
+ row[i*3+1] = 0;
+ row[i*3+2] = 0;
+ }
+
+ for (i=py; i < XSANE_ZOOM_SIZE; i++)
+ {
+ gtk_preview_draw_row(GTK_PREVIEW(p->zoom), row, 0, i, XSANE_ZOOM_SIZE);
+ }
+ }
+ else
+ {
+ for (i = 0; i < XSANE_ZOOM_SIZE; i++)
+ {
+ gtk_preview_draw_row(GTK_PREVIEW(p->zoom), row, 0, i, XSANE_ZOOM_SIZE);
+ }
+ }
+ gtk_widget_queue_draw(p->zoom);
+
+ free(row);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void preview_display_color_components(Preview *p, int x, int y)
+{
+ char buffer[256];
+ int raw_red, raw_green, raw_blue, enh_red, enh_green, enh_blue;
+
+ if (! preview_get_pixel_color(p, x, y, &raw_red, &raw_green, &raw_blue, &enh_red, &enh_green, &enh_blue))
+ {
+ snprintf(buffer, sizeof(buffer), " %03d, %03d, %03d \n" \
+ " %03d, %03d, %03d ",
+ raw_red, raw_green, raw_blue, enh_red, enh_green, enh_blue);
+ }
+ else
+ {
+ snprintf(buffer, sizeof(buffer), " ###, ###, ### \n" \
+ " ###, ###, ### ");
+ }
+
+ gtk_label_set_text(GTK_LABEL(p->rgb_label), buffer);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
static gint preview_hold_event_handler(gpointer data)
{
Preview *p = data;
@@ -2437,6 +3011,9 @@ static gint preview_motion_event_handler(GtkWidget *window, GdkEvent *event, gpo
if (!p->scanning)
{
+ preview_display_zoom(p, event->motion.x, event->motion.y, XSANE_ZOOM_FACTOR);
+ preview_display_color_components(p, event->motion.x, event->motion.y);
+
switch (((GdkEventMotion *)event)->state &
GDK_Num_Lock & GDK_Caps_Lock & GDK_Shift_Lock & GDK_Scroll_Lock) /* mask all Locks */
{
@@ -2447,8 +3024,159 @@ static gint preview_motion_event_handler(GtkWidget *window, GdkEvent *event, gpo
if ( (p->selection_drag) || (p->selection_drag_edge) )
{
p->selection.active = TRUE;
- p->selection.coordinate[p->selection_xedge] = preview_x;
- p->selection.coordinate[p->selection_yedge] = preview_y;
+
+ if (preview_x < p->scanner_surface[p->index_xmin])
+ {
+ preview_x = p->scanner_surface[p->index_xmin];
+ }
+ else if (preview_x > p->scanner_surface[p->index_xmax])
+ {
+ preview_x = p->scanner_surface[p->index_xmax];
+ }
+
+ if (preview_y < p->scanner_surface[p->index_ymin])
+ {
+ preview_y = p->scanner_surface[p->index_ymin];
+ }
+ else if (preview_y > p->scanner_surface[p->index_ymax])
+ {
+ preview_y = p->scanner_surface[p->index_ymax];
+ }
+
+
+ if (p->selection_xedge != -1)
+ {
+ p->selection.coordinate[p->selection_xedge] = preview_x;
+ }
+
+ if (p->selection_yedge != -1)
+ {
+ p->selection.coordinate[p->selection_yedge] = preview_y;
+ }
+
+ if (p->ratio) /* forced preview ratio ? */
+ {
+ if ( (p->selection_xedge == p->index_xmin) && (p->selection_yedge == p->index_ymin) ) /* top left corner */
+ {
+ float width;
+ width = fabs(p->selection.coordinate[p->index_xmax] - p->selection.coordinate[p->index_xmin]);
+
+ p->selection.coordinate[p->index_ymax] = p->selection.coordinate[p->index_ymin] + width / p->ratio;
+
+ if (p->selection.coordinate[p->index_ymax] > p->scanner_surface[p->index_ymax])
+ {
+ float height;
+ p->selection.coordinate[p->index_ymax] = p->scanner_surface[p->index_ymax];
+ height = fabs(p->selection.coordinate[p->index_ymax] - p->selection.coordinate[p->index_ymin]);
+ p->selection.coordinate[p->index_xmin] = p->selection.coordinate[p->index_xmax] - height * p->ratio;
+ }
+ }
+ else if ( (p->selection_xedge == p->index_xmax) && (p->selection_yedge == p->index_ymin) )/* top right corner */
+ {
+ float width;
+ width = fabs(p->selection.coordinate[p->index_xmax] - p->selection.coordinate[p->index_xmin]);
+
+ p->selection.coordinate[p->index_ymax] = p->selection.coordinate[p->index_ymin] + width / p->ratio;
+
+ if (p->selection.coordinate[p->index_ymax] > p->scanner_surface[p->index_ymax])
+ {
+ float height;
+ p->selection.coordinate[p->index_ymax] = p->scanner_surface[p->index_ymax];
+ height = fabs(p->selection.coordinate[p->index_ymax] - p->selection.coordinate[p->index_ymin]);
+ p->selection.coordinate[p->index_xmax] = p->selection.coordinate[p->index_xmin] + height * p->ratio;
+ }
+ }
+ else if ( (p->selection_xedge == p->index_xmin) && (p->selection_yedge == p->index_ymax) ) /* bottom left edge */
+ {
+ float width;
+ width = fabs(p->selection.coordinate[p->index_xmax] - p->selection.coordinate[p->index_xmin]);
+
+ p->selection.coordinate[p->index_ymin] = p->selection.coordinate[p->index_ymax] - width / p->ratio;
+
+ if (p->selection.coordinate[p->index_ymin] < p->scanner_surface[p->index_ymin])
+ {
+ float height;
+ p->selection.coordinate[p->index_ymin] = p->scanner_surface[p->index_ymin];
+ height = fabs(p->selection.coordinate[p->index_ymax] - p->selection.coordinate[p->index_ymin]);
+ p->selection.coordinate[p->index_xmin] = p->selection.coordinate[p->index_xmax] - height * p->ratio;
+ }
+ }
+ else if ( (p->selection_xedge == p->index_xmax) && (p->selection_yedge == p->index_ymax) ) /* bottom right edge */
+ {
+ float width;
+ width = fabs(p->selection.coordinate[p->index_xmax] - p->selection.coordinate[p->index_xmin]);
+
+ p->selection.coordinate[p->index_ymin] = p->selection.coordinate[p->index_ymax] - width / p->ratio;
+
+ if (p->selection.coordinate[p->index_ymin] < p->scanner_surface[p->index_ymin])
+ {
+ float height;
+ p->selection.coordinate[p->index_ymin] = p->scanner_surface[p->index_ymin];
+ height = fabs(p->selection.coordinate[p->index_ymax] - p->selection.coordinate[p->index_ymin]);
+ p->selection.coordinate[p->index_xmax] = p->selection.coordinate[p->index_xmin] + height * p->ratio;
+ }
+ }
+ else if (p->selection_xedge == p->index_xmin) /* left edge */
+ {
+ float width;
+ width = fabs(p->selection.coordinate[p->index_xmax] - p->selection.coordinate[p->index_xmin]);
+
+ p->selection.coordinate[p->index_ymax] = p->selection.coordinate[p->index_ymin] + width / p->ratio;
+
+ if (p->selection.coordinate[p->index_ymax] > p->scanner_surface[p->index_ymax])
+ {
+ float height;
+ p->selection.coordinate[p->index_ymax] = p->scanner_surface[p->index_ymax];
+ height = fabs(p->selection.coordinate[p->index_ymax] - p->selection.coordinate[p->index_ymin]);
+ p->selection.coordinate[p->index_xmin] = p->selection.coordinate[p->index_xmax] - height * p->ratio;
+ }
+ }
+ else if (p->selection_xedge == p->index_xmax) /* right edge */
+ {
+ float width;
+ width = fabs(p->selection.coordinate[p->index_xmax] - p->selection.coordinate[p->index_xmin]);
+
+ p->selection.coordinate[p->index_ymax] = p->selection.coordinate[p->index_ymin] + width / p->ratio;
+
+ if (p->selection.coordinate[p->index_ymax] > p->scanner_surface[p->index_ymax])
+ {
+ float height;
+ p->selection.coordinate[p->index_ymax] = p->scanner_surface[p->index_ymax];
+ height = fabs(p->selection.coordinate[p->index_ymax] - p->selection.coordinate[p->index_ymin]);
+ p->selection.coordinate[p->index_xmax] = p->selection.coordinate[p->index_xmin] + height * p->ratio;
+ }
+ }
+ else if (p->selection_yedge == p->index_ymin) /* top edge */
+ {
+ float height;
+ height = fabs(p->selection.coordinate[p->index_ymax] - p->selection.coordinate[p->index_ymin]);
+
+ p->selection.coordinate[p->index_xmax] = p->selection.coordinate[p->index_xmin] + height * p->ratio;
+
+ if (p->selection.coordinate[p->index_xmax] > p->scanner_surface[p->index_xmax])
+ {
+ float width;
+ p->selection.coordinate[p->index_xmax] = p->scanner_surface[p->index_xmax];
+ width = fabs(p->selection.coordinate[p->index_xmax] - p->selection.coordinate[p->index_xmin]);
+ p->selection.coordinate[p->index_ymin] = p->selection.coordinate[p->index_ymax] - width / p->ratio;
+ }
+ }
+ else if (p->selection_yedge == p->index_ymax) /* bottom edge */
+ {
+ float height;
+ height = fabs(p->selection.coordinate[p->index_ymax] - p->selection.coordinate[p->index_ymin]);
+
+ p->selection.coordinate[p->index_xmax] = p->selection.coordinate[p->index_xmin] + height * p->ratio;
+
+ if (p->selection.coordinate[p->index_xmax] > p->scanner_surface[p->index_xmax])
+ {
+ float width;
+ p->selection.coordinate[p->index_xmax] = p->scanner_surface[p->index_xmax];
+ width = fabs(p->selection.coordinate[p->index_xmax] - p->selection.coordinate[p->index_xmin]);
+ p->selection.coordinate[p->index_ymax] = p->selection.coordinate[p->index_ymin] + width / p->ratio;
+ }
+ }
+ }
preview_order_selection(p);
preview_bound_selection(p);
@@ -2551,7 +3279,7 @@ static gint preview_motion_event_handler(GtkWidget *window, GdkEvent *event, gpo
{
cursor = gdk_cursor_new(cursornr); /* set curosr */
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = cursornr;
}
break;
@@ -2727,7 +3455,7 @@ static gint preview_motion_event_handler(GtkWidget *window, GdkEvent *event, gpo
{
cursor = gdk_cursor_new(cursornr); /* set curosr */
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = cursornr;
}
break;
@@ -2842,7 +3570,7 @@ static gint preview_button_press_event_handler(GtkWidget *window, GdkEvent *even
cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW);
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = XSANE_CURSOR_PREVIEW;
}
break;
@@ -2947,7 +3675,7 @@ static gint preview_button_press_event_handler(GtkWidget *window, GdkEvent *even
cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW);
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = XSANE_CURSOR_PREVIEW;
}
break;
@@ -3037,11 +3765,51 @@ static gint preview_button_press_event_handler(GtkWidget *window, GdkEvent *even
cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW);
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
+ p->cursornr = XSANE_CURSOR_PREVIEW;
+ }
+ break;
+
+ case MODE_AUTORAISE_SCANAREA:
+ {
+ DBG(DBG_info, "autoraise scanarea mode\n");
+
+ if ( ( (((GdkEventButton *)event)->button == 1) || (((GdkEventButton *)event)->button == 2) ) &&
+ (p->image_data_raw) ) /* left or middle button */
+ {
+ preview_autoraise_scanarea(p, event->button.x, event->button.y, p->selection.coordinate); /* raise selection area */
+ }
+
+ p->mode = MODE_NORMAL;
+
+ cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW);
+ gdk_window_set_cursor(p->window->window, cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = XSANE_CURSOR_PREVIEW;
}
break;
+ case MODE_ZOOM_IN:
+ {
+ DBG(DBG_info, "zoom in mode\n");
+
+ if ( ( (((GdkEventButton *)event)->button == 1) || (((GdkEventButton *)event)->button == 2) ) &&
+ (p->image_data_raw) ) /* left or middle button */
+ {
+ preview_select_zoom_point(p, event->button.x, event->button.y); /* select zoom point */
+ }
+ else
+ {
+ p->mode = MODE_NORMAL;
+
+ cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW);
+ gdk_window_set_cursor(p->window->window, cursor);
+ gdk_cursor_unref(cursor);
+ p->cursornr = XSANE_CURSOR_PREVIEW;
+ }
+ }
+ break;
+
case MODE_NORMAL:
{
DBG(DBG_info, "normal mode\n");
@@ -3117,7 +3885,7 @@ static gint preview_button_press_event_handler(GtkWidget *window, GdkEvent *even
cursornr = GDK_CROSS;
cursor = gdk_cursor_new(cursornr); /* set curosr */
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = cursornr;
}
break;
@@ -3139,7 +3907,7 @@ static gint preview_button_press_event_handler(GtkWidget *window, GdkEvent *even
cursornr = GDK_HAND2;
cursor = gdk_cursor_new(cursornr); /* set curosr */
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = cursornr;
}
break;
@@ -3184,7 +3952,7 @@ static gint preview_button_release_event_handler(GtkWidget *window, GdkEvent *ev
cursornr = XSANE_CURSOR_PREVIEW;
cursor = gdk_cursor_new(cursornr); /* set curosr */
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = cursornr;
}
@@ -3220,7 +3988,7 @@ static gint preview_expose_event_handler_start(GtkWidget *window, GdkEvent *even
if (!p->gc_selection)
{
DBG(DBG_info, "defining line styles for selection and page frames\n");
- colormap = gdk_window_get_colormap(p->window->window);
+ colormap = gdk_drawable_get_colormap(p->window->window);
p->gc_selection = gdk_gc_new(p->window->window);
gdk_gc_set_function(p->gc_selection, GDK_INVERT);
@@ -3265,7 +4033,7 @@ static gint preview_expose_event_handler_end(GtkWidget *window, GdkEvent *event,
if (!p->gc_selection)
{
DBG(DBG_info, "defining line styles for selection and page frames\n");
- colormap = gdk_window_get_colormap(p->window->window);
+ colormap = gdk_drawable_get_colormap(p->window->window);
p->gc_selection = gdk_gc_new(p->window->window);
gdk_gc_set_function(p->gc_selection, GDK_INVERT);
@@ -3283,8 +4051,8 @@ static gint preview_expose_event_handler_end(GtkWidget *window, GdkEvent *event,
}
else
{
- p->selection.active = expose_event_selection_active;
- p->selection_maximum.active = expose_event_selection_maximum_active;
+ p->selection.active = expose_event_selection_active;
+ p->selection_maximum.active = expose_event_selection_maximum_active;
preview_draw_selection(p); /* draw selections again */
}
}
@@ -3335,8 +4103,8 @@ static void preview_create_preset_area_menu(Preview *p, int selection)
{
preset_area_item = gtk_menu_item_new_with_label(preferences.preset_area[i]->name);
gtk_container_add(GTK_CONTAINER(preset_area_menu), preset_area_item);
- gtk_signal_connect(GTK_OBJECT(preset_area_item), "button_press_event", (GtkSignalFunc) preview_preset_area_context_menu_callback, p);
- gtk_signal_connect(GTK_OBJECT(preset_area_item), "activate", (GtkSignalFunc) preview_preset_area_callback, p);
+ g_signal_connect(GTK_OBJECT(preset_area_item), "button_press_event", (GtkSignalFunc) preview_preset_area_context_menu_callback, p);
+ g_signal_connect(GTK_OBJECT(preset_area_item), "activate", (GtkSignalFunc) preview_preset_area_callback, p);
gtk_object_set_data(GTK_OBJECT(preset_area_item), "Selection", (void *) i);
gtk_object_set_data(GTK_OBJECT(preset_area_item), "Preview", (void *) p);
@@ -3410,16 +4178,20 @@ Preview *preview_new(void)
GtkWidget *table, *frame;
GtkSignalFunc signal_func;
GtkWidgetClass *class;
- GtkWidget *vbox, *hbox;
+ GtkWidget *vbox, *action_box;
+ GtkWidget *outer_hbox, *middle_vbox;
GdkCursor *cursor;
GtkWidget *preset_area_option_menu;
GtkWidget *rotation_option_menu, *rotation_menu, *rotation_item;
+ GtkWidget *ratio_option_menu, *ratio_menu, *ratio_item;
GtkWidget *delete_images;
GdkBitmap *mask;
GdkPixmap *pixmap = NULL;
+ GtkWidget *pixmapwidget;
Preview *p;
int i;
char buf[256];
+ int ratio_nr = 0;
DBG(DBG_proc, "preview_new\n");
@@ -3468,12 +4240,14 @@ Preview *preview_new(void)
p->maximum_output_width = INF; /* full output with */
p->maximum_output_height = INF; /* full output height */
+ p->block_update_maximum_output_size_clipping = FALSE;
p->preview_colors = -1;
p->invalid = TRUE; /* no valid preview */
+ p->ratio = 0.0;
#ifndef XSERVER_WITH_BUGGY_VISUALS
- gtk_widget_push_visual(gtk_preview_get_visual());
+ gtk_widget_push_visual(gtk_preview_get_visual()); /* this has no function for gtk+-2.0 */
#endif
gtk_widget_push_colormap(gtk_preview_get_cmap());
@@ -3481,7 +4255,8 @@ Preview *preview_new(void)
p->top = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(p->top), buf);
xsane_set_window_icon(p->top, 0);
- gtk_accel_group_attach(xsane.accelerator_group, GTK_OBJECT(p->top));
+ gtk_window_add_accel_group(GTK_WINDOW(p->top), xsane.accelerator_group);
+
/* set the main vbox */
vbox = gtk_vbox_new(FALSE, 0);
@@ -3489,39 +4264,51 @@ Preview *preview_new(void)
gtk_container_add(GTK_CONTAINER(p->top), vbox);
gtk_widget_show(vbox);
- /* set the main hbox */
- hbox = gtk_hbox_new(FALSE, 0);
- gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
- gtk_widget_show(hbox);
- /* top hbox for icons */
+ /* the button_box (hbox) */
p->button_box = gtk_hbox_new(FALSE, 1);
- gtk_container_set_border_width(GTK_CONTAINER(p->button_box), 1);
+ gtk_container_set_border_width(GTK_CONTAINER(p->button_box), 0);
gtk_box_pack_start(GTK_BOX(vbox), p->button_box, FALSE, FALSE, 0);
+
+ /* add new selection for batch scanning */
+ p->add_batch = xsane_button_new_with_pixmap(p->top->window, p->button_box, add_batch_xpm, DESC_ADD_BATCH, (GtkSignalFunc) preview_add_batch, p);
+
+ xsane_vseparator_new(p->button_box, 3);
+
/* White, gray and black pipette button */
p->pipette_white = xsane_button_new_with_pixmap(p->top->window, p->button_box, pipette_white_xpm, DESC_PIPETTE_WHITE, (GtkSignalFunc) preview_pipette_white, p);
p->pipette_gray = xsane_button_new_with_pixmap(p->top->window, p->button_box, pipette_gray_xpm, DESC_PIPETTE_GRAY, (GtkSignalFunc) preview_pipette_gray, p);
p->pipette_black = xsane_button_new_with_pixmap(p->top->window, p->button_box, pipette_black_xpm, DESC_PIPETTE_BLACK, (GtkSignalFunc) preview_pipette_black, p);
+ xsane_vseparator_new(p->button_box, 3);
+
/* Zoom not, zoom out and zoom in button */
- p->zoom_not = xsane_button_new_with_pixmap(p->top->window, p->button_box, zoom_not_xpm, DESC_ZOOM_FULL, (GtkSignalFunc) preview_zoom_not, p);
- p->zoom_out = xsane_button_new_with_pixmap(p->top->window, p->button_box, zoom_out_xpm, DESC_ZOOM_OUT, (GtkSignalFunc) preview_zoom_out, p);
- p->zoom_in = xsane_button_new_with_pixmap(p->top->window, p->button_box, zoom_in_xpm, DESC_ZOOM_IN, (GtkSignalFunc) preview_zoom_in, p);
- p->zoom_undo = xsane_button_new_with_pixmap(p->top->window, p->button_box, zoom_undo_xpm, DESC_ZOOM_UNDO, (GtkSignalFunc) preview_zoom_undo, p);
- p->full_area = xsane_button_new_with_pixmap(p->top->window, p->button_box, auto_select_preview_area_xpm, DESC_AUTOSELECT_SCANAREA, (GtkSignalFunc) preview_autoselect_scanarea_callback, p);
- p->autoselect = xsane_button_new_with_pixmap(p->top->window, p->button_box, full_preview_area_xpm, DESC_FULL_PREVIEW_AREA, (GtkSignalFunc) preview_full_preview_area_callback, p);
- delete_images = xsane_button_new_with_pixmap(p->top->window, p->button_box, delete_images_xpm, DESC_DELETE_IMAGES, (GtkSignalFunc) preview_delete_images_callback, p);
-
- gtk_widget_add_accelerator(p->zoom_not, "clicked", xsane.accelerator_group, GDK_KP_Multiply, GDK_MOD1_MASK, GTK_ACCEL_LOCKED); /* Alt keypad_* */
- gtk_widget_add_accelerator(p->zoom_out, "clicked", xsane.accelerator_group, GDK_KP_Subtract, GDK_MOD1_MASK, GTK_ACCEL_LOCKED); /* Alt keypad_- */
- gtk_widget_add_accelerator(p->zoom_in, "clicked", xsane.accelerator_group, GDK_KP_Add, GDK_MOD1_MASK, GTK_ACCEL_LOCKED); /* Alt keypad_+ */
- gtk_widget_add_accelerator(p->zoom_undo, "clicked", xsane.accelerator_group, GDK_KP_Divide, GDK_MOD1_MASK, GTK_ACCEL_LOCKED); /* Alt keypad_/ */
- gtk_widget_add_accelerator(p->full_area, "clicked", xsane.accelerator_group, GDK_A, GDK_MOD1_MASK, GTK_ACCEL_LOCKED); /* Alt keypad_* */
- gtk_widget_add_accelerator(p->autoselect, "clicked", xsane.accelerator_group, GDK_V, GDK_MOD1_MASK, GTK_ACCEL_LOCKED); /* Alt keypad_* */
- gtk_widget_add_accelerator(delete_images, "clicked", xsane.accelerator_group, GDK_KP_Delete, GDK_MOD1_MASK, GTK_ACCEL_LOCKED); /* Alt keypad_* */
+ p->zoom_not = xsane_button_new_with_pixmap(p->top->window, p->button_box, zoom_not_xpm, DESC_ZOOM_FULL, (GtkSignalFunc) preview_zoom_not, p);
+ p->zoom_out = xsane_button_new_with_pixmap(p->top->window, p->button_box, zoom_out_xpm, DESC_ZOOM_OUT, (GtkSignalFunc) preview_zoom_out, p);
+ p->zoom_in = xsane_button_new_with_pixmap(p->top->window, p->button_box, zoom_in_xpm, DESC_ZOOM_IN, (GtkSignalFunc) preview_zoom_in, p);
+ p->zoom_area = xsane_button_new_with_pixmap(p->top->window, p->button_box, zoom_area_xpm, DESC_ZOOM_AREA, (GtkSignalFunc) preview_zoom_area, p);
+ p->zoom_undo = xsane_button_new_with_pixmap(p->top->window, p->button_box, zoom_undo_xpm, DESC_ZOOM_UNDO, (GtkSignalFunc) preview_zoom_undo, p);
+
+ xsane_vseparator_new(p->button_box, 3);
+
+ p->full_area = xsane_button_new_with_pixmap(p->top->window, p->button_box, auto_select_preview_area_xpm, DESC_AUTOSELECT_SCANAREA, (GtkSignalFunc) preview_autoselect_scanarea_callback, p);
+ p->autoraise = xsane_button_new_with_pixmap(p->top->window, p->button_box, auto_raise_preview_area_xpm, DESC_AUTORAISE_SCANAREA, (GtkSignalFunc) preview_init_autoraise_scanarea, p);
+ p->autoselect = xsane_button_new_with_pixmap(p->top->window, p->button_box, full_preview_area_xpm, DESC_FULL_PREVIEW_AREA, (GtkSignalFunc) preview_full_preview_area_callback, p);
+
+ xsane_vseparator_new(p->button_box, 3);
+
+ delete_images = xsane_button_new_with_pixmap(p->top->window, p->button_box, delete_images_xpm, DESC_DELETE_IMAGES, (GtkSignalFunc) preview_delete_images_callback, p);
+
+ gtk_widget_add_accelerator(p->zoom_not, "clicked", xsane.accelerator_group, GDK_KP_Multiply, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt keypad_* */
+ gtk_widget_add_accelerator(p->zoom_out, "clicked", xsane.accelerator_group, GDK_KP_Subtract, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt keypad_- */
+ gtk_widget_add_accelerator(p->zoom_in, "clicked", xsane.accelerator_group, GDK_KP_Add, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt keypad_+ */
+ gtk_widget_add_accelerator(p->zoom_area, "clicked", xsane.accelerator_group, GDK_KP_Enter, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt keypad_Enter */
+ gtk_widget_add_accelerator(p->zoom_undo, "clicked", xsane.accelerator_group, GDK_KP_Divide, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt keypad_/ */
+ gtk_widget_add_accelerator(p->full_area, "clicked", xsane.accelerator_group, GDK_A, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt keypad_* */
+ gtk_widget_add_accelerator(p->autoselect, "clicked", xsane.accelerator_group, GDK_V, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt keypad_* */
+ gtk_widget_add_accelerator(delete_images, "clicked", xsane.accelerator_group, GDK_KP_Delete, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt keypad_* */
gtk_widget_set_sensitive(p->zoom_not, FALSE); /* no zoom at this point, so no zoom not */
gtk_widget_set_sensitive(p->zoom_out, FALSE); /* no zoom at this point, so no zoom out */
@@ -3530,42 +4317,157 @@ Preview *preview_new(void)
gtk_widget_set_sensitive(p->autoselect, FALSE); /* no selection */
+ gtk_widget_show(p->button_box);
+ /* the button box is ready */
+
+
+
+ /* construct the preview area (table with sliders & preview window) */
+
+ table = gtk_table_new(2, 2, /* homogeneous */ FALSE);
+ gtk_table_set_col_spacing(GTK_TABLE(table), 0, 1);
+ gtk_table_set_row_spacing(GTK_TABLE(table), 0, 1);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 1);
+ gtk_box_pack_start(GTK_BOX(vbox), table, /* expand */ TRUE, /* fill */ TRUE, /* padding */ 0);
+ gtk_widget_show(table);
+
+ /* the empty box in the top-left corner */
+ frame = gtk_frame_new(/* label */ 0);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
+ gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_widget_show(frame);
+
+ /* the unit label */
+ p->unit_label = gtk_label_new("cm");
+ gtk_container_add(GTK_CONTAINER(frame), p->unit_label);
+ gtk_widget_show(p->unit_label);
+
+ /* the horizontal ruler */
+ p->hruler = gtk_hruler_new();
+ gtk_table_attach(GTK_TABLE(table), p->hruler, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
+ gtk_widget_show(p->hruler);
+
+ /* the vertical ruler */
+ p->vruler = gtk_vruler_new();
+ gtk_table_attach(GTK_TABLE(table), p->vruler, 0, 1, 1, 2, 0, GTK_FILL, 0, 0);
+ gtk_widget_show(p->vruler);
+
+ /* the preview area */
+ p->window = gtk_preview_new(GTK_PREVIEW_COLOR);
+ gtk_preview_set_expand(GTK_PREVIEW(p->window), TRUE);
+
+ gtk_widget_set_events(p->window, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
+
+ /* the first expose_event is responsible to undraw the selection frame */
+ g_signal_connect(GTK_OBJECT(p->window), "expose_event", (GtkSignalFunc) preview_expose_event_handler_start, p);
+ g_signal_connect(GTK_OBJECT(p->window), "button_press_event", (GtkSignalFunc) preview_button_press_event_handler, p);
+ g_signal_connect(GTK_OBJECT(p->window), "motion_notify_event", (GtkSignalFunc) preview_motion_event_handler, p);
+ g_signal_connect(GTK_OBJECT(p->window), "button_release_event", (GtkSignalFunc) preview_button_release_event_handler, p);
+
+ g_signal_connect_after(GTK_OBJECT(p->window), "size_allocate", (GtkSignalFunc) preview_area_resize_handler, p);
+ /* the second expose_event is responsible to redraw the selection frame */
+ g_signal_connect_after(GTK_OBJECT(p->window), "expose_event", (GtkSignalFunc) preview_expose_event_handler_end, p);
+
+ /* Connect the motion-notify events of the preview area with the rulers. Nifty stuff! */
+
+#ifdef HAVE_GTK2
+ class = (GtkWidgetClass *) GTK_HSCROLLBAR_GET_CLASS(p->hruler);
+#else
+ class = GTK_WIDGET_CLASS(GTK_OBJECT(p->hruler)->klass);
+#endif
+
+ signal_func = (GtkSignalFunc) class->motion_notify_event;
+ g_signal_connect_swapped(GTK_OBJECT(p->window), "motion_notify_event", signal_func, GTK_OBJECT(p->hruler));
+
+#ifdef HAVE_GTK2
+ class = (GtkWidgetClass *) GTK_VSCROLLBAR_GET_CLASS(p->vruler);
+#else
+ class = GTK_WIDGET_CLASS(GTK_OBJECT(p->vruler)->klass);
+#endif
+
+ signal_func = (GtkSignalFunc) class->motion_notify_event;
+ g_signal_connect_swapped(GTK_OBJECT(p->window), "motion_notify_event", signal_func, GTK_OBJECT(p->vruler));
+
+
+ p->viewport = gtk_frame_new(/* label */ 0);
+ gtk_frame_set_shadow_type(GTK_FRAME(p->viewport), GTK_SHADOW_IN);
+ gtk_container_add(GTK_CONTAINER(p->viewport), p->window);
+ gtk_widget_show(p->viewport);
+
+ gtk_table_attach(GTK_TABLE(table), p->viewport, 1, 2, 1, 2,
+ GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
+ /* the preview area is ready */
+
+
+
+ /* the outer hbox at the bottom */
+ outer_hbox = gtk_hbox_new(FALSE, 4);
+ gtk_container_set_border_width(GTK_CONTAINER(outer_hbox), 1);
+ gtk_box_pack_start(GTK_BOX(vbox), outer_hbox, FALSE, FALSE, 0);
+ gtk_widget_show(outer_hbox);
+
+ /* the middle vbox at the bottom */
+ middle_vbox = gtk_vbox_new(FALSE, 4);
+ gtk_container_set_border_width(GTK_CONTAINER(middle_vbox), 1);
+ gtk_box_pack_start(GTK_BOX(outer_hbox), middle_vbox, FALSE, FALSE, 0);
+ gtk_widget_show(middle_vbox);
+
+ /* the menu_box (hbox) */
+ p->menu_box = gtk_hbox_new(FALSE, 4);
+ gtk_container_set_border_width(GTK_CONTAINER(p->menu_box), 1);
+ gtk_box_pack_start(GTK_BOX(middle_vbox), p->menu_box, FALSE, FALSE, 0);
+
+ xsane_separator_new(middle_vbox, 1);
+
+
/* select maximum scanarea */
+ pixmap = gdk_pixmap_create_from_xpm_d(p->top->window, &mask, xsane.bg_trans, (gchar **) size_xpm);
+ pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(p->menu_box), pixmapwidget, FALSE, FALSE, 2);
+ gtk_widget_show(pixmapwidget);
+ gdk_drawable_unref(pixmap);
preset_area_option_menu = gtk_option_menu_new();
xsane_back_gtk_set_tooltip(xsane.tooltips, preset_area_option_menu, DESC_PRESET_AREA);
- gtk_box_pack_start(GTK_BOX(p->button_box), preset_area_option_menu, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(p->menu_box), preset_area_option_menu, FALSE, FALSE, 0);
gtk_widget_show(preset_area_option_menu);
p->preset_area_option_menu = preset_area_option_menu;
preview_create_preset_area_menu(p, 0); /* build menu and set default to 0=full size */
+ xsane_vseparator_new(p->menu_box, 3);
/* select rotation */
+ pixmap = gdk_pixmap_create_from_xpm_d(p->top->window, &mask, xsane.bg_trans, (gchar **) rotation_xpm);
+ pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(p->menu_box), pixmapwidget, FALSE, FALSE, 2);
+ gtk_widget_show(pixmapwidget);
+ gdk_drawable_unref(pixmap);
+
rotation_menu = gtk_menu_new();
for (i = 0; i < 12; ++i)
{
- char buffer[256];
int rot;
if (i<4)
{
- snprintf(buffer, sizeof(buffer), "%03d ", i*90);
+ snprintf(buf, sizeof(buf), "%03d ", i*90);
rot = i;
}
else if (i<8)
{
- snprintf(buffer, sizeof(buffer), "%03d |", i*90-360);
+ snprintf(buf, sizeof(buf), "%03d |", i*90-360);
rot = i;
}
else
{
- snprintf(buffer, sizeof(buffer), "%03d -", i*90-2*360);
+ snprintf(buf, sizeof(buf), "%03d -", i*90-2*360);
rot = (((i & 3) + 2) & 3) + 4;
}
- rotation_item = gtk_menu_item_new_with_label(buffer);
+ rotation_item = gtk_menu_item_new_with_label(buf);
gtk_container_add(GTK_CONTAINER(rotation_menu), rotation_item);
- gtk_signal_connect(GTK_OBJECT(rotation_item), "activate", (GtkSignalFunc) preview_rotation_callback, p);
+ g_signal_connect(GTK_OBJECT(rotation_item), "activate", (GtkSignalFunc) preview_rotation_callback, p);
gtk_object_set_data(GTK_OBJECT(rotation_item), "Selection", (void *) rot);
gtk_widget_show(rotation_item);
@@ -3573,133 +4475,143 @@ Preview *preview_new(void)
rotation_option_menu = gtk_option_menu_new();
xsane_back_gtk_set_tooltip(xsane.tooltips, rotation_option_menu, DESC_ROTATION);
- gtk_box_pack_start(GTK_BOX(p->button_box), rotation_option_menu, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(p->menu_box), rotation_option_menu, FALSE, FALSE, 0);
gtk_option_menu_set_menu(GTK_OPTION_MENU(rotation_option_menu), rotation_menu);
gtk_option_menu_set_history(GTK_OPTION_MENU(rotation_option_menu), p->rotation); /* set rotation */
-/* xsane_back_gtk_set_tooltip(tooltips, rotation_option_menu, desc); */
gtk_widget_show(rotation_option_menu);
p->rotation_option_menu = rotation_option_menu;
+ xsane_vseparator_new(p->menu_box, 3);
- gtk_widget_show(p->button_box);
-
+ /* the preview aspect ratio menu */
+ pixmap = gdk_pixmap_create_from_xpm_d(p->top->window, &mask, xsane.bg_trans, (gchar **) aspect_ratio_xpm);
+ pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(p->menu_box), pixmapwidget, FALSE, FALSE, 2);
+ gtk_widget_show(pixmapwidget);
+ gdk_drawable_unref(pixmap);
+ ratio_menu = gtk_menu_new();
- /* construct the preview area (table with sliders & preview window) */
- table = gtk_table_new(2, 2, /* homogeneous */ FALSE);
- gtk_table_set_col_spacing(GTK_TABLE(table), 0, 1);
- gtk_table_set_row_spacing(GTK_TABLE(table), 0, 1);
- gtk_container_set_border_width(GTK_CONTAINER(table), 1);
- gtk_box_pack_start(GTK_BOX(vbox), table, /* expand */ TRUE, /* fill */ TRUE, /* padding */ 0);
+ for (i = 0; i < sizeof(ratio_value)/sizeof(float); ++i)
+ {
+ ratio_item = gtk_menu_item_new_with_label(ratio_string[i]);
+ gtk_container_add(GTK_CONTAINER(ratio_menu), ratio_item);
+ g_signal_connect(GTK_OBJECT(ratio_item), "activate", (GtkSignalFunc) preview_ratio_callback, p);
+ gtk_object_set_data(GTK_OBJECT(ratio_item), "Selection", &ratio_value[i]);
- /* the empty box in the top-left corner */
- frame = gtk_frame_new(/* label */ 0);
- gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
- gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_widget_show(ratio_item);
- /* the unit label */
- p->unit_label = gtk_label_new("cm");
- gtk_container_add(GTK_CONTAINER(frame), p->unit_label);
- gtk_widget_show(p->unit_label);
+ if (ratio_value[i] == p->ratio)
+ {
+ ratio_nr = i;
+ }
+ }
- /* the horizontal ruler */
- p->hruler = gtk_hruler_new();
- gtk_table_attach(GTK_TABLE(table), p->hruler, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
+ ratio_option_menu = gtk_option_menu_new();
+ xsane_back_gtk_set_tooltip(xsane.tooltips, ratio_option_menu, DESC_RATIO);
+ gtk_box_pack_start(GTK_BOX(p->menu_box), ratio_option_menu, FALSE, FALSE, 0);
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(ratio_option_menu), ratio_menu);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(ratio_option_menu), ratio_nr); /* set ratio */
- /* the vertical ruler */
- p->vruler = gtk_vruler_new();
- gtk_table_attach(GTK_TABLE(table), p->vruler, 0, 1, 1, 2, 0, GTK_FILL, 0, 0);
+ gtk_widget_show(ratio_option_menu);
+ p->ratio_option_menu = ratio_option_menu;
- /* the preview area */
- p->window = gtk_preview_new(GTK_PREVIEW_COLOR);
- gtk_preview_set_expand(GTK_PREVIEW(p->window), TRUE);
-
- gtk_widget_set_events(p->window, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
-
- /* the first expose_event is responsible to undraw the selection frame */
- gtk_signal_connect(GTK_OBJECT(p->window), "expose_event", (GtkSignalFunc) preview_expose_event_handler_start, p);
- gtk_signal_connect(GTK_OBJECT(p->window), "button_press_event", (GtkSignalFunc) preview_button_press_event_handler, p);
- gtk_signal_connect(GTK_OBJECT(p->window), "motion_notify_event", (GtkSignalFunc) preview_motion_event_handler, p);
- gtk_signal_connect(GTK_OBJECT(p->window), "button_release_event", (GtkSignalFunc) preview_button_release_event_handler, p);
- gtk_signal_connect_after(GTK_OBJECT(p->window), "size_allocate", (GtkSignalFunc) preview_area_resize_handler, p);
- /* the second expose_event is responsible to redraw the selection frame */
- gtk_signal_connect_after(GTK_OBJECT(p->window), "expose_event", (GtkSignalFunc) preview_expose_event_handler_end, p);
+ /* the pointer zoom */
+ frame = gtk_frame_new(0);
+ gtk_box_pack_start(GTK_BOX(outer_hbox), frame, FALSE, FALSE, 3);
+ gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
+ gtk_widget_show(frame);
+ p->zoom = gtk_preview_new(GTK_PREVIEW_COLOR);
+ gtk_preview_size(GTK_PREVIEW(p->zoom), XSANE_ZOOM_SIZE, XSANE_ZOOM_SIZE);
+ gtk_container_add(GTK_CONTAINER(frame), p->zoom);
+ gtk_widget_show(p->zoom);
- /* Connect the motion-notify events of the preview area with the rulers. Nifty stuff! */
- class = GTK_WIDGET_CLASS(GTK_OBJECT(p->hruler)->klass);
- signal_func = (GtkSignalFunc) class->motion_notify_event;
- gtk_signal_connect_object(GTK_OBJECT(p->window), "motion_notify_event", signal_func, GTK_OBJECT(p->hruler));
- class = GTK_WIDGET_CLASS(GTK_OBJECT(p->vruler)->klass);
- signal_func = (GtkSignalFunc) class->motion_notify_event;
- gtk_signal_connect_object(GTK_OBJECT(p->window), "motion_notify_event", signal_func, GTK_OBJECT(p->vruler));
+#if 0
+ /* the RGB label */
+ frame = gtk_frame_new(0);
+ gtk_box_pack_start(GTK_BOX(p->menu_box), frame, FALSE, FALSE, 3);
+ gtk_widget_show(frame);
+ p->rgb_label = gtk_label_new(0);
+ gtk_container_add(GTK_CONTAINER(frame), p->rgb_label);
+ gtk_widget_show(p->rgb_label);
+ preview_display_color_components(p, -1, -1); /* display "###, ###, ###" */
+#endif
+ gtk_widget_show(p->menu_box);
+ /* the menu box is ready */
- p->viewport = gtk_frame_new(/* label */ 0);
- gtk_frame_set_shadow_type(GTK_FRAME(p->viewport), GTK_SHADOW_IN);
- gtk_container_add(GTK_CONTAINER(p->viewport), p->window);
- gtk_table_attach(GTK_TABLE(table), p->viewport, 1, 2, 1, 2,
- GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
- preview_update_surface(p, 0);
+ /* set the action_hbox */
+ action_box = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(middle_vbox), action_box, FALSE, FALSE, 2);
+ gtk_container_set_border_width(GTK_CONTAINER(action_box), 0);
+ gtk_widget_show(action_box);
- /* fill in action area: */
/* the (in)valid pixmaps */
pixmap = gdk_pixmap_create_from_xpm_d(p->top->window, &mask, xsane.bg_trans, (gchar **) valid_xpm);
- p->valid_pixmap = gtk_pixmap_new(pixmap, mask);
- gtk_box_pack_start(GTK_BOX(hbox), p->valid_pixmap, FALSE, FALSE, 0);
+ p->valid_pixmap = gtk_image_new_from_pixmap(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(action_box), p->valid_pixmap, FALSE, FALSE, 0);
gtk_widget_show(p->valid_pixmap);
- gdk_pixmap_unref(pixmap);
+ gdk_drawable_unref(pixmap);
pixmap = gdk_pixmap_create_from_xpm_d(p->top->window, &mask, xsane.bg_trans, (gchar **) scanning_xpm);
- p->scanning_pixmap = gtk_pixmap_new(pixmap, mask);
- gtk_box_pack_start(GTK_BOX(hbox), p->scanning_pixmap, FALSE, FALSE, 0);
+ p->scanning_pixmap = gtk_image_new_from_pixmap(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(action_box), p->scanning_pixmap, FALSE, FALSE, 0);
gtk_widget_show(p->scanning_pixmap);
- gdk_pixmap_unref(pixmap);
+ gdk_drawable_unref(pixmap);
pixmap = gdk_pixmap_create_from_xpm_d(p->top->window, &mask, xsane.bg_trans, (gchar **) incomplete_xpm);
- p->incomplete_pixmap = gtk_pixmap_new(pixmap, mask);
- gtk_box_pack_start(GTK_BOX(hbox), p->incomplete_pixmap, FALSE, FALSE, 0);
+ p->incomplete_pixmap = gtk_image_new_from_pixmap(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(action_box), p->incomplete_pixmap, FALSE, FALSE, 0);
gtk_widget_show(p->incomplete_pixmap);
- gdk_pixmap_unref(pixmap);
+ gdk_drawable_unref(pixmap);
pixmap = gdk_pixmap_create_from_xpm_d(p->top->window, &mask, xsane.bg_trans, (gchar **) invalid_xpm);
- p->invalid_pixmap = gtk_pixmap_new(pixmap, mask);
- gtk_box_pack_start(GTK_BOX(hbox), p->invalid_pixmap, FALSE, FALSE, 0);
+ p->invalid_pixmap = gtk_image_new_from_pixmap(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(action_box), p->invalid_pixmap, FALSE, FALSE, 0);
gtk_widget_show(p->invalid_pixmap);
- gdk_pixmap_unref(pixmap);
+ gdk_drawable_unref(pixmap);
+
/* Start button */
p->start = gtk_button_new_with_label(BUTTON_PREVIEW_ACQUIRE);
xsane_back_gtk_set_tooltip(xsane.tooltips, p->start, DESC_PREVIEW_ACQUIRE);
- gtk_signal_connect(GTK_OBJECT(p->start), "clicked", (GtkSignalFunc) preview_start_button_clicked, p);
- gtk_box_pack_start(GTK_BOX(hbox), p->start, TRUE, TRUE, 10);
- gtk_widget_add_accelerator(p->start, "clicked", xsane.accelerator_group, GDK_P, GDK_MOD1_MASK, GTK_ACCEL_LOCKED); /* Alt P */
+ g_signal_connect(GTK_OBJECT(p->start), "clicked", (GtkSignalFunc) preview_start_button_clicked, p);
+ gtk_box_pack_start(GTK_BOX(action_box), p->start, TRUE, TRUE, 5);
+ gtk_widget_add_accelerator(p->start, "clicked", xsane.accelerator_group, GDK_P, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt P */
+ gtk_widget_show(p->start);
/* Cancel button */
p->cancel = gtk_button_new_with_label(BUTTON_PREVIEW_CANCEL);
xsane_back_gtk_set_tooltip(xsane.tooltips, p->cancel, DESC_PREVIEW_CANCEL);
- gtk_signal_connect(GTK_OBJECT(p->cancel), "clicked", (GtkSignalFunc) preview_cancel_button_clicked, p);
- gtk_box_pack_start(GTK_BOX(hbox), p->cancel, TRUE, TRUE, 10);
- gtk_widget_add_accelerator(p->cancel, "clicked", xsane.accelerator_group, GDK_Escape, GDK_MOD1_MASK, GTK_ACCEL_LOCKED); /* Alt ESC */
+ g_signal_connect(GTK_OBJECT(p->cancel), "clicked", (GtkSignalFunc) preview_cancel_button_clicked, p);
+ gtk_box_pack_start(GTK_BOX(action_box), p->cancel, TRUE, TRUE, 5);
+ gtk_widget_add_accelerator(p->cancel, "clicked", xsane.accelerator_group, GDK_Escape, GDK_MOD1_MASK, DEF_GTK_ACCEL_LOCKED); /* Alt ESC */
+ gtk_widget_show(p->cancel);
gtk_widget_set_sensitive(p->cancel, FALSE);
- gtk_widget_show(p->cancel);
- gtk_widget_show(p->start);
- gtk_widget_show(p->viewport);
- gtk_widget_show(p->window);
- gtk_widget_show(p->hruler);
- gtk_widget_show(p->vruler);
+#if 1
+ /* the RGB label */
+ frame = gtk_frame_new(0);
+ gtk_box_pack_start(GTK_BOX(action_box), frame, FALSE, FALSE, 3);
gtk_widget_show(frame);
- gtk_widget_show(table);
+ p->rgb_label = gtk_label_new(0);
+ gtk_container_add(GTK_CONTAINER(frame), p->rgb_label);
+ gtk_widget_show(p->rgb_label);
+ preview_display_color_components(p, -1, -1); /* display "###, ###, ###" */
+#endif
+
+ preview_update_surface(p, 0);
+
+ gtk_widget_show(p->window);
gtk_widget_show(p->top);
cursor = gdk_cursor_new(XSANE_CURSOR_PREVIEW); /* set default curosr */
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = XSANE_CURSOR_PREVIEW;
gtk_widget_pop_colormap();
@@ -3875,6 +4787,7 @@ void preview_update_surface(Preview *p, int surface_changed)
{
gtk_widget_set_sensitive(p->preset_area_option_menu, TRUE); /* enable preset area */
gtk_widget_set_sensitive(p->zoom_in, TRUE); /* zoom in is allowed at all */
+ gtk_widget_set_sensitive(p->zoom_area, TRUE); /* zoom area is allowed at all */
gtk_widget_set_sensitive(p->full_area, TRUE); /* enable selection buttons */
gtk_widget_set_sensitive(p->autoselect, TRUE);
}
@@ -3882,6 +4795,7 @@ void preview_update_surface(Preview *p, int surface_changed)
{
gtk_widget_set_sensitive(p->preset_area_option_menu, FALSE); /* disable preset area */
gtk_widget_set_sensitive(p->zoom_in, FALSE); /* no zoom at all */
+ gtk_widget_set_sensitive(p->zoom_area, FALSE);
gtk_widget_set_sensitive(p->zoom_out, FALSE);
gtk_widget_set_sensitive(p->zoom_undo, FALSE);
gtk_widget_set_sensitive(p->zoom_not, FALSE);
@@ -3906,7 +4820,11 @@ void preview_update_surface(Preview *p, int surface_changed)
width = p->surface[p->index_xmax] - p->surface[p->index_xmin];
height = p->surface[p->index_ymax] - p->surface[p->index_ymin];
+#if 0
if ( (p->calibration) || (p->startimage) ) /* predefined image should have constant aspect */
+#else
+ if (p->calibration) /* predefined calibration image should have constant aspect */
+#endif
{
p->aspect = fabs(p->image_width/(float) p->image_height);
}
@@ -3942,7 +4860,7 @@ void preview_update_surface(Preview *p, int surface_changed)
p->preview_window_width = 0.3 * gdk_screen_width();
p->preview_window_height = 0.5 * gdk_screen_height();
preview_area_correct(p); /* calculate preview_width and height */
- gtk_widget_set_usize(GTK_WIDGET(p->window), p->preview_width, p->preview_height);
+ gtk_widget_set_size_request(GTK_WIDGET(p->window), p->preview_width, p->preview_height);
}
else if (surface_changed) /* establish new surface */
{
@@ -3967,6 +4885,7 @@ void preview_update_surface(Preview *p, int surface_changed)
/* ---------------------------------------------------------------------------------------------------------------------- */
+/* preview_scan is called once when the "Preview scan" button is pressed */
void preview_scan(Preview *p)
{
double min, max, swidth, sheight, width, height, dpi = 0;
@@ -3974,6 +4893,14 @@ void preview_scan(Preview *p)
gint gwidth, gheight;
int i;
float dsurface[4];
+ int gamma_gray_size = 256; /* set this values to image depth for more than 8bpp input support!!! */
+ int gamma_red_size = 256;
+ int gamma_green_size = 256;
+ int gamma_blue_size = 256;
+ int gamma_gray_max = 255; /* set this to to image depth for more than 8bpp output support */
+ int gamma_red_max = 255;
+ int gamma_green_max = 255;
+ int gamma_blue_max = 255;
DBG(DBG_proc, "preview_scan\n");
@@ -3995,10 +4922,6 @@ void preview_scan(Preview *p)
preview_save_option(p, xsane.well_known.bit_depth, &p->saved_bit_depth, &p->saved_bit_depth_valid);
-#if 0
- xsane_set_medium(preferences.medium[xsane.medium_nr]); /* make sure medium gamma values are up to date */
-#endif
-
/* determine dpi, if necessary: */
if (xsane.well_known.dpi > 0)
@@ -4066,6 +4989,7 @@ void preview_scan(Preview *p)
xsane_set_resolution(xsane.well_known.dpi_y, dpi); /* set resolution to dpi or next higher value that is available */
}
+
preview_rotate_previewsurface_to_devicesurface(p->rotation, p->surface, dsurface);
for (i = 0; i < 4; ++i)
@@ -4087,6 +5011,97 @@ void preview_scan(Preview *p)
}
#endif
+
+ if (xsane.well_known.gamma_vector >0)
+ {
+ const SANE_Option_Descriptor *opt;
+
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector);
+ if (SANE_OPTION_IS_ACTIVE(opt->cap))
+ {
+ SANE_Int *gamma_data;
+
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector);
+ gamma_gray_size = opt->size / sizeof(opt->type);
+ gamma_gray_max = opt->constraint.range->max;
+
+ gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int));
+
+ if ((xsane.xsane_colors > 1) || (xsane.no_preview_medium_gamma)) /* color scan or medium preview gamma disabled */
+ {
+ xsane_create_gamma_curve(gamma_data, 0, 1.0, 0.0, 0.0, 0.0, 100.0, 1.0, gamma_gray_size, gamma_gray_max);
+ }
+ else /* grayscale scan */
+ {
+ xsane_create_gamma_curve(gamma_data, xsane.medium_negative, 1.0, 0.0, 0.0,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ gamma_gray_size, gamma_gray_max);
+ }
+
+ xsane_back_gtk_update_vector(xsane.well_known.gamma_vector, gamma_data);
+ free(gamma_data);
+ }
+ }
+
+ if (xsane.well_known.gamma_vector_r >0)
+ {
+ const SANE_Option_Descriptor *opt;
+
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_r);
+ if (SANE_OPTION_IS_ACTIVE(opt->cap))
+ {
+ SANE_Int *gamma_data_red, *gamma_data_green, *gamma_data_blue;
+
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_r);
+ gamma_red_size = opt->size / sizeof(opt->type);
+ gamma_red_max = opt->constraint.range->max;
+
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_g);
+ gamma_green_size = opt->size / sizeof(opt->type);
+ gamma_green_max = opt->constraint.range->max;
+
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.gamma_vector_b);
+ gamma_blue_size = opt->size / sizeof(opt->type);
+ gamma_blue_max = opt->constraint.range->max;
+
+ gamma_data_red = malloc(gamma_red_size * sizeof(SANE_Int));
+ gamma_data_green = malloc(gamma_green_size * sizeof(SANE_Int));
+ gamma_data_blue = malloc(gamma_blue_size * sizeof(SANE_Int));
+
+ if (xsane.no_preview_medium_gamma) /* do not use medium gamma for preview */
+ {
+ DBG(DBG_info, "preview: not using medium gamma table\n");
+
+ xsane_create_gamma_curve(gamma_data_red, 0, 1.0, 0.0, 0.0, 0.0, 100.0, 1.0, gamma_red_size, gamma_red_max);
+ xsane_create_gamma_curve(gamma_data_green, 0, 1.0, 0.0, 0.0, 0.0, 100.0, 1.0, gamma_green_size, gamma_green_max);
+ xsane_create_gamma_curve(gamma_data_blue, 0, 1.0, 0.0, 0.0, 0.0, 100.0, 1.0, gamma_blue_size, gamma_blue_max);
+ }
+ else /* use medium gamma for preview */
+ {
+ DBG(DBG_info, "preview: using medium gamma table\n");
+
+ xsane_create_gamma_curve(gamma_data_red, xsane.medium_negative, 1.0, 0.0, 0.0,
+ xsane.medium_shadow_red, xsane.medium_highlight_red, xsane.medium_gamma_red,
+ gamma_red_size, gamma_red_max);
+ xsane_create_gamma_curve(gamma_data_green, xsane.medium_negative, 1.0, 0.0, 0.0,
+ xsane.medium_shadow_green, xsane.medium_highlight_green, xsane.medium_gamma_green,
+ gamma_green_size, gamma_green_max);
+ xsane_create_gamma_curve(gamma_data_blue, xsane.medium_negative, 1.0, 0.0, 0.0,
+ xsane.medium_shadow_blue, xsane.medium_highlight_blue, xsane.medium_gamma_blue,
+ gamma_blue_size, gamma_blue_max);
+ }
+
+ xsane_back_gtk_update_vector(xsane.well_known.gamma_vector_r, gamma_data_red);
+ xsane_back_gtk_update_vector(xsane.well_known.gamma_vector_g, gamma_data_green);
+ xsane_back_gtk_update_vector(xsane.well_known.gamma_vector_b, gamma_data_blue);
+
+ free(gamma_data_red);
+ free(gamma_data_green);
+ free(gamma_data_blue);
+ }
+ }
+
+
xsane.block_update_param = FALSE;
p->preview_colors = xsane.xsane_colors;
p->scan_incomplete = FALSE;
@@ -4189,6 +5204,8 @@ static void preview_delete_images(Preview *p)
fclose(out);
}
preview_update_surface(p, 1);
+
+ xsane_batch_scan_update_icon_list();
}
/* ---------------------------------------------------------------------------------------------------------------------- */
@@ -4232,12 +5249,12 @@ void preview_destroy(Preview *p)
if (p->gc_selection)
{
- gdk_gc_destroy(p->gc_selection);
+ gdk_gc_unref(p->gc_selection);
}
if (p->gc_selection_maximum)
{
- gdk_gc_destroy(p->gc_selection_maximum);
+ gdk_gc_unref(p->gc_selection_maximum);
}
if (p->top)
@@ -4251,6 +5268,27 @@ void preview_destroy(Preview *p)
/* ---------------------------------------------------------------------------------------------------------------------- */
+static void preview_zoom_area(GtkWidget *window, gpointer data)
+{
+ Preview *p=data;
+ int i;
+
+ DBG(DBG_proc, "preview_zoom_area\n");
+
+ for (i=0; i<4; i++)
+ {
+ p->old_surface[i] = p->surface[i];
+ p->surface[i] = p->selection.coordinate[i];
+ }
+
+ preview_update_surface(p, 1);
+ gtk_widget_set_sensitive(p->zoom_not, TRUE); /* allow unzoom */
+ gtk_widget_set_sensitive(p->zoom_out, TRUE); /* allow zoom out */
+ gtk_widget_set_sensitive(p->zoom_undo,TRUE); /* allow zoom undo */
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
static void preview_zoom_not(GtkWidget *window, gpointer data)
{
Preview *p=data;
@@ -4320,19 +5358,25 @@ static void preview_zoom_out(GtkWidget *window, gpointer data)
/* ---------------------------------------------------------------------------------------------------------------------- */
-static void preview_zoom_in(GtkWidget *window, gpointer data)
+static void preview_select_zoom_point(Preview *p, int preview_x, int preview_y)
{
- Preview *p=data;
int i;
+ float device_x, device_y;
- DBG(DBG_proc, "preview_zoom_in\n");
+ DBG(DBG_proc, "preview_select_zoom_point(%d, %d)\n", preview_x, preview_y);
+
+ preview_transform_coordinate_window_to_device(p, preview_x, preview_y, &device_x, &device_y);
for (i=0; i<4; i++)
{
p->old_surface[i] = p->surface[i];
- p->surface[i] = p->selection.coordinate[i];
}
+ p->surface[0] = device_x + (p->surface[0] - device_x) * 0.8;
+ p->surface[1] = device_y + (p->surface[1] - device_y) * 0.8;
+ p->surface[2] = device_x + (p->surface[2] - device_x) * 0.8;
+ p->surface[3] = device_y + (p->surface[3] - device_y) * 0.8;
+
preview_update_surface(p, 1);
gtk_widget_set_sensitive(p->zoom_not, TRUE); /* allow unzoom */
gtk_widget_set_sensitive(p->zoom_out, TRUE); /* allow zoom out */
@@ -4375,7 +5419,7 @@ static void preview_get_color(Preview *p, int x, int y, int range, int *red, int
{
preview_transform_coordinate_window_to_image(p, x, y, &image_x, &image_y);
- if ( (image_x < p->image_width) && (image_y < p->image_height) )
+ if ( (image_x >= 0) && (image_x < p->image_width) && (image_y >=0) && (image_y < p->image_height) )
{
image_x_min = image_x - range/2;
image_y_min = image_y - range/2;
@@ -4423,6 +5467,20 @@ static void preview_get_color(Preview *p, int x, int y, int range, int *red, int
/* ---------------------------------------------------------------------------------------------------------------------- */
+static void preview_add_batch(GtkWidget *window, Preview *data)
+{
+ DBG(DBG_proc, "preview_add_batch\n");
+
+ xsane_batch_scan_add(); /* add active settings to batch list */
+
+#if 0
+ preview_draw_selection(p); /* read selection from backend: correct rotation */
+ preview_establish_selection(p); /* read selection from backend: correct rotation */
+#endif
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
static void preview_pipette_white(GtkWidget *window, gpointer data)
{
Preview *p=data;
@@ -4450,7 +5508,7 @@ static void preview_pipette_white(GtkWidget *window, gpointer data)
cursor = gdk_cursor_new_from_pixmap(pixmap, mask, &fg, &bg, CURSOR_PIPETTE_HOT_X, CURSOR_PIPETTE_HOT_Y);
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = -1;
}
@@ -4483,7 +5541,7 @@ static void preview_pipette_gray(GtkWidget *window, gpointer data)
cursor = gdk_cursor_new_from_pixmap(pixmap, mask, &fg, &bg, CURSOR_PIPETTE_HOT_X, CURSOR_PIPETTE_HOT_Y);
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = -1;
}
@@ -4516,12 +5574,77 @@ static void preview_pipette_black(GtkWidget *window, gpointer data)
cursor = gdk_cursor_new_from_pixmap(pixmap, mask, &fg, &bg, CURSOR_PIPETTE_HOT_X, CURSOR_PIPETTE_HOT_Y);
gdk_window_set_cursor(p->window->window, cursor);
- gdk_cursor_destroy(cursor);
+ gdk_cursor_unref(cursor);
+ p->cursornr = -1;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void preview_init_autoraise_scanarea(GtkWidget *window, gpointer data)
+{
+ Preview *p=data;
+ GdkCursor *cursor;
+ GdkColor fg;
+ GdkColor bg;
+ GdkPixmap *pixmap;
+ GdkPixmap *mask;
+
+ DBG(DBG_proc, "preview_init_autoraise_scanarea\n");
+
+ p->mode = MODE_AUTORAISE_SCANAREA;
+
+ pixmap = gdk_bitmap_create_from_data(p->top->window, cursor_autoraise_scanarea, CURSOR_AUTORAISE_SCANAREA_WIDTH, CURSOR_AUTORAISE_SCANAREA_HEIGHT);
+ mask = gdk_bitmap_create_from_data(p->top->window, cursor_autoraise_scanarea_mask, CURSOR_AUTORAISE_SCANAREA_WIDTH, CURSOR_AUTORAISE_SCANAREA_HEIGHT);
+
+ fg.red = 0;
+ fg.green = 0;
+ fg.blue = 0;
+
+ bg.red = 65535;
+ bg.green = 65535;
+ bg.blue = 65535;
+
+ cursor = gdk_cursor_new_from_pixmap(pixmap, mask, &fg, &bg, CURSOR_AUTORAISE_SCANAREA_HOT_X, CURSOR_AUTORAISE_SCANAREA_HOT_Y);
+
+ gdk_window_set_cursor(p->window->window, cursor);
+ gdk_cursor_unref(cursor);
p->cursornr = -1;
}
/* ---------------------------------------------------------------------------------------------------------------------- */
+static void preview_zoom_in(GtkWidget *window, gpointer data)
+{
+ Preview *p=data;
+ GdkCursor *cursor;
+ GdkColor fg;
+ GdkColor bg;
+ GdkPixmap *pixmap;
+ GdkPixmap *mask;
+
+ DBG(DBG_proc, "preview_zoom\n");
+
+ p->mode = MODE_ZOOM_IN;
+
+ pixmap = gdk_bitmap_create_from_data(p->top->window, cursor_zoom, CURSOR_ZOOM_WIDTH, CURSOR_ZOOM_HEIGHT);
+ mask = gdk_bitmap_create_from_data(p->top->window, cursor_zoom_mask, CURSOR_ZOOM_WIDTH, CURSOR_ZOOM_HEIGHT);
+
+ fg.red = 0;
+ fg.green = 0;
+ fg.blue = 0;
+
+ bg.red = 65535;
+ bg.green = 65535;
+ bg.blue = 65535;
+
+ cursor = gdk_cursor_new_from_pixmap(pixmap, mask, &fg, &bg, CURSOR_ZOOM_HOT_X, CURSOR_ZOOM_HOT_Y);
+
+ gdk_window_set_cursor(p->window->window, cursor);
+ gdk_cursor_unref(cursor);
+ p->cursornr = -1;
+}
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
void preview_select_full_preview_area(Preview *p)
{
int i;
@@ -4566,32 +5689,15 @@ static void preview_delete_images_callback(GtkWidget *widget, gpointer call_data
/* ---------------------------------------------------------------------------------------------------------------------- */
-int xsane_preset_area_entry_rename;
-
-static void xsane_preset_area_entry_rename_button_callback(GtkWidget *widget, gpointer data)
-{
- DBG(DBG_proc, "xsane_preset_area_entry_rename\n");
-
- xsane_preset_area_entry_rename = (int) data;
-}
-
-/* ---------------------------------------------------------------------------------------------------------------------- */
-
static gint preview_preset_area_rename_callback(GtkWidget *widget, GtkWidget *preset_area_widget)
{
int selection;
char *oldname;
char *newname;
Preview *p;
- GtkWidget *rename_dialog;
- GtkWidget *text;
- GtkWidget *button;
- GtkWidget *vbox, *hbox;
GtkWidget *old_preset_area_menu;
- char buf[256];
int old_selection;
-
DBG(DBG_proc, "preview_preset_area_rename_callback\n");
selection = (int) gtk_object_get_data(GTK_OBJECT(preset_area_widget), "Selection");
@@ -4599,71 +5705,15 @@ static gint preview_preset_area_rename_callback(GtkWidget *widget, GtkWidget *pr
DBG(DBG_info ,"rename %s\n", preferences.preset_area[selection]->name);
+ /* set menu in correct state, is a bit strange this way but I do not have a better idea */
old_preset_area_menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(p->preset_area_option_menu));
old_selection = (int) gtk_object_get_data(GTK_OBJECT(gtk_menu_get_active(GTK_MENU(old_preset_area_menu))), "Selection");
-
gtk_menu_popdown(GTK_MENU(old_preset_area_menu));
- /* set menu in correct state, is a bit strange this way but I do not have a better idea */
gtk_option_menu_set_history(GTK_OPTION_MENU(p->preset_area_option_menu), old_selection);
oldname = strdup(preferences.preset_area[selection]->name);
- rename_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
- xsane_set_window_icon(rename_dialog, 0);
-
- /* set rename dialog */
- gtk_window_set_position(GTK_WINDOW(rename_dialog), GTK_WIN_POS_CENTER);
- gtk_window_set_policy(GTK_WINDOW(rename_dialog), FALSE, FALSE, FALSE);
- snprintf(buf, sizeof(buf), "%s %s", xsane.prog_name, WINDOW_PRESET_AREA_RENAME);
- gtk_window_set_title(GTK_WINDOW(rename_dialog), buf);
- gtk_signal_connect(GTK_OBJECT(rename_dialog), "delete_event", (GtkSignalFunc) xsane_preset_area_entry_rename_button_callback, (void *) -1);
- gtk_widget_show(rename_dialog);
-
- /* set the main vbox */
- vbox = gtk_vbox_new(FALSE, 0);
- gtk_container_set_border_width(GTK_CONTAINER(vbox), 0);
- gtk_container_add(GTK_CONTAINER(rename_dialog), vbox);
- gtk_widget_show(vbox);
-
- /* set the main hbox */
- hbox = gtk_hbox_new(FALSE, 0);
- xsane_separator_new(vbox, 2);
- gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
- gtk_widget_show(hbox);
-
- text = gtk_entry_new_with_max_length(64);
- xsane_back_gtk_set_tooltip(xsane.tooltips, text, DESC_PRESET_AREA_NAME);
- gtk_entry_set_text(GTK_ENTRY(text), oldname);
- gtk_widget_set_usize(text, 300, 0);
- gtk_box_pack_start(GTK_BOX(vbox), text, TRUE, TRUE, 4);
- gtk_widget_show(text);
-
-
- button = gtk_button_new_with_label("OK");
- gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_preset_area_entry_rename_button_callback, (void *) 1);
- gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
- gtk_widget_show(button);
-
- button = gtk_button_new_with_label("Cancel");
- gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_preset_area_entry_rename_button_callback, (void *) -1);
- gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
- gtk_widget_show(button);
-
- xsane_preset_area_entry_rename = 0;
-
- while (xsane_preset_area_entry_rename == 0)
- {
- while (gtk_events_pending())
- {
- DBG(DBG_info, "preview_preset_area_rename_callback: calling gtk_main_iteration\n");
- gtk_main_iteration();
- }
- }
-
- newname = strdup(gtk_entry_get_text(GTK_ENTRY(text)));
-
- if (xsane_preset_area_entry_rename == 1) /* OK button has been pressed */
+ if (!xsane_front_gtk_getname_dialog(WINDOW_PRESET_AREA_RENAME, DESC_PRESET_AREA_RENAME, oldname, &newname))
{
gtk_option_menu_remove_menu(GTK_OPTION_MENU(p->preset_area_option_menu));
@@ -4682,8 +5732,6 @@ static gint preview_preset_area_rename_callback(GtkWidget *widget, GtkWidget *pr
free(oldname);
free(newname);
- gtk_widget_destroy(rename_dialog);
-
xsane_set_sensitivity(TRUE);
return TRUE; /* event is handled */
@@ -4695,6 +5743,9 @@ static gint preview_preset_area_add_callback(GtkWidget *widget, GtkWidget *prese
{
int selection, i, old_selection = 0;
Preview *p;
+ float coord[4];
+ char suggested_name[256];
+ char *newname;
GtkWidget *old_preset_area_menu;
DBG(DBG_proc, "preview_preset_area_add_callback\n");
@@ -4702,11 +5753,18 @@ static gint preview_preset_area_add_callback(GtkWidget *widget, GtkWidget *prese
selection = (int) gtk_object_get_data(GTK_OBJECT(preset_area_widget), "Selection");
p = (Preview *) gtk_object_get_data(GTK_OBJECT(preset_area_widget), "Preview");
- if (selection < preferences.preset_area_definitions)
- {
- char buf[256];
- float coord[4];
+ /* set menu in correct state, is a bit strange this way but I do not have a better idea */
+ old_preset_area_menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(p->preset_area_option_menu));
+ old_selection = (int) gtk_object_get_data(GTK_OBJECT(gtk_menu_get_active(GTK_MENU(old_preset_area_menu))), "Selection");
+ gtk_menu_popdown(GTK_MENU(old_preset_area_menu));
+ gtk_option_menu_set_history(GTK_OPTION_MENU(p->preset_area_option_menu), old_selection);
+
+ /* sugggest name = size in mm */
+ preview_rotate_previewsurface_to_devicesurface(p->rotation, p->selection.coordinate, coord);
+ snprintf(suggested_name, sizeof(suggested_name), "%d mm x %d mm", (int) (coord[2]-coord[0]), (int) (coord[3]-coord[1]));
+ if (!xsane_front_gtk_getname_dialog(WINDOW_PRESET_AREA_ADD, DESC_PRESET_AREA_ADD, suggested_name, &newname))
+ {
preferences.preset_area = realloc(preferences.preset_area, (preferences.preset_area_definitions+1) * sizeof(void *));
/* shift all items after selection */
@@ -4715,32 +5773,18 @@ static gint preview_preset_area_add_callback(GtkWidget *widget, GtkWidget *prese
preferences.preset_area[i+1] = preferences.preset_area[i];
}
- /* insert new item behind selected item, name is size in mm */
- preview_rotate_previewsurface_to_devicesurface(p->rotation, p->selection.coordinate, coord);
- snprintf(buf, sizeof(buf), "%d mm x %d mm", (int) (coord[2]-coord[0]), (int) (coord[3]-coord[1]));
+ /* insert new item behind selected item */
preferences.preset_area[selection+1] = calloc(sizeof(Preferences_preset_area_t), 1);
- preferences.preset_area[selection+1]->name = strdup(buf);
+ preferences.preset_area[selection+1]->name = strdup(newname);
preferences.preset_area[selection+1]->xoffset = coord[0];
preferences.preset_area[selection+1]->yoffset = coord[1];
preferences.preset_area[selection+1]->width = coord[2] - coord[0];
preferences.preset_area[selection+1]->height = coord[3] - coord[1];
- DBG(DBG_proc, "added %s\n", buf);
+ DBG(DBG_proc, "added %s\n", newname);
preferences.preset_area_definitions++;
- old_preset_area_menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(p->preset_area_option_menu));
-
- gtk_option_menu_remove_menu(GTK_OPTION_MENU(p->preset_area_option_menu));
- old_selection = (int) gtk_object_get_data(GTK_OBJECT(gtk_menu_get_active(GTK_MENU(old_preset_area_menu))), "Selection");
-
- if (old_selection > selection) /* we are moving the selected surface */
- {
- old_selection++;
- }
-
- gtk_widget_destroy(old_preset_area_menu);
-
preview_create_preset_area_menu(p, old_selection);
}
@@ -4895,6 +5939,7 @@ static gint preview_preset_area_context_menu_callback(GtkWidget *widget, GdkEven
GtkWidget *menu_item;
GdkEventButton *event_button;
int selection;
+ char buf[256];
DBG(DBG_proc, "preview_preset_area_context_menu_callback\n");
@@ -4912,42 +5957,51 @@ static gint preview_preset_area_context_menu_callback(GtkWidget *widget, GdkEven
menu_item = gtk_menu_item_new_with_label(MENU_ITEM_PRESET_AREA_ADD_SEL);
gtk_widget_show(menu_item);
gtk_container_add(GTK_CONTAINER(menu), menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_add_callback, widget);
+ g_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_add_callback, widget);
+
+ /* add separator */
+ menu_item = gtk_menu_item_new();
+ gtk_widget_show(menu_item);
+ gtk_container_add(GTK_CONTAINER(menu), menu_item);
/* rename preset area */
- menu_item = gtk_menu_item_new_with_label(MENU_ITEM_PRESET_AREA_RENAME);
+ snprintf(buf, sizeof(buf), "%s: %s", preferences.preset_area[selection]->name, MENU_ITEM_RENAME);
+ menu_item = gtk_menu_item_new_with_label(buf);
gtk_widget_show(menu_item);
gtk_container_add(GTK_CONTAINER(menu), menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_rename_callback, widget);
+ g_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_rename_callback, widget);
if (selection) /* not available for "full area" */
{
/* delete preset area */
- menu_item = gtk_menu_item_new_with_label(MENU_ITEM_PRESET_AREA_DELETE);
+ snprintf(buf, sizeof(buf), "%s: %s", preferences.preset_area[selection]->name, MENU_ITEM_DELETE);
+ menu_item = gtk_menu_item_new_with_label(buf);
gtk_widget_show(menu_item);
gtk_container_add(GTK_CONTAINER(menu), menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_delete_callback, widget);
+ g_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_delete_callback, widget);
}
if (selection>1) /* available from 3rd item */
{
/* move up */
- menu_item = gtk_menu_item_new_with_label(MENU_OTEM_PRESET_AREA_MOVE_UP);
+ snprintf(buf, sizeof(buf), "%s: %s", preferences.preset_area[selection]->name, MENU_ITEM_MOVE_UP);
+ menu_item = gtk_menu_item_new_with_label(buf);
gtk_widget_show(menu_item);
gtk_container_add(GTK_CONTAINER(menu), menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_move_up_callback, widget);
+ g_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_move_up_callback, widget);
}
if ((selection) && (selection < preferences.preset_area_definitions-1))
{
/* move down */
- menu_item = gtk_menu_item_new_with_label(MENU_OTEM_PRESET_AREA_MOVE_DWN);
+ snprintf(buf, sizeof(buf), "%s: %s", preferences.preset_area[selection]->name, MENU_ITEM_MOVE_DWN);
+ menu_item = gtk_menu_item_new_with_label(buf);
gtk_widget_show(menu_item);
gtk_container_add(GTK_CONTAINER(menu), menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_move_down_callback, widget);
+ g_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc) preview_preset_area_move_down_callback, widget);
}
- gtk_widget_show(menu);
+/* gtk_widget_show(menu); */
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event_button->button, event_button->time);
return TRUE; /* event is handled */
@@ -4959,9 +6013,9 @@ static gint preview_preset_area_context_menu_callback(GtkWidget *widget, GdkEven
/* ---------------------------------------------------------------------------------------------------------------------- */
-static void preview_preset_area_callback(GtkWidget *widget, gpointer call_data)
+static void preview_preset_area_callback(GtkWidget *widget, gpointer data)
{
- Preview *p = call_data;
+ Preview *p = data;
int selection;
DBG(DBG_proc, "preview_preset_area_callback\n");
@@ -4982,9 +6036,9 @@ static void preview_preset_area_callback(GtkWidget *widget, gpointer call_data)
/* ---------------------------------------------------------------------------------------------------------------------- */
-static void preview_rotation_callback(GtkWidget *widget, gpointer call_data)
+static void preview_rotation_callback(GtkWidget *widget, gpointer data)
{
- Preview *p = call_data;
+ Preview *p = data;
float rotated_surface[4];
int rot;
@@ -5070,8 +6124,84 @@ static void preview_rotation_callback(GtkWidget *widget, gpointer call_data)
p->rotation = rot;
- preview_update_selection(p); /* read selection from backend: correct rotation */
+ p->block_update_maximum_output_size_clipping = TRUE; /* necessary when in copy mode */
preview_update_surface(p, 2); /* rotate surfaces */
+ p->block_update_maximum_output_size_clipping = FALSE;
+ preview_update_selection(p); /* read selection from backend: correct rotation */
+ xsane_batch_scan_update_icon_list(); /* rotate batch scan icons */
+ preview_establish_ratio(p); /* make sure ratio is like selected - when selected */
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void preview_establish_ratio(Preview *p)
+{
+ float width, height;
+
+ DBG(DBG_proc, "preview_establish_ratio\n");
+
+ if (p->ratio == 0.0)
+ {
+ return;
+ }
+
+ width = fabs(p->selection.coordinate[p->index_xmax] - p->selection.coordinate[p->index_xmin]);
+ height = fabs(p->selection.coordinate[p->index_ymax] - p->selection.coordinate[p->index_ymin]);
+
+ if ( (0.99 < width / p->ratio / height) && (width / p->ratio / height < 1.01) )
+ {
+ return;
+ }
+
+ if ( (0.99 < width * p->ratio / height) && (width * p->ratio / height < 1.01) )
+ {
+ width = height;
+
+ if (width > p->scanner_surface[p->index_xmax] - p->scanner_surface[p->index_xmin])
+ {
+ width = p->scanner_surface[p->index_xmax] - p->scanner_surface[p->index_xmin];
+ }
+ }
+
+ height = width / p->ratio;
+ if (height > p->scanner_surface[p->index_ymax] - p->scanner_surface[p->index_ymin])
+ {
+ height = p->scanner_surface[p->index_ymax] - p->scanner_surface[p->index_ymin];
+ width = height * p->ratio;
+ }
+
+ p->selection.coordinate[p->index_xmax] = p->selection.coordinate[p->index_xmin] + width;
+ if (p->selection.coordinate[p->index_xmax] > p->scanner_surface[p->index_xmax])
+ {
+ p->selection.coordinate[p->index_xmax] = p->scanner_surface[p->index_xmax];
+ p->selection.coordinate[p->index_xmin] = p->selection.coordinate[p->index_xmax] - width;
+ }
+
+ p->selection.coordinate[p->index_ymax] = p->selection.coordinate[p->index_ymin] + height;
+ if (p->selection.coordinate[p->index_ymax] > p->scanner_surface[p->index_ymax])
+ {
+ p->selection.coordinate[p->index_ymax] = p->scanner_surface[p->index_ymax];
+ p->selection.coordinate[p->index_ymin] = p->selection.coordinate[p->index_ymax] - height;
+ }
+
+ preview_draw_selection(p);
+ preview_establish_selection(p);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void preview_ratio_callback(GtkWidget *widget, gpointer data)
+{
+ Preview *p = data;
+ float *ratio;
+
+ DBG(DBG_proc, "preview_ratio_callback\n");
+
+ ratio = (float *) gtk_object_get_data(GTK_OBJECT(widget), "Selection");
+
+ p->ratio = *ratio;
+
+ preview_establish_ratio(p);
}
/* ---------------------------------------------------------------------------------------------------------------------- */
@@ -5092,8 +6222,8 @@ void preview_do_gamma_correction(Preview *p)
{
int x,y;
int offset;
- u_char *image_data_enhp;
- guint16 *image_data_rawp;
+ u_char *image_data_enhp = NULL;
+ guint16 *image_data_rawp = NULL;
int rotate = 16 - preview_gamma_input_bits;
DBG(DBG_proc, "preview_do_gamma_correction\n");
@@ -5142,7 +6272,10 @@ void preview_do_gamma_correction(Preview *p)
for (x=0; x < p->image_width; x++)
{
- level = ((*image_data_rawp++) + (*image_data_rawp++) + (*image_data_rawp++)) / 3;
+ level = (*image_data_rawp++); /* red */
+ level += (*image_data_rawp++); /* green */
+ level += (*image_data_rawp++); /* blue */
+ level /= 3;
level >>= rotate;
*image_data_enhp++ = preview_gamma_data_red [level]; /* use 12 bit gamma table */
*image_data_enhp++ = preview_gamma_data_green[level];
@@ -5619,11 +6752,28 @@ gint preview_area_resize_handler(GtkWidget *widget, GdkEvent *event, gpointer da
}
/* ---------------------------------------------------------------------------------------------------------------------- */
-#if 0
+
void preview_update_maximum_output_size(Preview *p)
{
+ float xxx = 0.0;
+ float yyy = 0.0;
+ float dxmin = 0;
+ float dymin = 0;
+ float dxmax = 0;
+ float dymax = 0;
+
+ int paper_orientation = 0;
+
+ if (p->block_update_maximum_output_size_clipping)
+ {
+ DBG(DBG_info, "preview_update_maximum_output_size: blocked\n");
+ return;
+ }
+
DBG(DBG_proc, "preview_update_maximum_output_size\n");
+ p->block_update_maximum_output_size_clipping = TRUE;
+
if ( (p->maximum_output_width >= INF) || (p->maximum_output_height >= INF) )
{
if (p->selection_maximum.active)
@@ -5631,127 +6781,384 @@ void preview_update_maximum_output_size(Preview *p)
p->selection_maximum.active = FALSE;
}
}
- else
+ else /* we have a maximum output size definition */
{
p->previous_selection_maximum = p->selection_maximum;
-
p->selection_maximum.active = TRUE;
- p->selection_maximum.coordinate[0] = (p->selection.coordinate[0] + p->selection.coordinate[2] - p->maximum_output_width )/2.0;
- p->selection_maximum.coordinate[1] = (p->selection.coordinate[1] + p->selection.coordinate[3] - p->maximum_output_height)/2.0;
- p->selection_maximum.coordinate[2] = (p->selection.coordinate[0] + p->selection.coordinate[2] + p->maximum_output_width )/2.0;
- p->selection_maximum.coordinate[3] = (p->selection.coordinate[1] + p->selection.coordinate[3] + p->maximum_output_height)/2.0;
- if (p->selection_maximum.coordinate[0] < p->max_scanner_surface[0])
+ if (p->paper_orientation & 4) /* center? */
{
- p->selection_maximum.coordinate[0] = p->max_scanner_surface[0];
+ paper_orientation = p->paper_orientation;
}
-
- if (p->selection_maximum.coordinate[1] < p->max_scanner_surface[1])
+ else /* not in center */
{
- p->selection_maximum.coordinate[1] = p->max_scanner_surface[1];
- }
+ switch (p->rotation)
+ {
+ default:
+ case 0: /* 0 degree */
+ paper_orientation = p->paper_orientation & 3;
+ break;
- if (p->selection_maximum.coordinate[2] > p->max_scanner_surface[2])
- {
- p->selection_maximum.coordinate[2] = p->max_scanner_surface[2];
+ case 1: /* 90 degree */
+ paper_orientation = (1 - p->paper_orientation) & 3;
+ break;
+
+ case 2: /* 180 degree */
+ paper_orientation = (2 + p->paper_orientation) & 3;
+ break;
+
+ case 3: /* 270 degree */
+ paper_orientation = (3 - p->paper_orientation) & 3;
+ break;
+
+ case 4: /* 0 degree, x mirror */
+ paper_orientation = (1 - p->paper_orientation) & 3;
+ break;
+
+ case 5: /* 90 degree, x mirror */
+ paper_orientation = p->paper_orientation & 3;
+ break;
+
+ case 6: /* 180 degree, x mirror */
+ paper_orientation = (3 - p->paper_orientation) & 3;
+ break;
+
+ case 7: /* 270 degree, x mirror */
+ paper_orientation = (2 + p->paper_orientation) & 3;
+ break;
+ }
}
- if (p->selection_maximum.coordinate[3] > p->max_scanner_surface[3])
+ switch (paper_orientation)
{
- p->selection_maximum.coordinate[3] = p->max_scanner_surface[3];
+ default:
+ case 0: /* top left portrait */
+ case 8: /* top left landscape */
+ xxx = 0.0;
+ yyy = 0.0;
+ break;
+
+ case 1: /* top right portrait */
+ case 9: /* top right landscape */
+ xxx = 1.0;
+ yyy = 0.0;
+ break;
+
+ case 2: /* bottom right portrait */
+ case 10: /* bottom right landscape */
+ xxx = 1.0;
+ yyy = 1.0;
+ break;
+
+ case 3: /* bottom left portrait */
+ case 11: /* bottom left landscape */
+ xxx = 0.0;
+ yyy = 1.0;
+ break;
+
+ case 4: /* center portrait */
+ case 12: /* center landscape */
+ xxx = 0.5;
+ yyy = 0.5;
+ break;
}
- if ( (p->selection.coordinate[0] < p->selection_maximum.coordinate[0]) ||
- (p->selection.coordinate[1] < p->selection_maximum.coordinate[1]) ||
- (p->selection.coordinate[2] > p->selection_maximum.coordinate[2]) ||
- (p->selection.coordinate[3] > p->selection_maximum.coordinate[3]) )
+ p->selection_maximum.coordinate[p->index_xmin] = p->selection.coordinate[p->index_xmin] + xxx *(-p->selection.coordinate[p->index_xmin] + p->selection.coordinate[p->index_xmax]) - p->maximum_output_width * xxx - dxmin;
+ p->selection_maximum.coordinate[p->index_ymin] = p->selection.coordinate[p->index_ymin] + yyy *(-p->selection.coordinate[p->index_ymin] + p->selection.coordinate[p->index_ymax]) - p->maximum_output_height * yyy - dymin;
+ p->selection_maximum.coordinate[p->index_xmax] = p->selection.coordinate[p->index_xmin] + xxx *(-p->selection.coordinate[p->index_xmin] + p->selection.coordinate[p->index_xmax]) + p->maximum_output_width * (1.0 - xxx) + dxmax;
+ p->selection_maximum.coordinate[p->index_ymax] = p->selection.coordinate[p->index_ymin] + yyy *(-p->selection.coordinate[p->index_ymin] + p->selection.coordinate[p->index_ymax]) + p->maximum_output_height * (1.0 - yyy) + dymax;
+
+
+ if ( (p->selection.coordinate[p->index_xmin] < p->selection_maximum.coordinate[p->index_xmin]) ||
+ (p->selection.coordinate[p->index_ymin] < p->selection_maximum.coordinate[p->index_ymin]) ||
+ (p->selection.coordinate[p->index_xmax] > p->selection_maximum.coordinate[p->index_xmax]) ||
+ (p->selection.coordinate[p->index_ymax] > p->selection_maximum.coordinate[p->index_ymax]) )
{
- if (p->selection.coordinate[0] < p->selection_maximum.coordinate[0])
+ int selection_changed = FALSE;
+
+ if (p->selection.coordinate[p->index_xmin] < p->selection_maximum.coordinate[p->index_xmin])
{
- p->selection.coordinate[0] = p->selection_maximum.coordinate[0];
+ p->selection.coordinate[p->index_xmin] = p->selection_maximum.coordinate[p->index_xmin];
+ selection_changed = TRUE;
}
- if (p->selection.coordinate[1] < p->selection_maximum.coordinate[1])
+ if (p->selection.coordinate[p->index_ymin] < p->selection_maximum.coordinate[p->index_ymin])
{
- p->selection.coordinate[1] = p->selection_maximum.coordinate[1];
+ p->selection.coordinate[p->index_ymin] = p->selection_maximum.coordinate[p->index_ymin];
+ selection_changed = TRUE;
}
- if (p->selection.coordinate[2] > p->selection_maximum.coordinate[2])
+ if (p->selection.coordinate[p->index_xmax] > p->selection_maximum.coordinate[p->index_xmax])
{
- p->selection.coordinate[2] = p->selection_maximum.coordinate[2];
+ p->selection.coordinate[p->index_xmax] = p->selection_maximum.coordinate[p->index_xmax];
+ selection_changed = TRUE;
}
- if (p->selection.coordinate[3] > p->selection_maximum.coordinate[3])
+ if (p->selection.coordinate[p->index_ymax] > p->selection_maximum.coordinate[p->index_ymax])
{
- p->selection.coordinate[3] = p->selection_maximum.coordinate[3];
+ p->selection.coordinate[p->index_ymax] = p->selection_maximum.coordinate[p->index_ymax];
+ selection_changed = TRUE;
}
+
preview_draw_selection(p);
- preview_establish_selection(p);
+
+ if (selection_changed)
+ {
+ preview_establish_selection(p);
+ }
}
}
+
+ p->block_update_maximum_output_size_clipping=FALSE;
}
-#endif
+/* ---------------------------------------------------------------------------------------------------------------------- */
-void preview_update_maximum_output_size(Preview *p)
+void preview_set_maximum_output_size(Preview *p, float width, float height, int paper_orientation)
{
- if ( (p->maximum_output_width >= INF) || (p->maximum_output_height >= INF) )
+ /* witdh and height in device units */
+ DBG(DBG_proc, "preview_set_maximum_output_size\n");
+
+ p->maximum_output_width = width;
+ p->maximum_output_height = height;
+ p->paper_orientation = paper_orientation;
+
+ preview_update_maximum_output_size(p);
+ preview_draw_selection(p);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+#define AUTORAISE_ERROR 30
+void preview_autoraise_scanarea(Preview *p, int preview_x, int preview_y, float *autoselect_coord)
+{
+ int x, y;
+ int image_x, image_y;
+ int offset;
+ float average_color_r, average_color_g, average_color_b;
+ int count;
+ float error;
+ int top, bottom, left, right;
+ int top_ok, bottom_ok, left_ok, right_ok;
+ float xscale, yscale;
+
+ DBG(DBG_proc, "preview_autoraise_scanarea\n");
+
+ preview_transform_coordinate_window_to_image(p, preview_x, preview_y, &image_x, &image_y);
+
+ top_ok = FALSE;
+ bottom_ok = FALSE;
+ left_ok = FALSE;
+ right_ok = FALSE;
+
+ top = image_y - 5;
+ bottom = image_y + 5;
+ left = image_x - 5;
+ right = image_x + 5;
+
+
+ while (!(top_ok && bottom_ok && left_ok && right_ok))
{
- if (p->selection_maximum.active)
+ /* search top */
+ if (!top_ok)
{
- p->selection_maximum.active = FALSE;
+ top--;
}
- }
- else
- {
- p->previous_selection_maximum = p->selection_maximum;
- p->selection_maximum.active = TRUE;
- p->selection_maximum.coordinate[p->index_xmin] = p->selection.coordinate[p->index_xmin];
- p->selection_maximum.coordinate[p->index_ymin] = p->selection.coordinate[p->index_ymin];
- p->selection_maximum.coordinate[p->index_xmax] = p->selection.coordinate[p->index_xmin] + p->maximum_output_width;
- p->selection_maximum.coordinate[p->index_ymax] = p->selection.coordinate[p->index_ymin] + p->maximum_output_height;
+ top_ok = TRUE;
- if (p->selection_maximum.coordinate[p->index_xmax] > p->max_scanner_surface[p->index_xmax])
+ if (top <= 0)
{
- p->selection_maximum.coordinate[p->index_xmax] = p->max_scanner_surface[p->index_xmax];
+ top = 0;
+ }
+ else
+ {
+ average_color_r = average_color_g = average_color_b = 0;
+ count = 0;
+
+ for (x = left; x < right; x++)
+ {
+ offset = 3 * (top * p->image_width + x);
+ average_color_r += p->image_data_enh[offset + 0];
+ average_color_g += p->image_data_enh[offset + 1];
+ average_color_b += p->image_data_enh[offset + 2];
+ count++;
+ }
+
+ average_color_r /= count;
+ average_color_g /= count;
+ average_color_b /= count;
+
+ for (x = left; x < right; x++)
+ {
+ offset = 3 * (top * p->image_width + x);
+
+ error = fabs(p->image_data_enh[offset + 0] - average_color_r) +
+ fabs(p->image_data_enh[offset + 1] - average_color_g) +
+ fabs(p->image_data_enh[offset + 2] - average_color_b);
+
+ if (error > AUTORAISE_ERROR)
+ {
+ top_ok = FALSE;
+ break;
+ }
+ }
}
- if (p->selection_maximum.coordinate[p->index_ymax] > p->max_scanner_surface[p->index_ymax])
+ /* search bottom */
+ if (!bottom_ok)
{
- p->selection_maximum.coordinate[p->index_ymax] = p->max_scanner_surface[p->index_ymax];
+ bottom++;
}
- if ( (p->selection.coordinate[p->index_xmin] < p->selection_maximum.coordinate[p->index_xmin]) ||
- (p->selection.coordinate[p->index_ymin] < p->selection_maximum.coordinate[p->index_ymin]) ||
- (p->selection.coordinate[p->index_xmax] > p->selection_maximum.coordinate[p->index_xmax]) ||
- (p->selection.coordinate[p->index_ymax] > p->selection_maximum.coordinate[p->index_ymax]) )
+ bottom_ok = TRUE;
+
+ if (bottom >= p->image_height-1)
{
- if (p->selection.coordinate[p->index_xmax] > p->selection_maximum.coordinate[p->index_xmax])
+ bottom = p->image_height-1;
+ }
+ else
+ {
+ average_color_r = average_color_g = average_color_b = 0;
+ count = 0;
+
+ for (x = left; x < right; x++)
{
- p->selection.coordinate[p->index_xmax] = p->selection_maximum.coordinate[p->index_xmax];
+ offset = 3 * (bottom * p->image_width + x);
+ average_color_r += p->image_data_enh[offset + 0];
+ average_color_g += p->image_data_enh[offset + 1];
+ average_color_b += p->image_data_enh[offset + 2];
+ count++;
}
- if (p->selection.coordinate[p->index_ymax] > p->selection_maximum.coordinate[p->index_ymax])
+ average_color_r /= count;
+ average_color_g /= count;
+ average_color_b /= count;
+
+ for (x = left; x < right; x++)
{
- p->selection.coordinate[p->index_ymax] = p->selection_maximum.coordinate[p->index_ymax];
+ offset = 3 * (bottom * p->image_width + x);
+
+ error = fabs(p->image_data_enh[offset + 0] - average_color_r) +
+ fabs(p->image_data_enh[offset + 1] - average_color_g) +
+ fabs(p->image_data_enh[offset + 2] - average_color_b);
+
+ if (error > AUTORAISE_ERROR)
+ {
+ bottom_ok = FALSE;
+ break;
+ }
+ }
+ }
+
+ /* search left */
+ if (!left_ok)
+ {
+ left--;
+ }
+
+ left_ok = TRUE;
+
+ if (left <= 0)
+ {
+ left = 0;
+ }
+ else
+ {
+ average_color_r = average_color_g = average_color_b = 0;
+ count = 0;
+
+ for (y = top; y < bottom; y++)
+ {
+ offset = 3 * (left + y * p->image_width);
+ average_color_r += p->image_data_enh[offset + 0];
+ average_color_g += p->image_data_enh[offset + 1];
+ average_color_b += p->image_data_enh[offset + 2];
+ count++;
+ }
+
+ average_color_r /= count;
+ average_color_g /= count;
+ average_color_b /= count;
+
+ for (y = top; y < bottom; y++)
+ {
+ offset = 3 * (left + y * p->image_width);
+
+ error = fabs(p->image_data_enh[offset + 0] - average_color_r) +
+ fabs(p->image_data_enh[offset + 1] - average_color_g) +
+ fabs(p->image_data_enh[offset + 2] - average_color_b);
+
+ if (error > AUTORAISE_ERROR)
+ {
+ left_ok = FALSE;
+ break;
+ }
+ }
+ }
+
+ /* search right */
+ if (!right_ok)
+ {
+ right++;
+ }
+
+ right_ok = TRUE;
+
+ if (right >= p->image_width-1)
+ {
+ right = p->image_width-1;
+ }
+ else
+ {
+ average_color_r = average_color_g = average_color_b = 0;
+ count = 0;
+
+ for (y = top; y < bottom; y++)
+ {
+ offset = 3 * (right + y * p->image_width);
+ average_color_r += p->image_data_enh[offset + 0];
+ average_color_g += p->image_data_enh[offset + 1];
+ average_color_b += p->image_data_enh[offset + 2];
+ count++;
+ }
+
+ average_color_r /= count;
+ average_color_g /= count;
+ average_color_b /= count;
+
+ for (y = top; y < bottom; y++)
+ {
+ offset = 3 * (right + y * p->image_width);
+
+ error = fabs(p->image_data_enh[offset + 0] - average_color_r) +
+ fabs(p->image_data_enh[offset + 1] - average_color_g) +
+ fabs(p->image_data_enh[offset + 2] - average_color_b);
+
+ if (error > AUTORAISE_ERROR)
+ {
+ right_ok = FALSE;
+ break;
+ }
}
- preview_draw_selection(p);
- preview_establish_selection(p);
}
}
-}
-/* ---------------------------------------------------------------------------------------------------------------------- */
-void preview_set_maximum_output_size(Preview *p, float width, float height)
-{
- /* witdh and height in device units */
- DBG(DBG_proc, "preview_set_maximum_output_size\n");
- p->maximum_output_width = width;
- p->maximum_output_height = height;
+ preview_get_scale_device_to_image(p, &xscale, &yscale);
- preview_update_maximum_output_size(p);
- preview_draw_selection(p);
+ if (((p->rotation & 3) == 0) || ((p->rotation & 3) == 2)) /* 0 or 180 degree */
+ {
+ *(autoselect_coord+0) = p->image_surface[0] + left / xscale;
+ *(autoselect_coord+2) = p->image_surface[0] + right / xscale;
+ *(autoselect_coord+1) = p->image_surface[1] + top / yscale;
+ *(autoselect_coord+3) = p->image_surface[1] + bottom / yscale;
+ }
+ else /* 90 or 270 degree */
+ {
+ *(autoselect_coord+1) = p->image_surface[1] + left / xscale;
+ *(autoselect_coord+3) = p->image_surface[1] + right / xscale;
+ *(autoselect_coord+0) = p->image_surface[0] + top / yscale;
+ *(autoselect_coord+2) = p->image_surface[0] + bottom / yscale;
+ }
}
/* ---------------------------------------------------------------------------------------------------------------------- */
@@ -5932,6 +7339,15 @@ void preview_autoselect_scanarea(Preview *p, float *autoselect_coord)
}
}
+ if ( (top >= bottom) || (right <= left) ) /* empty selection: use complete image */
+ {
+ DBG(DBG_info, "autoselect_scanarea: empty selection: using complete area\n");
+ top = 0;
+ bottom = p->image_height -1;
+ left = 0;
+ right = p->image_width -1;
+ }
+
preview_get_scale_device_to_image(p, &xscale, &yscale);
if (((p->rotation & 3) == 0) || ((p->rotation & 3) == 2)) /* 0 or 180 degree */