diff options
Diffstat (limited to 'frontend/xsane-scan.c')
-rw-r--r-- | frontend/xsane-scan.c | 2369 |
1 files changed, 0 insertions, 2369 deletions
diff --git a/frontend/xsane-scan.c b/frontend/xsane-scan.c deleted file mode 100644 index d66ab28..0000000 --- a/frontend/xsane-scan.c +++ /dev/null @@ -1,2369 +0,0 @@ -/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend - - xsane-scan.c - - Oliver Rauch <Oliver.Rauch@Wolfsburg.DE> - Copyright (C) 1998-2000 Oliver Rauch - This file is part of the XSANE package. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#include "xsane.h" -#include "xsane-back-gtk.h" -#include "xsane-front-gtk.h" -#include "xsane-preferences.h" -#include "xsane-preview.h" -#include "xsane-save.h" -#include "xsane-text.h" -#include "xsane-gamma.h" -#include "xsane-setup.h" - -#ifdef HAVE_LIBPNG -#ifdef HAVE_LIBZ -#include <png.h> -#include <zlib.h> -#endif -#endif - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef HAVE_LIBGIMP_GIMP_H - -#include <libgimp/gimp.h> - -static void xsane_gimp_query(void); -static void xsane_gimp_run(char *name, int nparams, GParam * param, int *nreturn_vals, GParam ** return_vals); - -GPlugInInfo PLUG_IN_INFO = -{ - NULL, /* init_proc */ - NULL, /* quit_proc */ - xsane_gimp_query, /* query_proc */ - xsane_gimp_run, /* run_proc */ -}; - -#endif /* HAVE_LIBGIMP_GIMP_H */ - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* forward declarations: */ - -static int xsane_generate_dummy_filename(); -#ifdef HAVE_LIBGIMP_GIMP_H -static int xsane_decode_devname(const char *encoded_devname, int n, char *buf); -static int xsane_encode_devname(const char *devname, int n, char *buf); -void null_print_func(gchar *msg); -static void xsane_gimp_advance(void); -#endif -static void xsane_read_image_data(gpointer data, gint source, GdkInputCondition cond); -static RETSIGTYPE xsane_sigpipe_handler(int signal); -static int xsane_test_multi_scan(void); -void xsane_scan_done(SANE_Status status); -void xsane_cancel(void); -static void xsane_start_scan(void); -void xsane_scan_dialog(GtkWidget * widget, gpointer call_data); - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_generate_dummy_filename() -{ - /* returns TRUE if file is a temporary file */ - - if (xsane.dummy_filename) - { - free(xsane.dummy_filename); - } - - if ( (xsane.xsane_mode == XSANE_COPY) || (xsane.xsane_mode == XSANE_FAX) || /* we have to do a conversion */ - ( (xsane.xsane_mode == XSANE_SCAN) && (xsane.xsane_output_format != XSANE_PNM) && - (xsane.xsane_output_format != XSANE_RAW16) && (xsane.xsane_output_format != XSANE_RGBA) ) ) - { - char filename[PATH_MAX]; - - xsane_back_gtk_make_path(sizeof(filename), filename, 0, 0, "conversion-", dialog->dev_name, ".ppm", XSANE_PATH_TMP); - xsane.dummy_filename = strdup(filename); - return TRUE; - } - else /* no conversion following, save directly to the selected filename */ - { - xsane.dummy_filename = strdup(xsane.output_filename); - return FALSE; - } -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -#ifdef HAVE_LIBGIMP_GIMP_H -static int xsane_decode_devname(const char *encoded_devname, int n, char *buf) -{ - char *dst, *limit; - const char *src; - char ch, val; - - limit = buf + n; - for (src = encoded_devname, dst = buf; *src; ++dst) - { - if (dst >= limit) - { - return -1; - } - - ch = *src++; - /* don't use the ctype.h macros here since we don't want to allow anything non-ASCII here... */ - if (ch != '-') - { - *dst = ch; - } - else /* decode */ - { - ch = *src++; - if (ch == '-') - { - *dst = ch; - } - else - { - if (ch >= 'a' && ch <= 'f') - { - val = (ch - 'a') + 10; - } - else - { - val = (ch - '0'); - } - val <<= 4; - - ch = *src++; - if (ch >= 'a' && ch <= 'f') - { - val |= (ch - 'a') + 10; - } - else - { - val |= (ch - '0'); - } - - *dst = val; - - ++src; /* simply skip terminating '-' for now... */ - } - } - } - - if (dst >= limit) - { - return -1; - } - - *dst = '\0'; - return 0; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_encode_devname(const char *devname, int n, char *buf) -{ - static const char hexdigit[] = "0123456789abcdef"; - char *dst, *limit; - const char *src; - char ch; - - limit = buf + n; - for (src = devname, dst = buf; *src; ++src) - { - if (dst >= limit) - { - return -1; - } - - ch = *src; - /* don't use the ctype.h macros here since we don't want to allow anything non-ASCII here... */ - if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) - { - *dst++ = ch; - } - else /* encode */ - { - if (dst + 4 >= limit) - { - return -1; - } - - *dst++ = '-'; - if (ch == '-') - { - *dst++ = '-'; - } - else - { - *dst++ = hexdigit[(ch >> 4) & 0x0f]; - *dst++ = hexdigit[(ch >> 0) & 0x0f]; - *dst++ = '-'; - } - } - } - - if (dst >= limit) - { - return -1; - } - - *dst = '\0'; - return 0; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static void xsane_gimp_query(void) -{ - static GParamDef args[] = - { - {PARAM_INT32, "run_mode", "Interactive, non-interactive"}, - }; - static GParamDef *return_vals = NULL; - static int nargs = sizeof(args) / sizeof(args[0]); - static int nreturn_vals = 0; - char mpath[1024]; - char name[1024]; - size_t len; - int i, j; - - snprintf(name, sizeof(name), "%s", prog_name); -#ifdef GIMP_CHECK_VERSION -# if GIMP_CHECK_VERSION(1,1,9) - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_DIALOG); -# else - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_DIALOG_OLD); -# endif -#else - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_DIALOG_OLD); -#endif - gimp_install_procedure(name, - XSANE_GIMP_INSTALL_BLURB, - XSANE_GIMP_INSTALL_HELP, - XSANE_AUTHOR, - XSANE_COPYRIGHT, - XSANE_DATE, - mpath, - 0, /* "RGB, GRAY", */ - PROC_EXTENSION, - nargs, nreturn_vals, - args, return_vals); - - sane_init(&xsane.sane_backend_versioncode, (void *) xsane_authorization_callback); - if (SANE_VERSION_MAJOR(xsane.sane_backend_versioncode) != SANE_V_MAJOR) - { - fprintf(stderr, "\n\n" - "%s %s:\n" - " %s\n" - " %s %d\n" - " %s %d\n" - "%s\n\n", - prog_name, ERR_ERROR, - ERR_MAJOR_VERSION_NR_CONFLICT, - ERR_XSANE_MAJOR_VERSION, SANE_V_MAJOR, - ERR_BACKEND_MAJOR_VERSION, SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), - ERR_PROGRAM_ABORTED); - return; - } - - sane_get_devices(&devlist, SANE_FALSE); - - for (i = 0; devlist[i]; ++i) - { - snprintf(name, sizeof(name), "%s-", prog_name); - if (xsane_encode_devname(devlist[i]->name, sizeof(name) - 6, name + 6) < 0) - { - continue; /* name too long... */ - } - -#ifdef GIMP_CHECK_VERSION -# if GIMP_CHECK_VERSION(1,1,9) - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU); -# else - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_OLD); -# endif -#else - snprintf(mpath, sizeof(mpath), "%s", XSANE_GIMP_MENU_OLD); -#endif - len = strlen(mpath); - for (j = 0; devlist[i]->name[j]; ++j) - { - if (devlist[i]->name[j] == '/') - mpath[len++] = '\''; - else - mpath[len++] = devlist[i]->name[j]; - } - mpath[len++] = '\0'; - - gimp_install_procedure(name, - XSANE_GIMP_INSTALL_BLURB, - XSANE_GIMP_INSTALL_HELP, - XSANE_AUTHOR, - XSANE_COPYRIGHT, - XSANE_DATE, - mpath, - "RGB, GRAY", - PROC_EXTENSION, - nargs, nreturn_vals, - args, return_vals); - } - sane_exit(); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static void xsane_gimp_run(char *name, int nparams, GParam * param, int *nreturn_vals, GParam ** return_vals) -{ - static GParam values[2]; - GRunModeType run_mode; - char devname[1024]; - char *args[2]; - int nargs; - - run_mode = param[0].data.d_int32; - xsane.mode = XSANE_GIMP_EXTENSION; - - *nreturn_vals = 1; - *return_vals = values; - - values[0].type = PARAM_STATUS; - values[0].data.d_status = STATUS_CALLING_ERROR; - - nargs = 0; - args[nargs++] = "xsane"; - - seldev = -1; - if (strncmp(name, "xsane-", 6) == 0) - { - if (xsane_decode_devname(name + 6, sizeof(devname), devname) < 0) - { - return; /* name too long */ - } - args[nargs++] = devname; - } - - switch (run_mode) - { - case RUN_INTERACTIVE: - xsane_interface(nargs, args); - values[0].data.d_status = STATUS_SUCCESS; - break; - - case RUN_NONINTERACTIVE: - /* Make sure all the arguments are there! */ - break; - - case RUN_WITH_LAST_VALS: - /* Possibly retrieve data */ - break; - - default: - break; - } -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void null_print_func(gchar *msg) -{ -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static void xsane_gimp_advance(void) -{ - if (++xsane.x >= xsane.param.pixels_per_line) - { - int tile_height = gimp_tile_height(); - - xsane.x = 0; - ++xsane.y; - if (xsane.y % tile_height == 0) - { - gimp_pixel_rgn_set_rect(&xsane.region, xsane.tile, 0, xsane.y - tile_height, xsane.param.pixels_per_line, tile_height); - if (xsane.param.format >= SANE_FRAME_RED && xsane.param.format <= SANE_FRAME_BLUE) - { - int height; - - xsane.tile_offset %= 3; - - if (!xsane.first_frame) /* get the data for the existing tile: */ - { - height = tile_height; - - if (xsane.y + height >= xsane.param.lines) - { - height = xsane.param.lines - xsane.y; - } - - gimp_pixel_rgn_get_rect(&xsane.region, xsane.tile, 0, xsane.y, xsane.param.pixels_per_line, height); - } - } - else - { - xsane.tile_offset = 0; - } - } - } -} - -#endif /* HAVE_LIBGIMP_GIMP_H */ - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static void xsane_read_image_data(gpointer data, gint source, GdkInputCondition cond) -{ - SANE_Handle dev = xsane_back_gtk_dialog_get_device (dialog); - SANE_Status status; - SANE_Int len; - int i; - char buf[255]; - - if ( (xsane.param.depth == 1) || (xsane.param.depth == 8) ) - { - static unsigned char buf8[32768]; - - while (1) - { - status = sane_read(dev, (SANE_Byte *) buf8, sizeof(buf8), &len); - if (status == SANE_STATUS_EOF) - { - if (!xsane.param.last_frame) - { - xsane_start_scan(); - break; /* leave while loop */ - } - - xsane_scan_done(SANE_STATUS_EOF); /* image complete, stop scanning */ - return; - } - - if (status != SANE_STATUS_GOOD) - { - xsane_scan_done(status); /* status = return of sane_read */ - snprintf(buf, sizeof(buf), "%s %s.", ERR_DURING_READ, XSANE_STRSTATUS(status)); - xsane_back_gtk_error(buf, TRUE); - return; - } - - if (!len) - { - break; /* out of data for now, leave while loop */ - } - - xsane.bytes_read += len; - xsane_progress_update(xsane.progress, xsane.bytes_read / (gfloat) xsane.num_bytes); - - if (xsane.input_tag < 0) - { - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } - - switch (xsane.param.format) - { - case SANE_FRAME_GRAY: - if (xsane.mode == XSANE_STANDALONE) - { - int i; - char val; - - if ((!xsane.scanner_gamma_gray) && (xsane.param.depth > 1)) - { - for (i=0; i < len; ++i) - { - val = xsane.gamma_data[(int) buf8[i]]; - fwrite(&val, 1, 1, xsane.out); - } - } - else - { - fwrite(buf8, 1, len, xsane.out); - } - } -#ifdef HAVE_LIBGIMP_GIMP_H - else /* GIMP MODE GRAY 8 bit */ - { - switch (xsane.param.depth) - { - case 1: - for (i = 0; i < len; ++i) - { - u_char mask; - int j; - - mask = buf8[i]; - for (j = 7; j >= 0; --j) - { - u_char gl = (mask & (1 << j)) ? 0x00 : 0xff; - xsane.tile[xsane.tile_offset++] = gl; - xsane_gimp_advance(); - if (xsane.x == 0) - { - break; - } - } - } - break; - - case 8: - if (!xsane.scanner_gamma_gray) - { - for (i = 0; i < len; ++i) - { - xsane.tile[xsane.tile_offset++] = xsane.gamma_data[(int) buf8[i]]; - xsane_gimp_advance(); - } - } - else - { - for (i = 0; i < len; ++i) - { - xsane.tile[xsane.tile_offset++] = buf8[i]; - xsane_gimp_advance(); - } - } - break; - } - } -#endif /* HAVE_LIBGIMP_GIMP_H */ - break; - - case SANE_FRAME_RGB: - if (xsane.mode == XSANE_STANDALONE) - { - int i; - char val; - - if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ - { - for (i=0; i < len; ++i) - { - if (dialog->pixelcolor == 0) - { - val = xsane.gamma_data_red[(int) buf8[i]]; - dialog->pixelcolor++; - } - else if (dialog->pixelcolor == 1) - { - val = xsane.gamma_data_green[(int) buf8[i]]; - dialog->pixelcolor++; - } - else - { - val = xsane.gamma_data_blue[(int) buf8[i]]; - dialog->pixelcolor = 0; - } - fwrite(&val, 1, 1, xsane.out); - } - } - else /* gamma correction has been done by scanner */ - { - fwrite(buf8, 1, len, xsane.out); - } - } -#ifdef HAVE_LIBGIMP_GIMP_H - else /* GIMP MODE RGB 8 bit */ - { - switch (xsane.param.depth) - { - case 1: - if (xsane.param.format == SANE_FRAME_RGB) - { - goto bad_depth; - } - for (i = 0; i < len; ++i) - { - u_char mask; - int j; - - mask = buf8[i]; - for (j = 0; j < 8; ++j) - { - u_char gl = (mask & 1) ? 0xff : 0x00; - mask >>= 1; - xsane.tile[xsane.tile_offset++] = gl; - xsane_gimp_advance(); - if (xsane.x == 0) - break; - } - } - break; - - case 8: - if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ - { - for (i = 0; i < len; ++i) - { - if (xsane.tile_offset % 3 == 0) - { - xsane.tile[xsane.tile_offset++] = xsane.gamma_data_red[(int) buf8[i]]; - } - else if (xsane.tile_offset % 3 == 1) - { - xsane.tile[xsane.tile_offset++] = xsane.gamma_data_green[(int) buf8[i]]; - } - else - { - xsane.tile[xsane.tile_offset++] = xsane.gamma_data_blue[(int) buf8[i]]; - } - - if (xsane.tile_offset % 3 == 0) - { - xsane_gimp_advance(); - } - } - } - else /* gamma correction by scanner */ - { - for (i = 0; i < len; ++i) - { - xsane.tile[xsane.tile_offset++] = buf8[i]; - if (xsane.tile_offset % 3 == 0) - { - xsane_gimp_advance(); - } - } - } - break; - - default: - goto bad_depth; - break; - } - } -#endif /* HAVE_LIBGIMP_GIMP_H */ - break; - - case SANE_FRAME_RED: - case SANE_FRAME_GREEN: - case SANE_FRAME_BLUE: - if (xsane.mode == XSANE_STANDALONE) - { - if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ - { - char val; - SANE_Int *gamma; - - if (xsane.param.format == SANE_FRAME_RED) - { - gamma = xsane.gamma_data_red; - } - else if (xsane.param.format == SANE_FRAME_GREEN) - { - gamma = xsane.gamma_data_green; - } - else - { - gamma = xsane.gamma_data_blue; - } - - for (i = 0; i < len; ++i) - { - val = gamma[(int) buf8[i]]; - fwrite(&val, 1, 1, xsane.out); - fseek(xsane.out, 2, SEEK_CUR); - } - } - else /* gamma correction by scanner */ - { - for (i = 0; i < len; ++i) - { - fwrite(&buf8[i], 1, 1, xsane.out); - fseek(xsane.out, 2, SEEK_CUR); - } - } - } -#ifdef HAVE_LIBGIMP_GIMP_H - else /* GIMP MODE RED, GREEN, BLUE (3PASS) 8 bit */ - { - switch (xsane.param.depth) - { - case 1: - for (i = 0; i < len; ++i) - { - u_char mask; - int j; - - mask = buf8[i]; - for (j = 0; j < 8; ++j) - { - u_char gl = (mask & 1) ? 0xff : 0x00; - mask >>= 1; - xsane.tile[xsane.tile_offset] = gl; - xsane.tile_offset += 3; - xsane_gimp_advance(); - if (xsane.x == 0) - { - break; - } - } - } - break; - - case 8: - if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ - { - SANE_Int *gamma; - - if (xsane.param.format == SANE_FRAME_RED) - { - gamma = xsane.gamma_data_red; - } - else if (xsane.param.format == SANE_FRAME_GREEN) - { - gamma = xsane.gamma_data_green; - } - else - { - gamma = xsane.gamma_data_blue; - } - - for (i = 0; i < len; ++i) - { - xsane.tile[xsane.tile_offset] = gamma[(int) buf8[i]]; - xsane.tile_offset += 3; - xsane_gimp_advance(); - } - } - else /* gamma correction by scanner */ - { - for (i = 0; i < len; ++i) - { - xsane.tile[xsane.tile_offset] = buf8[i]; - xsane.tile_offset += 3; - xsane_gimp_advance(); - } - } - break; - - default: - goto bad_depth; - break; - } - } -#endif /* HAVE_LIBGIMP_GIMP_H */ - break; - -#ifdef SUPPORT_RGBA - case SANE_FRAME_RGBA: /* Scanning including Infrared channel */ - if (xsane.mode == XSANE_STANDALONE) - { - int i; - char val; - - if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ - { - for (i=0; i < len; ++i) - { - if (dialog->pixelcolor == 0) - { - val = xsane.gamma_data_red[(int) buf8[i]]; - dialog->pixelcolor++; - } - else if (dialog->pixelcolor == 1) - { - val = xsane.gamma_data_green[(int) buf8[i]]; - dialog->pixelcolor++; - } - else if (dialog->pixelcolor == 2) - { - val = xsane.gamma_data_blue[(int) buf8[i]]; - dialog->pixelcolor++; - } - else - { - val = buf8[i]; /* no gamma table for infrared channel */ - dialog->pixelcolor = 0; - } - fwrite(&val, 1, 1, xsane.out); - } - } - else /* gamma correction has been done by scanner */ - { - fwrite(buf8, 1, len, xsane.out); - } - } -#ifdef HAVE_LIBGIMP_GIMP_H - else /* GIMP MODE RGBA 8 bit */ - { - int i; - - - switch (xsane.param.depth) - { - case 8: - if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ - { - for (i=0; i < len; ++i) - { - if (xsane.tile_offset % 4 == 0) - { - xsane.tile[xsane.tile_offset++] = xsane.gamma_data_red[(int) buf8[i]]; - } - else if (xsane.tile_offset % 4 == 1) - { - xsane.tile[xsane.tile_offset++] = xsane.gamma_data_green[(int) buf8[i]]; - } - else if (xsane.tile_offset % 4 == 2) - { - xsane.tile[xsane.tile_offset++] = xsane.gamma_data_blue[(int) buf8[i]]; - } - else - { - xsane.tile[xsane.tile_offset++] = buf8[i]; /* no gamma table for infrared channel */ - } - - if (xsane.tile_offset % 4 == 0) - { - xsane_gimp_advance(); - } - } - } - else /* gamma correction has been done by scanner */ - { - for (i = 0; i < len; ++i) - { - xsane.tile[xsane.tile_offset++] = buf8[i]; - if (xsane.tile_offset % 4 == 0) - { - xsane_gimp_advance(); - } - } - } - break; - - default: - goto bad_depth; - break; - } - } -#endif /* HAVE_LIBGIMP_GIMP_H */ - break; -#endif - - default: - xsane_scan_done(-1); /* -1 = error */ - fprintf(stderr, "xsane_read_image_data: %s %d\n", ERR_BAD_FRAME_FORMAT, xsane.param.format); - return; - break; - } - } - } - else if ( xsane.param.depth == 16 ) - { - static guint16 buf16[32768]; - char buf[255]; - char last = 0; - int offset = 0; - - while (1) - { - if (offset) /* if we have had an odd number of bytes */ - { - buf16[0] = last; - status = sane_read(dev, (SANE_Byte *) (buf16 + 1), sizeof(buf16) - 1, &len); - if (len) - { - len++; - } - } - else /* last read we had an even number of bytes */ - { - status = sane_read(dev, (SANE_Byte *) buf16, sizeof(buf16), &len); - } - - if (len % 2) /* odd number of bytes */ - { - len--; - last = buf16[len]; - offset = 1; - } - else /* even number of bytes */ - { - offset = 0; - } - - if (status == SANE_STATUS_EOF) - { - if (!xsane.param.last_frame) - { - xsane_start_scan(); - break; /* leave while loop */ - } - - xsane_scan_done(SANE_STATUS_EOF); /* image complete, stop scanning */ - return; - } - - if (status != SANE_STATUS_GOOD) - { - xsane_scan_done(status); /* status = return of sane_read */ - snprintf(buf, sizeof(buf), "%s %s.", ERR_DURING_READ, XSANE_STRSTATUS(status)); - xsane_back_gtk_error(buf, TRUE); - return; - } - - if (!len) /* nothing read */ - { - break; /* out of data for now, leave while loop */ - } - - xsane.bytes_read += len; - xsane_progress_update(xsane.progress, xsane.bytes_read / (gfloat) xsane.num_bytes); - - if (xsane.input_tag < 0) - { - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } - - switch (xsane.param.format) - { - case SANE_FRAME_GRAY: - if (xsane.mode == XSANE_STANDALONE) - { - int i; - guint16 val; - - if (!xsane.scanner_gamma_gray) /* gamma correction by xsane */ - { - for (i=0; i < len/2; ++i) - { - val = xsane.gamma_data[buf16[i]]; - fwrite(&val, 2, 1, xsane.out); - } - } - else /* gamma correction by scanner */ - { - fwrite(buf16, 2, len/2, xsane.out); - } - } - break; - - case SANE_FRAME_RGB: - if (xsane.mode == XSANE_STANDALONE) - { - int i; - guint16 val; - - if (!xsane.scanner_gamma_color) /* gamma correction by xsane */ - { - for (i=0; i < len/2; ++i) - { - if (dialog->pixelcolor == 0) - { - val = xsane.gamma_data_red[buf16[i]]; - dialog->pixelcolor++; - } - else if (dialog->pixelcolor == 1) - { - val = xsane.gamma_data_green[buf16[i]]; - dialog->pixelcolor++; - } - else - { - val = xsane.gamma_data_blue[buf16[i]]; - dialog->pixelcolor = 0; - } - fwrite(&val, 2, 1, xsane.out); - } - } - else /* gamma correction by scanner */ - { - fwrite(buf16, 2, len/2, xsane.out); - } - } - break; - - case SANE_FRAME_RED: - case SANE_FRAME_GREEN: - case SANE_FRAME_BLUE: - if (xsane.mode == XSANE_STANDALONE) - { - for (i = 0; i < len/2; ++i) - { - fwrite(buf16 + i*2, 2, 1, xsane.out); - fseek(xsane.out, 4, SEEK_CUR); - } - } - break; - -#ifdef SUPPORT_RGBA - case SANE_FRAME_RGBA: - if (xsane.mode == XSANE_STANDALONE) - { - int i; - guint16 val; - - if (!xsane.scanner_gamma_color) - { - for (i=0; i < len/2; ++i) - { - if (dialog->pixelcolor == 0) - { - val = xsane.gamma_data_red[buf16[i]]; - dialog->pixelcolor++; - } - else if (dialog->pixelcolor == 1) - { - val = xsane.gamma_data_green[buf16[i]]; - dialog->pixelcolor++; - } - else if (dialog->pixelcolor == 2) - { - val = xsane.gamma_data_blue[buf16[i]]; - dialog->pixelcolor++; - } - else - { - val = buf16[i]; /* no gamma table for infrared channel */ - dialog->pixelcolor = 0; - } - fwrite(&val, 2, 1, xsane.out); - } - } - else - { - fwrite(buf16, 2, len/2, xsane.out); - } - } - break; -#endif - - default: - xsane_scan_done(-1); /* -1 = error */ - fprintf(stderr, "xsane_read_image_data: %s %d\n", ERR_BAD_FRAME_FORMAT, xsane.param.format); - return; - break; - } - } - } - else - { - xsane_scan_done(-1); /* -1 = error */ - snprintf(buf, sizeof(buf), "%s %d.", ERR_BAD_DEPTH, xsane.param.depth); - xsane_back_gtk_error(buf, TRUE); - return; - } - - return; - - /* ---------------------- */ - -#ifdef HAVE_LIBGIMP_GIMP_H -bad_depth: - - xsane_scan_done(-1); /* -1 = error */ - snprintf(buf, sizeof(buf), "%s %d.", ERR_BAD_DEPTH, xsane.param.depth); - xsane_back_gtk_error(buf, TRUE); - return; -#endif -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static RETSIGTYPE xsane_sigpipe_handler(int signal) -/* this is to catch a broken pipe while writing to printercommand */ -{ - xsane_cancel_save(0); - xsane.broken_pipe = 1; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static int xsane_test_multi_scan(void) -{ - char *set; - SANE_Status status; - const SANE_Option_Descriptor *opt; - - opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.scansource); - if (opt) - { - if (SANE_OPTION_IS_ACTIVE(opt->cap)) - { - if (opt->constraint_type == SANE_CONSTRAINT_STRING_LIST) - { - set = malloc(opt->size); - status = sane_control_option(dialog->dev, dialog->well_known.scansource, SANE_ACTION_GET_VALUE, set, 0); - - if (status == SANE_STATUS_GOOD) - { - if (!strcmp(set, SANE_NAME_DOCUMENT_FEEDER)) - { - return TRUE; - } - } - free(set); - } - } - } - -#if 0 /* this is planned for the next sane-standard */ - if (xsane.param.bitfield & XSANE_PARAM_STATUS_MORE_IMAGES) - { - return TRUE; - } -#endif - - return FALSE; -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_scan_done(SANE_Status status) -{ - if (xsane.input_tag >= 0) - { - gdk_input_remove(xsane.input_tag); - xsane.input_tag = -1; - } - - if (xsane.progress) /* remove progressbar */ - { - xsane_progress_free(xsane.progress); - xsane.progress = 0; - } - - while(gtk_events_pending()) /* let gtk remove the progress bar and update everything that needs it */ - { - gtk_main_iteration(); - } - - - /* we have to free the gamma tables if we used software gamma correction */ - - if (xsane.gamma_data) - { - free(xsane.gamma_data); - xsane.gamma_data = 0; - } - - if (xsane.gamma_data_red) - { - free(xsane.gamma_data_red); - free(xsane.gamma_data_green); - free(xsane.gamma_data_blue); - - xsane.gamma_data_red = 0; - xsane.gamma_data_green = 0; - xsane.gamma_data_blue = 0; - } - - if (xsane.out) /* close file - this is dummy_file but if there is no conversion it is the wanted file */ - { - fclose(xsane.out); - xsane.out = 0; - } - - if ( (status == SANE_STATUS_GOOD) || (status == SANE_STATUS_EOF) ) /* no error, do conversion etc. */ - { - if (xsane.mode == XSANE_STANDALONE) - { - if ( (xsane.xsane_mode == XSANE_SCAN) && (xsane.xsane_output_format != XSANE_PNM) && - (xsane.xsane_output_format != XSANE_RAW16) && (xsane.xsane_output_format != XSANE_RGBA) ) - { - FILE *outfile; - FILE *infile; - char buf[256]; - - /* open progressbar */ - snprintf(buf, sizeof(buf), PROGRESS_SAVING); - xsane.progress = xsane_progress_new(PROGRESS_CONVERTING_DATA, buf, (GtkSignalFunc) xsane_cancel_save, 0); - xsane_progress_update(xsane.progress, 0); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - infile = fopen(xsane.dummy_filename, "r"); - if (infile != 0) - { - fseek(infile, xsane.header_size, SEEK_SET); - -#ifdef HAVE_LIBTIFF - if (xsane.xsane_output_format == XSANE_TIFF) /* routines that want to have filename for saving */ - { - if (xsane.param.depth != 1) - { - remove(xsane.output_filename); - umask(preferences.image_umask); /* define image file permissions */ - xsane_save_tiff(xsane.output_filename, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, - xsane.param.lines, preferences.tiff_compression_nr, preferences.jpeg_quality); - umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ - } - else - { - remove(xsane.output_filename); - umask(preferences.image_umask); /* define image file permissions */ - xsane_save_tiff(xsane.output_filename, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, - xsane.param.lines, preferences.tiff_compression_1_nr, preferences.jpeg_quality); - umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ - } - } - else /* routines that want to have filedescriptor for saving */ -#endif - { - remove(xsane.output_filename); - umask(preferences.image_umask); /* define image file permissions */ - outfile = fopen(xsane.output_filename, "w"); - umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ - - if (outfile != 0) - { - switch(xsane.xsane_output_format) - { -#ifdef HAVE_LIBJPEG - case XSANE_JPEG: - xsane_save_jpeg(outfile, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, - xsane.param.lines, preferences.jpeg_quality); - break; -#endif - -#ifdef HAVE_LIBPNG -#ifdef HAVE_LIBZ - case XSANE_PNG: - if (xsane.param.depth <= 8) - { - xsane_save_png(outfile, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, - xsane.param.lines, preferences.png_compression); - } - else - { - xsane_save_png_16(outfile, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, - xsane.param.lines, preferences.png_compression); - } - break; -#endif -#endif - - case XSANE_PNM16: - xsane_save_pnm_16(outfile, infile, xsane.xsane_color, xsane.param.depth, xsane.param.pixels_per_line, - xsane.param.lines); - break; - - case XSANE_PS: /* save postscript, use original size */ - { - float imagewidth = xsane.param.pixels_per_line/xsane.resolution_x; /* width in inch */ - float imageheight = xsane.param.lines/xsane.resolution_y; /* height in inch */ - - if (preferences.psrotate) /* rotate: landscape */ - { - xsane_save_ps(outfile, infile, - xsane.xsane_color /* gray, color */, - xsane.param.depth /* bits */, - xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ - (preferences.printer[preferences.printernr]->bottomoffset + - preferences.printer[preferences.printernr]->height) * 36.0/MM_PER_INCH - imagewidth * 36.0, /* left edge */ - (preferences.printer[preferences.printernr]->leftoffset + - preferences.printer[preferences.printernr]->width) * 36.0/MM_PER_INCH - imageheight * 36.0, /* bottom edge */ - imagewidth, imageheight, - (preferences.printer[preferences.printernr]->leftoffset + - preferences.printer[preferences.printernr]->width ) * 72.0/MM_PER_INCH, /* paperwidth */ - (preferences.printer[preferences.printernr]->bottomoffset + - preferences.printer[preferences.printernr]->height) * 72.0/MM_PER_INCH, /* paperheight */ - 1 /* landscape */); - } - else /* do not rotate: portrait */ - { - xsane_save_ps(outfile, infile, - xsane.xsane_color /* gray, color */, - xsane.param.depth /* bits */, - xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ - (preferences.printer[preferences.printernr]->leftoffset + - preferences.printer[preferences.printernr]->width) * 36.0/MM_PER_INCH - imagewidth * 36.0, - (preferences.printer[preferences.printernr]->bottomoffset + - preferences.printer[preferences.printernr]->height) * 36.0/MM_PER_INCH - imageheight * 36.0, - imagewidth, imageheight, - (preferences.printer[preferences.printernr]->leftoffset + - preferences.printer[preferences.printernr]->width ) * 72.0/MM_PER_INCH, /* paperwidth */ - (preferences.printer[preferences.printernr]->bottomoffset + - preferences.printer[preferences.printernr]->height) * 72.0/MM_PER_INCH, /* paperheight */ - 0 /* portrait */); - } - } - break; - - - default: - snprintf(buf, sizeof(buf),"%s", ERR_UNKNOWN_SAVING_FORMAT); - xsane_back_gtk_error(buf, TRUE); - break; - } - fclose(outfile); - } - else - { - char buf[256]; - - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.output_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - } - } - fclose(infile); - remove(xsane.dummy_filename); - } - else - { - char buf[256]; - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.output_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - } - xsane_progress_free(xsane.progress); - xsane.progress = 0; - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } - else if (xsane.xsane_mode == XSANE_COPY) - { - FILE *outfile; - FILE *infile; - char buf[256]; - - xsane_update_int(xsane.copy_number_entry, &xsane.copy_number); /* get number of copies */ - if (xsane.copy_number < 1) - { - xsane.copy_number = 1; - } - - /* open progressbar */ - snprintf(buf, sizeof(buf), PROGRESS_CONVERTING_PS); - xsane.progress = xsane_progress_new(PROGRESS_CONVERTING_DATA, buf, (GtkSignalFunc) xsane_cancel_save, 0); - xsane_progress_update(xsane.progress, 0); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - xsane.broken_pipe = 0; - infile = fopen(xsane.dummy_filename, "r"); - - snprintf(buf, sizeof(buf), "%s %s%d", preferences.printer[preferences.printernr]->command, - preferences.printer[preferences.printernr]->copy_number_option, - xsane.copy_number); - outfile = popen(buf, "w"); -/* outfile = popen(preferences.printer[preferences.printernr]->command, "w"); */ - if ((outfile != 0) && (infile != 0)) /* copy mode, use zoom size */ - { - struct SIGACTION act; - float imagewidth = xsane.param.pixels_per_line/(float)preferences.printer[preferences.printernr]->resolution; /* width in inch */ - float imageheight = xsane.param.lines/(float)preferences.printer[preferences.printernr]->resolution; /* height in inch */ - - memset (&act, 0, sizeof (act)); /* define broken pipe handler */ - act.sa_handler = xsane_sigpipe_handler; - sigaction (SIGPIPE, &act, 0); - - - fseek(infile, xsane.header_size, SEEK_SET); - - if (preferences.psrotate) /* rotate: landscape */ - { - xsane_save_ps(outfile, infile, - xsane.xsane_color /* gray, color */, - xsane.param.depth /* bits */, - xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ - (preferences.printer[preferences.printernr]->bottomoffset + - preferences.printer[preferences.printernr]->height) * 36.0/MM_PER_INCH - imagewidth * 36.0, /* left edge */ - (preferences.printer[preferences.printernr]->leftoffset + - preferences.printer[preferences.printernr]->width) * 36.0/MM_PER_INCH - imageheight * 36.0, /* bottom edge */ - imagewidth, imageheight, - (preferences.printer[preferences.printernr]->leftoffset + - preferences.printer[preferences.printernr]->width ) * 72.0/MM_PER_INCH, /* paperwidth */ - (preferences.printer[preferences.printernr]->bottomoffset + - preferences.printer[preferences.printernr]->height) * 72.0/MM_PER_INCH, /* paperheight */ - 1 /* landscape */); - } - else /* do not rotate: portrait */ - { - xsane_save_ps(outfile, infile, - xsane.xsane_color /* gray, color */, - xsane.param.depth /* bits */, - xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ - (preferences.printer[preferences.printernr]->leftoffset + - preferences.printer[preferences.printernr]->width) * 36.0/MM_PER_INCH - imagewidth * 36.0, /* left edge */ - (preferences.printer[preferences.printernr]->bottomoffset + - preferences.printer[preferences.printernr]->height) * 36.0/MM_PER_INCH - imageheight * 36.0, /* bottom edge */ - imagewidth, imageheight, - (preferences.printer[preferences.printernr]->leftoffset + - preferences.printer[preferences.printernr]->width ) * 72.0/MM_PER_INCH, /* paperwidth */ - (preferences.printer[preferences.printernr]->bottomoffset + - preferences.printer[preferences.printernr]->height) * 72.0/MM_PER_INCH, /* paperheight */ - 0 /* portrait */); - } - } - else - { - char buf[256]; - - if (!infile) - { - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.output_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - } - else if (!outfile) - { - xsane_back_gtk_error(ERR_FAILED_PRINTER_PIPE, TRUE); - } - } - - if (xsane.broken_pipe) - { - snprintf(buf, sizeof(buf), "%s \"%s\"", ERR_FAILED_EXEC_PRINTER_CMD, preferences.printer[preferences.printernr]->command); - xsane_back_gtk_error(buf, TRUE); - } - - xsane_progress_free(xsane.progress); - xsane.progress = 0; - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - if (infile) - { - fclose(infile); - remove(xsane.dummy_filename); - } - - if (outfile) - { - pclose(outfile); - } - } - else if (xsane.xsane_mode == XSANE_FAX) - { - FILE *outfile; - FILE *infile; - char buf[256]; - - /* open progressbar */ - snprintf(buf, sizeof(buf), PROGRESS_SAVING_FAX); - xsane.progress = xsane_progress_new(PROGRESS_CONVERTING_DATA, buf, (GtkSignalFunc) xsane_cancel_save, 0); - xsane_progress_update(xsane.progress, 0); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - infile = fopen(xsane.dummy_filename, "r"); - if (infile != 0) - { - fseek(infile, xsane.header_size, SEEK_SET); - - umask(preferences.image_umask); /* define image file permissions */ - outfile = fopen(xsane.fax_filename, "w"); - umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ - if (outfile != 0) - { - float imagewidth, imageheight; - - imagewidth = xsane.param.pixels_per_line/xsane.resolution_x; /* width in inch */ - imageheight = xsane.param.lines/xsane.resolution_y; /* height in inch */ - -/* disabled ( 0 * ...) in the moment */ - if (0 * preferences.psrotate) /* rotate: landscape */ - { - xsane_save_ps(outfile, infile, - xsane.xsane_color /* gray, color */, - xsane.param.depth /* bits */, - xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ - (preferences.fax_bottomoffset + preferences.fax_height) * 36.0/MM_PER_INCH - imagewidth * 36.0, /* left edge */ - (preferences.fax_leftoffset + preferences.fax_width) * 36.0/MM_PER_INCH - imageheight * 36.0, /* bottom edge */ - imagewidth, imageheight, - (preferences.fax_leftoffset + preferences.fax_width ) * 72.0/MM_PER_INCH, /* paperwidth */ - (preferences.fax_bottomoffset + preferences.fax_height) * 72.0/MM_PER_INCH, /* paperheight */ - 1 /* landscape */); - } - else /* do not rotate: portrait */ - { - xsane_save_ps(outfile, infile, - xsane.xsane_color /* gray, color */, - xsane.param.depth /* bits */, - xsane.param.pixels_per_line, xsane.param.lines, /* pixel_width, pixel_height */ - (preferences.fax_leftoffset + preferences.fax_width) * 36.0/MM_PER_INCH - imagewidth * 36.0, - (preferences.fax_bottomoffset + preferences.fax_height) * 36.0/MM_PER_INCH - imageheight * 36.0, - imagewidth, imageheight, - (preferences.fax_leftoffset + preferences.fax_width ) * 72.0/MM_PER_INCH, /* paperwidth */ - (preferences.fax_bottomoffset + preferences.fax_height) * 72.0/MM_PER_INCH, /* paperheight */ - 0 /* portrait */); - } - fclose(outfile); - } - else - { - char buf[256]; - - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.fax_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - } - - fclose(infile); - remove(xsane.dummy_filename); - } - else - { - char buf[256]; - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.fax_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - } - xsane_progress_free(xsane.progress); - xsane.progress = 0; - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - } - } -#ifdef HAVE_LIBGIMP_GIMP_H - else - { - int remaining; - - /* GIMP mode */ - if (xsane.y > xsane.param.lines) - { - xsane.y = xsane.param.lines; - } - - remaining = xsane.y % gimp_tile_height(); - if (remaining) - { - gimp_pixel_rgn_set_rect(&xsane.region, xsane.tile, 0, xsane.y - remaining, xsane.param.pixels_per_line, remaining); - } - gimp_drawable_flush(xsane.drawable); - gimp_display_new(xsane.image_ID); - gimp_drawable_detach(xsane.drawable); - free(xsane.tile); - xsane.tile = 0; - } -#endif /* HAVE_LIBGIMP_GIMP_H */ - - xsane.header_size = 0; - - if ( (preferences.increase_filename_counter) && (xsane.xsane_mode == XSANE_SCAN) && (xsane.mode == XSANE_STANDALONE) ) - { - xsane_increase_counter_in_filename(preferences.filename, preferences.skip_existing_numbers); - gtk_entry_set_text(GTK_ENTRY(xsane.outputfilename_entry), (char *) preferences.filename); - } - else if (xsane.xsane_mode == XSANE_FAX) - { - GtkWidget *list_item; - char *page; - char *extension; - - page = strdup(strrchr(xsane.fax_filename,'/')+1); - extension = strrchr(page, '.'); - if (extension) - { - *extension = 0; - } - list_item = gtk_list_item_new_with_label(page); - gtk_object_set_data(GTK_OBJECT(list_item), "list_item_data", strdup(page)); - gtk_container_add(GTK_CONTAINER(xsane.fax_list), list_item); - gtk_widget_show(list_item); - - xsane_increase_counter_in_filename(xsane.fax_filename, preferences.skip_existing_numbers); - xsane_fax_project_save(); - free(page); - } - } - else /* an error occured, remove the dummy_file */ - { - if (xsane.dummy_filename) /* remove corrupt file */ - { - remove(xsane.dummy_filename); - } - } - - free(xsane.dummy_filename); /* no dummy_filename, needed if an error occurs */ - xsane.dummy_filename = 0; - - if (xsane.output_filename) - { - free(xsane.output_filename); - xsane.output_filename = 0; - } - - if ( ( (status == SANE_STATUS_GOOD) || (status == SANE_STATUS_EOF) ) && (xsane_test_multi_scan()) ) - { - /* multi scan (eg ADF): scan again */ - /* stopped when: */ - /* a) xsane_test_multi_scan returns false */ - /* b) sane_start returns SANE_STATUS_NO_DOCS */ - /* c) an error occurs */ - - gtk_signal_emit_by_name(xsane.start_button, "clicked"); /* press START button */ - } - else /* last scan: update histogram */ - { - xsane_set_sensitivity(TRUE); /* reactivate buttons etc */ - sane_cancel(xsane_back_gtk_dialog_get_device(dialog)); /* stop scanning */ - xsane_update_histogram(); - } -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -void xsane_cancel(void) -{ - sane_cancel(xsane_back_gtk_dialog_get_device(dialog)); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -static void xsane_start_scan(void) -{ - SANE_Status status; - SANE_Handle dev = xsane_back_gtk_dialog_get_device(dialog); - const char *frame_type = 0; - char buf[256]; - int fd; - - xsane_clear_histogram(&xsane.histogram_raw); - xsane_clear_histogram(&xsane.histogram_enh); - xsane_set_sensitivity(FALSE); - -#ifdef HAVE_LIBGIMP_GIMP_H - if (xsane.mode == XSANE_GIMP_EXTENSION && xsane.tile) - { - int height, remaining; - - /* write the last tile of the frame to the GIMP region: */ - - if (xsane.y > xsane.param.lines) /* sanity check */ - { - xsane.y = xsane.param.lines; - } - - remaining = xsane.y % gimp_tile_height(); - if (remaining) - { - gimp_pixel_rgn_set_rect(&xsane.region, xsane.tile, 0, xsane.y - remaining, xsane.param.pixels_per_line, remaining); - } - - /* initialize the tile with the first tile of the GIMP region: */ - - height = gimp_tile_height(); - if (height >= xsane.param.lines) - { - height = xsane.param.lines; - } - gimp_pixel_rgn_get_rect(&xsane.region, xsane.tile, 0, 0, xsane.param.pixels_per_line, height); - } -#endif /* HAVE_LIBGIMP_GIMP_H */ - - xsane.x = xsane.y = 0; - - status = sane_start(dev); - - if (status == SANE_STATUS_NO_DOCS) /* ADF out of docs */ - { - xsane_scan_done(status); /* ok, stop multi image scan */ - return; - } - else if (status != SANE_STATUS_GOOD) /* error */ - { - xsane_scan_done(status); - snprintf(buf, sizeof(buf), "%s %s", ERR_FAILED_START_SCANNER, XSANE_STRSTATUS(status)); - xsane_back_gtk_error(buf, TRUE); - return; - } - - status = sane_get_parameters(dev, &xsane.param); - if (status != SANE_STATUS_GOOD) - { - xsane_scan_done(status); - snprintf(buf, sizeof(buf), "%s %s", ERR_FAILED_GET_PARAMS, XSANE_STRSTATUS(status)); - xsane_back_gtk_error(buf, TRUE); - return; - } - - xsane.num_bytes = xsane.param.lines * xsane.param.bytes_per_line; - xsane.bytes_read = 0; - - switch (xsane.param.format) - { - case SANE_FRAME_RGB: frame_type = "RGB"; break; - case SANE_FRAME_RED: frame_type = "red"; break; - case SANE_FRAME_GREEN: frame_type = "green"; break; - case SANE_FRAME_BLUE: frame_type = "blue"; break; - case SANE_FRAME_GRAY: frame_type = "gray"; break; -#ifdef SUPPORT_RGBA - case SANE_FRAME_RGBA: frame_type = "RGBA"; break; -#endif - default: frame_type = "unknown"; break; - } - - if (xsane.mode == XSANE_STANDALONE) - { /* We are running in standalone mode */ - if (xsane_generate_dummy_filename()) /* create filename the scanned data is saved to */ - { - /* temporary file */ - umask(0177); /* creare temporary file with "-rw-------" permissions */ - } - else - { - /* no temporary file */ - umask(preferences.image_umask); /* define image file permissions */ - } - - if (!xsane.header_size) /* first pass of multi pass scan */ - { - remove(xsane.dummy_filename); /* remove existing file */ - xsane.out = fopen(xsane.dummy_filename, "w"); - umask(XSANE_DEFAULT_UMASK); /* define new file permissions */ - - if (!xsane.out) /* error while opening the dummy_file for writing */ - { - xsane_scan_done(-1); /* -1 = error */ - snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, xsane.output_filename, strerror(errno)); - xsane_back_gtk_error(buf, TRUE); - return; - } - - switch (xsane.param.format) - { - case SANE_FRAME_RGB: - case SANE_FRAME_RED: - case SANE_FRAME_GREEN: - case SANE_FRAME_BLUE: - switch (xsane.param.depth) - { - case 8: /* color 8 bit mode, write ppm header */ - fprintf(xsane.out, "P6\n# SANE data follows\n%d %d\n255\n", xsane.param.pixels_per_line, xsane.param.lines); - break; - - default: /* color, but not 8 bit mode, write as raw data because this is not defined in pnm */ - fprintf(xsane.out, "SANE_RGB_RAW\n%d %d\n65535\n", xsane.param.pixels_per_line, xsane.param.lines); - break; - } - break; - - case SANE_FRAME_GRAY: - switch (xsane.param.depth) - { - case 1: /* 1 bit lineart mode, write pbm header */ - fprintf(xsane.out, "P4\n# SANE data follows\n%d %d\n", xsane.param.pixels_per_line, xsane.param.lines); - break; - - case 8: /* 8 bit grayscale mode, write pgm header */ - fprintf(xsane.out, "P5\n# SANE data follows\n%d %d\n255\n", xsane.param.pixels_per_line, xsane.param.lines); - break; - - default: /* grayscale mode but not 1 or 8 bit, write as raw data because this is not defined in pnm */ - fprintf(xsane.out, "SANE_GRAYSCALE_RAW\n%d %d\n65535\n", xsane.param.pixels_per_line, xsane.param.lines); - break; - } - break; - -#ifdef SUPPORT_RGBA - case SANE_FRAME_RGBA: - switch (xsane.param.depth) - { - case 8: /* 8 bit RGBA mode */ - fprintf(xsane.out, "SANE_RGBA\n%d %d\n255\n", xsane.param.pixels_per_line, xsane.param.lines); - break; - - default: /* 16 bit RGBA mode */ - fprintf(xsane.out, "SANE_RGBA\n%d %d\n65535\n", xsane.param.pixels_per_line, xsane.param.lines); - break; - } - break; -#endif - - default: - /* unknown file format, do not write header */ - break; - } - fflush(xsane.out); - xsane.header_size = ftell(xsane.out); - } - - if (xsane.param.format >= SANE_FRAME_RED && xsane.param.format <= SANE_FRAME_BLUE) - { - fseek(xsane.out, xsane.header_size + xsane.param.format - SANE_FRAME_RED, SEEK_SET); - } - - if (xsane.xsane_mode == XSANE_SCAN) - { - snprintf(buf, sizeof(buf), PROGRESS_RECEIVING_SCAN, _(frame_type), xsane.output_filename); - } - else if (xsane.xsane_mode == XSANE_COPY) - { - snprintf(buf, sizeof(buf), PROGRESS_RECEIVING_COPY, _(frame_type)); - } - else if (xsane.xsane_mode == XSANE_FAX) - { - snprintf(buf, sizeof(buf), PROGRESS_RECEIVING_FAX, _(frame_type)); - } - } -#ifdef HAVE_LIBGIMP_GIMP_H - else - { - size_t tile_size; - - /* We are running under the GIMP */ - - xsane.tile_offset = 0; - tile_size = xsane.param.pixels_per_line * gimp_tile_height(); - - switch(xsane.param.format) - { - case SANE_FRAME_RGB: - case SANE_FRAME_RED: - case SANE_FRAME_BLUE: - case SANE_FRAME_GREEN: - tile_size *= 3; /* 24 bits/pixel RGB */ - break; -#ifdef SUPPORT_RGBA - case SANE_FRAME_RGBA: - tile_size *= 4; /* 32 bits/pixel RGBA */ - break; -#endif - default: - break; - } - - if (xsane.tile) - { - xsane.first_frame = 0; - } - else - { - GImageType image_type = RGB; - GDrawableType drawable_type = RGB_IMAGE; - gint32 layer_ID; - - if (xsane.param.format == SANE_FRAME_GRAY) - { - image_type = GRAY; - drawable_type = GRAY_IMAGE; - } -#ifdef SUPPORT_RGBA - else if (xsane.param.format == SANE_FRAME_RGBA) - { - image_type = RGB; - drawable_type = RGBA_IMAGE; /* interpret infrared as alpha */ - } -#endif - - - xsane.image_ID = gimp_image_new(xsane.param.pixels_per_line, xsane.param.lines, image_type); - -/* the following is supported since gimp-1.1.? */ -#ifdef GIMP_HAVE_RESOLUTION_INFO - if (xsane.resolution_x > 0) - { - gimp_image_set_resolution(xsane.image_ID, xsane.resolution_x ,xsane.resolution_y); - } -/* gimp_image_set_unit(xsane.image_ID, unit?); */ -#endif - - layer_ID = gimp_layer_new(xsane.image_ID, "Background", - xsane.param.pixels_per_line, - xsane.param.lines, - drawable_type, 100, NORMAL_MODE); - gimp_image_add_layer(xsane.image_ID, layer_ID, 0); - - xsane.drawable = gimp_drawable_get(layer_ID); - gimp_pixel_rgn_init(&xsane.region, xsane.drawable, 0, 0, - xsane.drawable->width, - xsane.drawable->height, TRUE, FALSE); - xsane.tile = g_new(guchar, tile_size); - xsane.first_frame = 1; - } - - if (xsane.param.format >= SANE_FRAME_RED && xsane.param.format <= SANE_FRAME_BLUE) - { - xsane.tile_offset = xsane.param.format - SANE_FRAME_RED; - } - - snprintf(buf, sizeof(buf), PROGRESS_RECEIVING_GIMP, _(frame_type)); - } -#endif /* HAVE_LIBGIMP_GIMP_H */ - - dialog->pixelcolor = 0; - - if (xsane.progress) - { - xsane_progress_free(xsane.progress); - } - xsane.progress = xsane_progress_new(PROGRESS_SCANNING, buf, (GtkSignalFunc) xsane_cancel, 0); - - xsane.input_tag = -1; - - if (sane_set_io_mode(dev, SANE_TRUE) == SANE_STATUS_GOOD && sane_get_select_fd(dev, &fd) == SANE_STATUS_GOOD) - { - xsane.input_tag = gdk_input_add(fd, GDK_INPUT_READ, xsane_read_image_data, 0); - } - else - { - xsane_read_image_data(0, -1, GDK_INPUT_READ); - } -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - -/* Invoked when the scan button is pressed */ -/* or by scan_done if automatic document feeder is selected */ -void xsane_scan_dialog(GtkWidget * widget, gpointer call_data) -{ - char buf[256]; - - sane_get_parameters(dialog->dev, &xsane.param); /* update xsane.param */ - - if (xsane.output_filename) - { - free(xsane.output_filename); - xsane.output_filename = 0; - } - - if (xsane.filetype) - { - char buffer[256]; - - snprintf(buffer, sizeof(buffer), "%s%s", preferences.filename, xsane.filetype); - xsane.output_filename = strdup(buffer); - } - else - { - xsane.output_filename = strdup(preferences.filename); - } - - if (xsane.mode == XSANE_STANDALONE) /* We are running in standalone mode */ - { - char *extension; - - if ( (xsane.xsane_mode == XSANE_SCAN) && (preferences.overwrite_warning) ) /* test if filename already used */ - { - FILE *testfile; - - testfile = fopen(xsane.output_filename, "r"); - if (testfile) /* filename used: skip */ - { - char buf[256]; - - fclose(testfile); - snprintf(buf, sizeof(buf), "File %s already exists\n", xsane.output_filename); - if (xsane_back_gtk_decision(ERR_HEADER_WARNING, (gchar **) warning_xpm, buf, BUTTON_OVERWRITE, BUTTON_CANCEL, TRUE /* wait */) == FALSE) - { - return; - } - } - } - - - extension = strrchr(xsane.output_filename, '.'); - if (extension) - { - extension++; /* skip "." */ - } - - xsane.xsane_output_format = XSANE_UNKNOWN; - - if (xsane.param.depth <= 8) - { - if (extension) - { - if ( (!strcasecmp(extension, "pnm")) || (!strcasecmp(extension, "ppm")) || - (!strcasecmp(extension, "pgm")) || (!strcasecmp(extension, "pbm")) ) - { - xsane.xsane_output_format = XSANE_PNM; - } -#ifdef HAVE_LIBPNG -#ifdef HAVE_LIBZ - else if (!strcasecmp(extension, "png")) - { - xsane.xsane_output_format = XSANE_PNG; - } -#endif -#endif -#ifdef HAVE_LIBJPEG - else if ( (!strcasecmp(extension, "jpg")) || (!strcasecmp(extension, "jpeg")) ) - { - xsane.xsane_output_format = XSANE_JPEG; - } -#endif - else if (!strcasecmp(extension, "ps")) - { - xsane.xsane_output_format = XSANE_PS; - } -#ifdef HAVE_LIBTIFF - else if ( (!strcasecmp(extension, "tif")) || (!strcasecmp(extension, "tiff")) ) - { - xsane.xsane_output_format = XSANE_TIFF; - } -#endif -#ifdef SUPPORT_RGBA - else if (!strcasecmp(extension, "rgba")) - { - xsane.xsane_output_format = XSANE_RGBA; - } -#endif - } - } - else /* depth >8 bpp */ - { - if (extension) - { - if (!strcasecmp(extension, "raw")) - { - xsane.xsane_output_format = XSANE_RAW16; - } - else if ( (!strcasecmp(extension, "pnm")) || (!strcasecmp(extension, "ppm")) || - (!strcasecmp(extension, "pgm")) || (!strcasecmp(extension, "pbm")) ) - { - xsane.xsane_output_format = XSANE_PNM16; - } -#ifdef HAVE_LIBPNG -#ifdef HAVE_LIBZ - else if (!strcasecmp(extension, "png")) - { - xsane.xsane_output_format = XSANE_PNG; - } -#endif -#endif -#ifdef SUPPORT_RGBA - else if (!strcasecmp(extension, "rgba")) - { - xsane.xsane_output_format = XSANE_RGBA; - } -#endif - } - } - - if (xsane.xsane_mode == XSANE_SCAN) - { - if (xsane.xsane_output_format == XSANE_UNKNOWN) - { - if (extension) - { - snprintf(buf, sizeof(buf), "Unsupported %d-bit output format: %s", xsane.param.depth, extension); - } - else - { - snprintf(buf, sizeof(buf), "%s", ERR_NO_OUTPUT_FORMAT); - } - xsane_back_gtk_error(buf, TRUE); - return; - } -#ifdef SUPPORT_RGBA - else if ((xsane.xsane_output_format == XSANE_RGBA) && (xsane.param.format != SANE_FRAME_RGBA)) - { - snprintf(buf, sizeof(buf), "No RGBA data format !!!"); /* user selected output format RGBA, scanner uses other format */ - xsane_back_gtk_error(buf, TRUE); - return; - } -#endif - } -#ifdef SUPPORT_RGBA - else if (xsane.param.format == SANE_FRAME_RGBA) /* no scanmode but format=rgba */ - { - snprintf(buf, sizeof(buf), "Special format RGBA only supported in scan mode !!!"); - xsane_back_gtk_error(buf, TRUE); - return; - } -#endif - -#ifdef SUPPORT_RGBA - if (xsane.param.format == SANE_FRAME_RGBA) - { - if ( (xsane.xsane_output_format != XSANE_RGBA) && (xsane.xsane_output_format != XSANE_PNG) ) - { - snprintf(buf, sizeof(buf), "Image data of type SANE_FRAME_RGBA\ncan only be saved in rgba or png format"); - xsane_back_gtk_error(buf, TRUE); - return; - } - } -#endif - - if (xsane.xsane_mode == XSANE_FAX) - { - mkdir(preferences.fax_project, 7*64 + 0*8 + 0); - } - } -#ifdef HAVE_LIBGIMP_GIMP_H - else /* We are running in gimp mode */ - { - if ((xsane.param.depth != 1) && (xsane.param.depth != 8)) /* not support bit depth ? */ - { - snprintf(buf, sizeof(buf), "%s %d.", ERR_GIMP_BAD_DEPTH, xsane.param.depth); - xsane_back_gtk_error(buf, TRUE); - return; - } - } -#endif - - if (xsane.dummy_filename) /* no dummy filename defined - necessary if an error occurs */ - { - free(xsane.dummy_filename); - xsane.dummy_filename = 0; - } - - if (xsane.param.depth > 1) /* if depth > 1 use gamma correction */ - { - int size; - int gamma_gray_size, gamma_red_size, gamma_green_size, gamma_blue_size; - int gamma_gray_max, gamma_red_max, gamma_green_max, gamma_blue_max; - const SANE_Option_Descriptor *opt; - - size = (int) pow(2, xsane.param.depth); - gamma_gray_size = size; - gamma_red_size = size; - gamma_green_size = size; - gamma_blue_size = size; - - size--; - gamma_gray_max = size; - gamma_red_max = size; - gamma_green_max = size; - gamma_blue_max = size; - - if (xsane.scanner_gamma_gray) /* gamma table for gray available */ - { - opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector); - gamma_gray_size = opt->size / sizeof(opt->type); - gamma_gray_max = opt->constraint.range->max; - } - - if (xsane.scanner_gamma_color) /* gamma table for red, green and blue available */ - { - double gamma_red, gamma_green, gamma_blue; - - /* ok, scanner color gamma function is supported, so we do all conversions about that */ - /* we do not need any gamma tables while scanning, so we can free them after sending */ - /* the data to the scanner */ - - /* if also gray gamma function is supported, set this to 1.0 to get the right colors */ - if (xsane.scanner_gamma_gray) - { - xsane.gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int)); - xsane_create_gamma_curve(xsane.gamma_data, 0, 1.0, 0.0, 0.0, gamma_gray_size, gamma_gray_max); - xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector, xsane.gamma_data); - free(xsane.gamma_data); - xsane.gamma_data = 0; - } - - opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector_r); - gamma_red_size = opt->size / sizeof(opt->type); - gamma_red_max = opt->constraint.range->max; - - opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector_g); - gamma_green_size = opt->size / sizeof(opt->type); - gamma_green_max = opt->constraint.range->max; - - opt = sane_get_option_descriptor(dialog->dev, dialog->well_known.gamma_vector_b); - gamma_blue_size = opt->size / sizeof(opt->type); - gamma_blue_max = opt->constraint.range->max; - - xsane.gamma_data_red = malloc(gamma_red_size * sizeof(SANE_Int)); - xsane.gamma_data_green = malloc(gamma_green_size * sizeof(SANE_Int)); - xsane.gamma_data_blue = malloc(gamma_blue_size * sizeof(SANE_Int)); - - if (xsane.xsane_mode == XSANE_COPY) - { - gamma_red = xsane.gamma * xsane.gamma_red * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_red; - gamma_green = xsane.gamma * xsane.gamma_green * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_green; - gamma_blue = xsane.gamma * xsane.gamma_blue * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_blue; - } - else - { - gamma_red = xsane.gamma * xsane.gamma_red; - gamma_green = xsane.gamma * xsane.gamma_green; - gamma_blue = xsane.gamma * xsane.gamma_blue; - } - - xsane_create_gamma_curve(xsane.gamma_data_red, xsane.negative, - gamma_red, - xsane.brightness + xsane.brightness_red, - xsane.contrast + xsane.contrast_red, gamma_red_size, gamma_red_max); - - xsane_create_gamma_curve(xsane.gamma_data_green, xsane.negative, - gamma_green, - xsane.brightness + xsane.brightness_green, - xsane.contrast + xsane.contrast_green, gamma_green_size, gamma_green_max); - - xsane_create_gamma_curve(xsane.gamma_data_blue, xsane.negative, - gamma_blue, - xsane.brightness + xsane.brightness_blue, - xsane.contrast + xsane.contrast_blue , gamma_blue_size, gamma_blue_max); - - xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector_r, xsane.gamma_data_red); - xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector_g, xsane.gamma_data_green); - xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector_b, xsane.gamma_data_blue); - - free(xsane.gamma_data_red); - free(xsane.gamma_data_green); - free(xsane.gamma_data_blue); - - xsane.gamma_data_red = 0; - xsane.gamma_data_green = 0; - xsane.gamma_data_blue = 0; - } - else if (xsane.scanner_gamma_gray) /* only scanner gray gamma function available */ - { - double gamma; - /* ok, the scanner only supports gray gamma function */ - /* if we are doing a grayscale scan everyting is ok, */ - /* for a color scan the software has to do the gamma correction set by the component slider */ - - if (xsane.xsane_mode == XSANE_COPY) - { - gamma = xsane.gamma * preferences.printer[preferences.printernr]->gamma; - } - else - { - gamma = xsane.gamma; - } - - xsane.gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int)); - xsane_create_gamma_curve(xsane.gamma_data, xsane.negative, - gamma, xsane.brightness, xsane.contrast, - gamma_gray_size, gamma_gray_max); - - xsane_back_gtk_update_vector(dialog, dialog->well_known.gamma_vector, xsane.gamma_data); - free(xsane.gamma_data); - xsane.gamma_data = 0; - - if (xsane.xsane_color) /* ok, we are doing a colorscan */ - { - /* we have to create color gamma table for software conversion */ - /* but we only have to use color slider values, because gray slider value */ - /* is used by scanner gray gamma */ - - double gamma_red, gamma_green, gamma_blue; - - xsane.gamma_data_red = malloc(gamma_red_size * sizeof(SANE_Int)); - xsane.gamma_data_green = malloc(gamma_green_size * sizeof(SANE_Int)); - xsane.gamma_data_blue = malloc(gamma_blue_size * sizeof(SANE_Int)); - - if (xsane.xsane_mode == XSANE_COPY) - { - gamma_red = xsane.gamma_red * preferences.printer[preferences.printernr]->gamma_red; - gamma_green = xsane.gamma_green * preferences.printer[preferences.printernr]->gamma_green; - gamma_blue = xsane.gamma_blue * preferences.printer[preferences.printernr]->gamma_blue; - } - else - { - gamma_red = xsane.gamma_red; - gamma_green = xsane.gamma_green; - gamma_blue = xsane.gamma_blue; - } - - xsane_create_gamma_curve(xsane.gamma_data_red, 0, - gamma_red, xsane.brightness_red, xsane.contrast_red, - gamma_red_size, gamma_red_max); - - xsane_create_gamma_curve(xsane.gamma_data_green, 0, - gamma_green, xsane.brightness_green, xsane.contrast_green, - gamma_green_size, gamma_green_max); - - xsane_create_gamma_curve(xsane.gamma_data_blue, 0, - gamma_blue, xsane.brightness_blue, xsane.contrast_blue, - gamma_blue_size, gamma_blue_max); - - /* gamma tables are freed after scan */ - } - - } - else /* scanner does not support any gamma correction */ - { - /* ok, we have to do it on our own */ - - if (xsane.xsane_color == 0) /* no color scan */ - { - double gamma; - - if (xsane.xsane_mode == XSANE_COPY) - { - gamma = xsane.gamma * preferences.printer[preferences.printernr]->gamma; - } - else - { - gamma = xsane.gamma; - } - - xsane.gamma_data = malloc(gamma_gray_size * sizeof(SANE_Int)); - xsane_create_gamma_curve(xsane.gamma_data, xsane.negative, - gamma, xsane.brightness, xsane.contrast, - gamma_gray_size, gamma_gray_max); - - /* gamma table is freed after scan */ - } - else /* color scan */ - { - double gamma_red, gamma_green, gamma_blue; - /* ok, we have to combin gray and color slider values */ - - xsane.gamma_data_red = malloc(gamma_red_size * sizeof(SANE_Int)); - xsane.gamma_data_green = malloc(gamma_green_size * sizeof(SANE_Int)); - xsane.gamma_data_blue = malloc(gamma_blue_size * sizeof(SANE_Int)); - - if (xsane.xsane_mode == XSANE_COPY) - { - gamma_red = xsane.gamma * xsane.gamma_red * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_red; - gamma_green = xsane.gamma * xsane.gamma_green * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_green; - gamma_blue = xsane.gamma * xsane.gamma_blue * preferences.printer[preferences.printernr]->gamma * preferences.printer[preferences.printernr]->gamma_blue; - } - else - { - gamma_red = xsane.gamma * xsane.gamma_red; - gamma_green = xsane.gamma * xsane.gamma_green; - gamma_blue = xsane.gamma * xsane.gamma_blue; - } - - xsane_create_gamma_curve(xsane.gamma_data_red, xsane.negative, - gamma_red, - xsane.brightness + xsane.brightness_red, - xsane.contrast + xsane.contrast_red, gamma_red_size, gamma_red_max); - - xsane_create_gamma_curve(xsane.gamma_data_green, xsane.negative, - gamma_green, - xsane.brightness + xsane.brightness_green, - xsane.contrast + xsane.contrast_green, gamma_green_size, gamma_green_max); - - xsane_create_gamma_curve(xsane.gamma_data_blue, xsane.negative, - gamma_blue, - xsane.brightness + xsane.brightness_blue, - xsane.contrast + xsane.contrast_blue , gamma_blue_size, gamma_blue_max); - - /* gamma tables are freed after scan */ - } - - } - } - - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - - xsane_start_scan(); -} - -/* ---------------------------------------------------------------------------------------------------------------------- */ - |