diff options
Diffstat (limited to 'src/xsane-save.c')
-rw-r--r-- | src/xsane-save.c | 2013 |
1 files changed, 1758 insertions, 255 deletions
diff --git a/src/xsane-save.c b/src/xsane-save.c index 3c78354..e9020e0 100644 --- a/src/xsane-save.c +++ b/src/xsane-save.c @@ -3,7 +3,7 @@ xsane-save.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 @@ -23,13 +23,18 @@ /* ---------------------------------------------------------------------------------------------------------------------- */ #include "xsane.h" -#include "xsane-preview.h" #include "xsane-back-gtk.h" #include "xsane-front-gtk.h" +#include <sys/wait.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> +/* the following test is always false */ +#ifdef _native_WIN32 +# include <winsock.h> +#else +# include <sys/socket.h> +# include <netinet/in.h> +# include <netdb.h> +#endif #ifdef HAVE_LIBJPEG #include <jpeglib.h> @@ -48,18 +53,25 @@ #endif #ifdef HAVE_MMAP -#include <unistd.h> #include <sys/mman.h> #endif +#ifdef HAVE_OS2_H +#include <process.h> +#endif + /* ---------------------------------------------------------------------------------------------------------------------- */ -#ifdef HAVE_LIBGIMP_GIMP_H +#ifdef HAVE_ANY_GIMP #include <libgimp/gimp.h> static void xsane_gimp_query(void); -static void xsane_gimp_run(char *name, int nparams, GimpParam * param, int *nreturn_vals, GimpParam ** return_vals); +#ifdef HAVE_GIMP_2 +static void xsane_gimp_run(const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); +#else +static void xsane_gimp_run(char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals); +#endif GimpPlugInInfo PLUG_IN_INFO = { @@ -75,7 +87,7 @@ char *buf); static int xsane_encode_devname(const char *devname, int n, char *buf); void null_print_func(gchar *msg); -#endif /* HAVE_LIBGIMP_GIMP_H */ +#endif /* HAVE_ANY_GIMP */ /* ---------------------------------------------------------------------------------------------------------------------- */ /* why this routine ? @@ -237,6 +249,68 @@ void xsane_convert_text_to_filename(char **text) /* ---------------------------------------------------------------------------------------------------------------------- */ +int xsane_get_filesize(char *filename) +{ + FILE *infile; + int pos; + int size; + + infile = fopen(filename, "rb"); /* read binary (b for win32) */ + if (infile == NULL) + { + return 0; + } + + pos = ftell(infile); + fseek(infile, 0, SEEK_END); /* get size */ + size = ftell(infile); + fseek(infile, pos, SEEK_SET); /* go to previous position */ + + fclose(infile); + + return size; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +void xsane_ensure_counter_in_filename(char **filename, int counter_len) +{ + char *position_point = NULL; + char *position; + int counter = 1; + + DBG(DBG_proc, "xsane_ensure_counter_in_filename\n"); + + if (!counter_len) + { + counter_len = 1; + } + + position_point = strrchr(*filename, '.'); + + if (!position_point) /* nothing usable ? */ + { + position_point = *filename + strlen(*filename); /* position_point - 1 is last character */ + } + + if (position_point) + { + position = position_point-1; + if ( (position < *filename) || (*position < '0') || (*position >'9') ) /* we have no counter */ + { + char buf[PATH_MAX]; + int len; + + len = position_point - (*filename); /* length until "." or end of string */ + strncpy(buf, *filename, len); + snprintf(buf+len, sizeof(buf)-len, "-%0*d%s", counter_len, counter, position_point); + *filename = strdup(buf); + } + } +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + void xsane_update_counter_in_filename(char **filename, int skip, int step, int min_counter_len) { FILE *testfile; @@ -249,12 +323,14 @@ void xsane_update_counter_in_filename(char **filename, int skip, int step, int m DBG(DBG_proc, "xsane_update_counter_in_filename\n"); - while (1) /* may be we have to skip existing files */ + if ( (!step) && (!min_counter_len) ) { - if (!xsane.filetype) /* no filetype: serach "." */ - { - position_point = strrchr(*filename, '.'); - } + return; /* do not touch counter */ + } + + while (1) /* loop because we may have to skip existing files */ + { + position_point = strrchr(*filename, '.'); if (!position_point) /* nothing usable ? */ { @@ -278,7 +354,7 @@ void xsane_update_counter_in_filename(char **filename, int skip, int step, int m if (counter_len) /* we have a counter */ { sscanf(position_counter, "%d", &counter); - counter += step; /* update counter */ + counter = counter + step; /* update counter */ if (counter < 0) { @@ -303,9 +379,9 @@ void xsane_update_counter_in_filename(char **filename, int skip, int step, int m if (skip) /* test if filename already used */ { - if (xsane.filetype) /* add filetype to filename */ + if (preferences.filetype) /* add filetype to filename */ { - snprintf(buf, sizeof(buf), "%s%s", *filename, xsane.filetype); + snprintf(buf, sizeof(buf), "%s%s", *filename, preferences.filetype); testfile = fopen(buf, "rb"); /* read binary (b for win32) */ } else /* filetype in filename */ @@ -337,12 +413,12 @@ void xsane_update_counter_in_filename(char **filename, int skip, int step, int m /* ---------------------------------------------------------------------------------------------------------------------- */ -void xsane_read_pnm_header(FILE *infile, Image_info *image_info) +void xsane_read_pnm_header(FILE *file, Image_info *image_info) { int max_val, filetype_nr; char buf[256]; - fgets(buf, sizeof(buf)-1, infile); + fgets(buf, sizeof(buf)-1, file); DBG(DBG_info, "filetype header :%s", buf); if (buf[0] == 'P') @@ -351,28 +427,73 @@ void xsane_read_pnm_header(FILE *infile, Image_info *image_info) image_info->resolution_x = 72.0; image_info->resolution_y = 72.0; + image_info->reduce_to_lineart = FALSE; while (strcmp(buf, "# XSANE data follows\n")) { - fgets(buf, sizeof(buf)-1, infile); + fgets(buf, sizeof(buf)-1, file); - if (!strncmp(buf, "# resolution_x =", 17)) + if (!strncmp(buf, "# resolution_x =", 20)) + { + sscanf(buf+20, "%lf", &image_info->resolution_x); + } + else if (!strncmp(buf, "# resolution_y =", 20)) + { + sscanf(buf+20, "%lf", &image_info->resolution_y); + } + else if (!strncmp(buf, "# threshold =", 20)) + { + sscanf(buf+20, "%lf", &image_info->threshold); + } + else if (!strncmp(buf, "# gamma =", 20)) + { + sscanf(buf+20, "%lf", &image_info->gamma); + } + else if (!strncmp(buf, "# gamma IRGB =", 20)) + { + sscanf(buf+20, "%lf %lf %lf %lf", + &image_info->gamma, + &image_info->gamma_red, + &image_info->gamma_green, + &image_info->gamma_blue); + } + else if (!strncmp(buf, "# brightness =", 20)) + { + sscanf(buf+20, "%lf", &image_info->brightness); + } + else if (!strncmp(buf, "# brightness IRGB =", 20)) + { + sscanf(buf+20, "%lf %lf %lf %lf", + &image_info->brightness, + &image_info->brightness_red, + &image_info->brightness_green, + &image_info->brightness_blue); + } + else if (!strncmp(buf, "# contrast =", 20)) + { + sscanf(buf+20, "%lf", &image_info->contrast); + } + else if (!strncmp(buf, "# contrast IRGB =", 20)) { - sscanf(buf+17, "%lf", &image_info->resolution_x); + sscanf(buf+20, "%lf %lf %lf %lf", + &image_info->contrast, + &image_info->contrast_red, + &image_info->contrast_green, + &image_info->contrast_blue); } - else if (!strncmp(buf, "# resolution_y =", 17)) + else if (!strncmp(buf, "# reduce to lineart", 20)) { - sscanf(buf+17, "%lf", &image_info->resolution_y); + image_info->reduce_to_lineart = TRUE; } } - fscanf(infile, "%d %d", &image_info->image_width, &image_info->image_height); + fscanf(file, "%d %d", &image_info->image_width, &image_info->image_height); image_info->depth = 1; if (filetype_nr != 4) /* P4 = lineart */ { - fscanf(infile, "%d", &max_val); + fscanf(file, "%d", &max_val); if (max_val == 255) { @@ -384,7 +505,7 @@ void xsane_read_pnm_header(FILE *infile, Image_info *image_info) } } - fgetc(infile); /* read exactly one newline character */ + fgetc(file); /* read exactly one newline character */ image_info->colors = 1; @@ -397,8 +518,8 @@ void xsane_read_pnm_header(FILE *infile, Image_info *image_info) #ifdef SUPPORT_RGBA else if (buf[0] == 'S') /* RGBA format */ { - fscanf(infile, "%d %d\n%d", &image_info->image_width, &image_info->image_height, &max_val); - fgetc(infile); /* read exactly one newline character */ + fscanf(file, "%d %d\n%d", &image_info->image_width, &image_info->image_height, &max_val); + fgetc(file); /* read exactly one newline character */ image_info->depth = 1; @@ -422,133 +543,239 @@ void xsane_read_pnm_header(FILE *infile, Image_info *image_info) /* ---------------------------------------------------------------------------------------------------------------------- */ -void xsane_write_pnm_header(FILE *outfile, Image_info *image_info) +void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_as_ascii) { - fflush(outfile); - rewind(outfile); + int maxval; + int magic; + fflush(file); + rewind(file); - if (image_info->colors == 1) + if (image_info->depth > 8) { - switch (image_info->depth) - { - case 1: /* 1 bit lineart mode, write pbm header */ - fprintf(outfile, "P4\n" - "# XSane settings:\n" - "# resolution_x = %6.1f\n" - "# resolution_y = %6.1f\n" - "# threshold = %4.1f\n" - "# XSANE data follows\n" - "%05d %05d\n", - image_info->resolution_x, - image_info->resolution_y, - image_info->threshold, - image_info->image_width, image_info->image_height); - break; + maxval = 65535; - case 8: /* 8 bit grayscale mode, write pgm header */ - fprintf(outfile, "P5\n" - "# XSane settings:\n" - "# resolution_x = %6.1f\n" - "# resolution_y = %6.1f\n" - "# gamma = %3.2f\n" - "# brightness = %4.1f\n" - "# contrast = %4.1f\n" - "# XSANE data follows\n" - "%05d %05d\n" - "255\n", - image_info->resolution_x, - image_info->resolution_y, - image_info->gamma, - image_info->brightness, - image_info->contrast, - image_info->image_width, image_info->image_height); - break; - - default: /* grayscale mode but not 1 or 8 bit, write as raw data because this is not defined in pnm */ - fprintf(outfile, "P5\n" - "# This file is in a not public defined data format.\n" - "# It is a 16 bit gray binary format.\n" - "# Some programs can read this as pnm/pgm format.\n" - "# XSane settings:\n" - "# resolution_x = %6.1f\n" - "# resolution_y = %6.1f\n" - "# gamma = %3.2f\n" - "# brightness = %4.1f\n" - "# contrast = %4.1f\n" - "# XSANE data follows\n" - "%05d %05d\n" - "65535\n", - image_info->resolution_x, - image_info->resolution_y, - image_info->gamma, - image_info->brightness, - image_info->contrast, - image_info->image_width, image_info->image_height); - break; + if (save_pnm16_as_ascii) + { + magic = 2; /* thats the magic number for grayscale ascii, 3 = color ascii */ + } + else /* save pnm as binary */ + { + magic = 5; /* that is the magic number for grayscake binary, 6 = color binary */ } } - else if (image_info->colors == 3) + else { - switch (image_info->depth) - { - case 8: /* color 8 bit mode, write ppm header */ - fprintf(outfile, "P6\n" - "# XSane settings:\n" - "# resolution_x = %6.1f\n" - "# resolution_y = %6.1f\n" - "# gamma IRGB = %3.2f %3.2f %3.2f %3.2f\n" - "# brightness IRGB = %4.1f %4.1f %4.1f %4.1f\n" - "# contrast IRGB = %4.1f %4.1f %4.1f %4.1f\n" - "# XSANE data follows\n" - "%05d %05d\n255\n", - image_info->resolution_x, - image_info->resolution_y, - image_info->gamma, image_info->gamma_red, image_info->gamma_green, image_info->gamma_blue, - image_info->brightness, image_info->brightness_red, image_info->brightness_green, image_info->brightness_blue, - image_info->contrast, image_info->contrast_red, image_info->contrast_green, image_info->contrast_blue, - image_info->image_width, image_info->image_height); - break; + maxval = 255; + magic = 5; /* 8 bit images are always saved in binary mode */ + } - default: /* color, but not 8 bit mode, write as raw data because this is not defined in pnm */ - fprintf(outfile, "P6\n" - "# This file is in a not public defined data format.\n" - "# It is a 16 bit RGB binary format.\n" - "# Some programs can read this as pnm/ppm format.\n" - "# File created by XSane.\n" - "# XSane settings:\n" - "# resolution_x = %6.1f\n" - "# resolution_y = %6.1f\n" - "# gamma IRGB = %3.2f %3.2f %3.2f %3.2f\n" - "# brightness IRGB = %4.1f %4.1f %4.1f %4.1f\n" - "# contrast IRGB = %4.1f %4.1f %4.1f %4.1f\n" - "# XSANE data follows\n" - "%05d %05d\n" - "65535\n", - image_info->resolution_x, - image_info->resolution_y, - image_info->gamma, image_info->gamma_red, image_info->gamma_green, image_info->gamma_blue, - image_info->brightness, image_info->brightness_red, image_info->brightness_green, image_info->brightness_blue, - image_info->contrast, image_info->contrast_red, image_info->contrast_green, image_info->contrast_blue, - image_info->image_width, image_info->image_height); - break; + + if (image_info->colors == 1) + { + if (image_info->depth == 1) + { + /* do not touch the texts and length here, the reading routine needs to know the exact texts */ + fprintf(file, "P4\n" + "# XSane settings:\n" + "# resolution_x = %6.1f\n" + "# resolution_y = %6.1f\n" + "# threshold = %4.1f\n" + "# XSANE data follows\n" + "%05d %05d\n", + image_info->resolution_x, + image_info->resolution_y, + image_info->threshold, + image_info->image_width, image_info->image_height); + } + else if (image_info->reduce_to_lineart) + { + /* do not touch the texts and length here, the reading routine needs to know the exact texts */ + fprintf(file, "P%d\n" + "# XSane settings:\n" + "# resolution_x = %6.1f\n" + "# resolution_y = %6.1f\n" + "# threshold = %4.1f\n" + "# reduce to lineart\n" + "# XSANE data follows\n" + "%05d %05d\n" + "%d\n", + magic, /* P5 for binary, P2 for ascii */ + image_info->resolution_x, + image_info->resolution_y, + image_info->threshold, + image_info->image_width, image_info->image_height, + maxval); + } + else + { + fprintf(file, "P%d\n" + "# XSane settings:\n" + "# resolution_x = %6.1f\n" + "# resolution_y = %6.1f\n" + "# gamma = %3.2f\n" + "# brightness = %4.1f\n" + "# contrast = %4.1f\n" + "# XSANE data follows\n" + "%05d %05d\n" + "%d\n", + magic, /* P5 for binary, P2 for ascii */ + image_info->resolution_x, + image_info->resolution_y, + image_info->gamma, + image_info->brightness, + image_info->contrast, + image_info->image_width, image_info->image_height, + maxval); } } + else if (image_info->colors == 3) + { + fprintf(file, "P%d\n" + "# XSane settings:\n" + "# resolution_x = %6.1f\n" + "# resolution_y = %6.1f\n" + "# gamma IRGB = %3.2f %3.2f %3.2f %3.2f\n" + "# brightness IRGB = %4.1f %4.1f %4.1f %4.1f\n" + "# contrast IRGB = %4.1f %4.1f %4.1f %4.1f\n" + "# XSANE data follows\n" + "%05d %05d\n" \ + "%d\n", + magic+1, /* P6 for binary, P3 for ascii */ + image_info->resolution_x, + image_info->resolution_y, + image_info->gamma, image_info->gamma_red, image_info->gamma_green, image_info->gamma_blue, + image_info->brightness, image_info->brightness_red, image_info->brightness_green, image_info->brightness_blue, + image_info->contrast, image_info->contrast_red, image_info->contrast_green, image_info->contrast_blue, + image_info->image_width, image_info->image_height, + maxval); + } #ifdef SUPPORT_RGBA else if (image_info->colors == 4) { - switch (image_info->depth) + fprintf(file, "SANE_RGBA\n" \ + "%d %d\n" \ + "%d\n", + image_info->image_width, image_info->image_height, maxval); + } +#endif +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +int xsane_copy_file(FILE *outfile, FILE *infile, GtkProgressBar *progress_bar, int *cancel_save) +{ + int size; + int bytes; + int bytes_sum = 0; + char buf[65536]; + + DBG(DBG_proc, "copying file\n"); + + fseek(infile, 0, SEEK_END); + size = ftell(infile); + fseek(infile, 0, SEEK_SET); + + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + while (!feof(infile)) + { + bytes = fread(buf, 1, sizeof(buf), infile); + if (bytes > 0) { - case 8: /* 8 bit RGBA mode */ - fprintf(outfile, "SANE_RGBA\n%d %d\n255\n", image_info->image_width, image_info->image_height); - break; + fwrite(buf, 1, bytes, outfile); + bytes_sum += bytes; + } - default: /* 16 bit RGBA mode */ - fprintf(outfile, "SANE_RGBA\n%d %d\n65535\n", image_info->image_width, image_info->image_height); - break; + gtk_progress_bar_update(progress_bar, (float) bytes_sum / size); /* update progress bar */ + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + + if (*cancel_save) + { + break; } } -#endif + + fflush(outfile); + + if (size != bytes_sum) + { + DBG(DBG_info, "copy errro, not complete, %d bytes of %d bytes copied\n", bytes_sum, size); + *cancel_save = 1; + return (*cancel_save); + } + + DBG(DBG_info, "copy complete, %d bytes copied\n", bytes_sum); + + return (*cancel_save); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +int xsane_copy_file_by_name(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save) +{ + FILE *infile; + FILE *outfile; + + DBG(DBG_proc, "copying file %s to %s\n", input_filename, output_filename); + + outfile = fopen(output_filename, "wb"); /* b = binary mode for win32 */ + + if (outfile == 0) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, output_filename, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + return -2; + } + + infile = fopen(input_filename, "rb"); /* read binary (b for win32) */ + if (infile == 0) + { + char buf[256]; + snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, input_filename, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + + fclose(outfile); + remove(output_filename); /* remove already created output file */ + return -1; + } + + xsane_copy_file(outfile, infile, progress_bar, cancel_save); + + fclose(infile); + fclose(outfile); + + gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + return (*cancel_save); } /* ---------------------------------------------------------------------------------------------------------------------- */ @@ -561,11 +788,8 @@ int xsane_save_grayscale_image_as_lineart(FILE *outfile, FILE *imagefile, Image_ *cancel_save = 0; image_info->depth = 1; -#if 0 - xsane.depth = 1; /* our new depth is 1 bit/pixel */ -#endif - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); for (y = 0; y < image_info->image_height; y++) { @@ -600,6 +824,18 @@ int xsane_save_grayscale_image_as_lineart(FILE *outfile, FILE *imagefile, Image_ packed = 0; } + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + + gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); /* update progress bar */ while (gtk_events_pending()) /* give gtk the chance to display the changes */ { @@ -619,6 +855,229 @@ int xsane_save_grayscale_image_as_lineart(FILE *outfile, FILE *imagefile, Image_ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_info, float x_scale, float y_scale, GtkProgressBar *progress_bar, int *cancel_save) { + int original_image_width = image_info->image_width; + int original_image_height = image_info->image_height; + int new_image_width = image_info->image_width * x_scale + 0.5; + int new_image_height = image_info->image_height * y_scale + 0.5; + unsigned char *original_line; + guint16 *original_line16 = NULL; + unsigned char *new_line; + float *pixel_val; + float *pixel_norm; + int bytespp = 1; + float x, y; + int c; + int oldy; + int x_new, y_new; + float x_go, y_go; + float factor, x_factor, y_factor; + guint16 color; + int read_line; + + DBG(DBG_proc, "xsane_save_scaled_image\n"); + + *cancel_save = 0; + + if (image_info->depth > 8) + { + bytespp = 2; + } + + image_info->image_width = new_image_width; + image_info->image_height = new_image_height; + image_info->resolution_x *= x_scale; + image_info->resolution_y *= y_scale; + + original_line = malloc(original_image_width * image_info->colors * bytespp); + if (!original_line) + { + DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); + return -1; + } + + new_line = malloc(new_image_width * image_info->colors * bytespp); + if (!new_line) + { + free(original_line); + DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); + return -1; + } + + pixel_val = malloc(new_image_width * image_info->colors * sizeof(float)); + if (!pixel_val) + { + free(original_line); + free(new_line); + DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); + return -1; + } + + pixel_norm = malloc(new_image_width * image_info->colors * sizeof(float)); + if (!pixel_norm) + { + free(original_line); + free(new_line); + free(pixel_val); + DBG(DBG_error, "xsane_save_scaled_image: out of memory\n"); + return -1; + } + + xsane_write_pnm_header(outfile, image_info, 0); + + read_line = TRUE; + + memset(pixel_val, 0, new_image_width * image_info->colors * sizeof(float)); + memset(pixel_norm, 0, new_image_width * image_info->colors * sizeof(float)); + + y_new = 0; + y_go = 1.0 / y_scale; + y_factor = 1.0; + y = 0.0; + + while (y < original_image_height) + { + DBG(DBG_info2, "xsane_save_scaled_image: original line %d, new line %d\n", (int) y, y_new); + + gtk_progress_bar_update(progress_bar, (float) y / original_image_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (read_line) + { + DBG(DBG_info, "xsane_save_scaled_image: reading original line %d\n", (int) y); + fread(original_line, original_image_width, image_info->colors * bytespp, imagefile); /* read one line */ + original_line16 = (guint16 *) original_line; + } + + x_new = 0; + x_go = 1.0 / x_scale; + x = 0.0; + x_factor = 1.0; + + while ( (x < original_image_width) && (x_new < new_image_width) ) /* add this line to anti aliasing buffer */ + + { + factor = x_factor * y_factor; + + for (c = 0; c < image_info->colors; c++) + { + if (bytespp == 1) + { + color = original_line[((int) x) * image_info->colors + c]; + } + else /* bytespp == 2 */ + { + color = original_line16[((int) x) * image_info->colors + c]; + } + + pixel_val [x_new * image_info->colors + c] += factor * color; + pixel_norm[x_new * image_info->colors + c] += factor; + } + + x_go -= x_factor; + + if (x_go <= 0.0) /* change of pixel in new image */ + { + x_new++; + x_go = 1.0 / x_scale; + + x_factor = x - (int) x; /* use pixel rest */ + if (x_factor > x_go) + { + x_factor = x_go; + } + } + else + { + x_factor = x_go; + } + + if (x_factor > 1.0) + { + x_factor = 1.0; + } + + x += x_factor; + } + + y_go -= y_factor; + + if (y_go <= 0.0) /* normalize one line and write to destination image file */ + { + DBG(DBG_info2, "xsane_save_scaled_image: writing new line %d\n", y_new); + + if (bytespp == 1) + { + for (x_new = 0; x_new < new_image_width * image_info->colors; x_new++) + { + new_line[x_new] = (int) (pixel_val[x_new] / pixel_norm[x_new]); + } + } + else /* bytespp == 2 */ + { + guint16 *new_line16 = (guint16 *) new_line; + + for (x_new = 0; x_new < new_image_width * image_info->colors; x_new++) + { + new_line16[x_new] = (int) (pixel_val[x_new] / pixel_norm[x_new]); + } + } + + fwrite(new_line, new_image_width, image_info->colors * bytespp, outfile); /* write one line */ + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + + /* reset values and norm factors */ + memset(pixel_val, 0, new_image_width * image_info->colors * sizeof(float)); + memset(pixel_norm, 0, new_image_width * image_info->colors * sizeof(float)); + + y_new++; + y_go = 1.0 / y_scale; + + y_factor = y - (int) y; + if (y_factor > y_go) + { + y_factor = y_go; + } + } + else + { + y_factor = y_go; + } + + if (y_factor > 1.0) + { + y_factor = 1.0; + } + + oldy = (int) y; + y += y_factor; + read_line = (oldy != (int) y); + } + + free(original_line); + free(new_line); + free(pixel_val); + free(pixel_norm); + + return (*cancel_save); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ +#if 0 +int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_info, float x_scale, float y_scale, GtkProgressBar *progress_bar, int *cancel_save) +{ float original_y; int old_original_y; int x, y, i; @@ -656,7 +1115,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in return -1; } - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); original_y = 0.0; old_original_y = -1; @@ -699,6 +1158,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in return (*cancel_save); } +#endif /* ---------------------------------------------------------------------------------------------------------------------- */ @@ -707,24 +1167,30 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image int x, y, sx, sy, i; int xmin, xmax; int ymin, ymax; - int pos0; int count; unsigned char *line_cache; unsigned char *line_cache_ptr; guint16 *color_cache; guint16 *color_cache_ptr; int bytespp = 1; - int color_radius = radius * image_info->colors; + int color_radius; int color_width = image_info->image_width * image_info->colors; + radius--; /* correct radius : 1 means nothing happens */ + + if (radius < 1) + { + radius = 1; + } + + color_radius = radius * image_info->colors; + if (image_info->depth > 8) { bytespp = 2; } - pos0 = ftell(imagefile); /* mark position to skip header */ - - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); line_cache = malloc(color_width * bytespp * (2 * radius + 1)); if (!line_cache) @@ -871,6 +1337,17 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image } } + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if ((y > radius) && (y < image_info->image_height - radius)) { memcpy(line_cache, line_cache + color_width * bytespp, @@ -890,6 +1367,224 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image /* ---------------------------------------------------------------------------------------------------------------------- */ +int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info, float radius, GtkProgressBar *progress_bar, int *cancel_save) +{ + int x, y, sx, sy; + int xmin, xmax; + int ymin, ymax; + float val, norm; + unsigned char *line_cache; + int bytespp = 1; + int intradius; + float outer_factor; + int xmin_flag; + int xmax_flag; + int ymin_flag; + int ymax_flag; + + *cancel_save = 0; + + intradius = (int) radius; + + outer_factor = radius - (int) radius; + + if (image_info->depth > 8) + { + bytespp = 2; + } + + xsane_write_pnm_header(outfile, image_info, 0); + + line_cache = malloc(image_info->image_width * image_info->colors * bytespp * (2 * intradius + 1)); + if (!line_cache) + { + DBG(DBG_error, "xsane_blur_image: out of memory\n"); + return -1; + } + + fread(line_cache, image_info->image_width * image_info->colors * bytespp, (2 * intradius + 1), imagefile); + + for (y = 0; y < image_info->image_height; y++) + { + gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + for (x = 0; x < image_info->image_width * image_info->colors; x++) + { + xmin_flag = xmax_flag = ymin_flag = ymax_flag = TRUE; + + xmin = x - intradius * image_info->colors; + xmax = x + intradius * image_info->colors; + + if (xmin < 0) + { + xmin = x % image_info->colors; + xmin_flag = FALSE; + } + + if (xmax > image_info->image_width * image_info->colors) + { + xmax = image_info->image_width * image_info->colors; + xmax_flag = FALSE; + } + + ymin = y - intradius; + ymax = y + intradius; + + if (ymin < 0) + { + ymin = 0; + ymin_flag = FALSE; + } + + if (ymax > image_info->image_height) + { + ymax = image_info->image_height; + ymax_flag = FALSE; + } + + val = 0.0; + norm = 0.0; + + if (bytespp == 1) + { + if (xmin_flag) /* integrate over left margin */ + { + for (sy = ymin+1; sy <= ymax-1 ; sy++) + { + val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->colors + xmin]; + norm += outer_factor; + } + } + + if (xmax_flag) /* integrate over right margin */ + { + for (sy = ymin+1; sy <= ymax-1 ; sy++) + { + val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->colors + xmax]; + norm += outer_factor; + } + } + + if (ymin_flag) /* integrate over top margin */ + { + for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) + { + val += outer_factor * line_cache[sx]; + norm += outer_factor; + } + } + + if (ymax_flag) /* integrate over bottom margin */ + { + for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) + { + val += outer_factor * line_cache[(ymax-ymin) * image_info->image_width * image_info->colors + sx]; + norm += outer_factor; + } + } + + for (sy = ymin+1; sy <= ymax-1; sy++) /* integrate internal square */ + { + for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors; sx+=image_info->colors) + { + val += line_cache[(sy-ymin) * image_info->image_width * image_info->colors + sx]; + norm += 1.0; + } + } + fputc((char) ((int) (val/norm)), outfile); + } + else + { + guint16 *line_cache16 = (guint16 *) line_cache; + guint16 val16; + char *bytes16 = (char *) &val16; + + if (xmin_flag) /* integrate over left margin */ + { + for (sy = ymin+1; sy <= ymax-1 ; sy++) + { + val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + xmin]; + norm += outer_factor; + } + } + + if (xmax_flag) /* integrate over right margin */ + { + for (sy = ymin+1; sy <= ymax-1 ; sy++) + { + val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + xmax]; + norm += outer_factor; + } + } + + if (ymin_flag) /* integrate over top margin */ + { + for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) + { + val += outer_factor * line_cache16[sx]; + norm += outer_factor; + } + } + + if (ymax_flag) /* integrate over bottom margin */ + { + for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors) + { + val += outer_factor * line_cache16[(ymax-ymin) * image_info->image_width * image_info->colors + sx]; + norm += outer_factor; + } + } + + for (sy = ymin; sy <= ymax; sy++) /* integrate internal square */ + { + for (sx = xmin; sx <= xmax; sx+=image_info->colors) + { + val += line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + sx]; + norm += 1.0; + } + } + + val16 = val / norm; + fputc(bytes16[0], outfile); /* write bytes in machine byte order */ + fputc(bytes16[1], outfile); + } + } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + + /* reset values and norm factors */ + + if ((y > intradius) && (y < image_info->image_height - intradius)) + { + memcpy(line_cache, line_cache + image_info->image_width * image_info->colors * bytespp, + image_info->image_width * image_info->colors * bytespp * 2 * intradius); + fread(line_cache + image_info->image_width * image_info->colors * bytespp * 2 * intradius, + image_info->image_width * image_info->colors * bytespp, 1, imagefile); + } + } + + fflush(outfile); + free(line_cache); + + return 0; +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +#if 0 int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info, int radius, GtkProgressBar *progress_bar) { int x, y, sx, sy; @@ -907,7 +1602,7 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info pos0 = ftell(imagefile); /* mark position to skip header */ - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); line_cache = malloc(image_info->image_width * image_info->colors * bytespp * (2 * radius + 1)); if (!line_cache) @@ -1004,6 +1699,7 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info return 0; } +#endif /* ---------------------------------------------------------------------------------------------------------------------- */ @@ -1040,7 +1736,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in #ifdef HAVE_MMAP mmaped_imagefile = mmap(NULL, pixel_width * pixel_height * bytespp + pos0, PROT_READ, MAP_PRIVATE, fileno(imagefile), 0); - if (mmaped_imagefile == (void *) -1) /* mmap failed */ + if (mmaped_imagefile == (char *) -1) /* mmap failed */ { DBG(DBG_info, "xsane_save_rotate_image: unable to memory map image file, using standard file access\n"); mmaped_imagefile = NULL; @@ -1057,7 +1753,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in break; case 0: /* 0 degree */ - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); for (y = 0; y < pixel_height; y++) { @@ -1089,6 +1785,17 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in } } + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if (*cancel_save) { break; @@ -1103,7 +1810,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in image_info->resolution_x = resolution_y; image_info->resolution_y = resolution_x; - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); for (x=0; x<pixel_width; x++) { @@ -1136,6 +1843,18 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in } } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if (*cancel_save) { break; @@ -1145,7 +1864,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in break; case 2: /* 180 degree */ - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); for (y = pixel_height-1; y >= 0; y--) { @@ -1178,6 +1897,18 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in } } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if (*cancel_save) { break; @@ -1192,7 +1923,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in image_info->resolution_x = resolution_y; image_info->resolution_y = resolution_x; - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); for (x = pixel_width-1; x >= 0; x--) { @@ -1225,6 +1956,18 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in } } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if (*cancel_save) { break; @@ -1233,7 +1976,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in break; case 4: /* 0 degree, x mirror */ - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); for (y = 0; y < pixel_height; y++) { @@ -1266,6 +2009,18 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in } } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if (*cancel_save) { break; @@ -1280,7 +2035,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in image_info->resolution_x = resolution_y; image_info->resolution_y = resolution_x; - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); for (x = 0; x < pixel_width; x++) { @@ -1313,6 +2068,18 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in } } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if (*cancel_save) { break; @@ -1322,7 +2089,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in break; case 6: /* 180 degree, x mirror */ - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); for (y = pixel_height-1; y >= 0; y--) { @@ -1355,6 +2122,18 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in } } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if (*cancel_save) { break; @@ -1369,7 +2148,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in image_info->resolution_x = resolution_y; image_info->resolution_y = resolution_x; - xsane_write_pnm_header(outfile, image_info); + xsane_write_pnm_header(outfile, image_info, 0); for (x = pixel_width-1; x >= 0; x--) { @@ -1402,6 +2181,18 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in } } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if (*cancel_save) { break; @@ -1425,50 +2216,114 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in /* ---------------------------------------------------------------------------------------------------------------------- */ static void xsane_save_ps_create_header(FILE *outfile, Image_info *image_info, - int left, int bottom, float width, float height, - int paperwidth, int paperheight, int rotate, + float width, float height, + int paper_left_margin, int paper_bottom_margin, + int paper_width, int paper_height, + int paper_orientation, GtkProgressBar *progress_bar) { - int degree, position_left, position_bottom, box_left, box_bottom, box_right, box_top; + int degree, position_left, position_bottom, box_left, box_bottom, box_right, box_top, depth; + int left, bottom; DBG(DBG_proc, "xsane_save_ps_create_header\n"); - if (rotate) /* rotate with 90 degrees - eg for landscape mode */ + switch (paper_orientation) + { + default: + case 0: /* top left portrait */ + left = 0.0; + bottom = paper_height - height; + break; + + case 1: /* top right portrait */ + left = paper_width - width; + bottom = paper_height - height; + break; + + case 2: /* bottom right portrait */ + left = paper_width - width; + bottom = 0.0; + break; + + case 3: /* bottom left portrait */ + left = 0.0; + bottom = 0.0; + break; + + case 4: /* center portrait */ + left = paper_width / 2.0 - width / 2.0; + bottom = paper_height / 2.0 - height / 2.0; + break; + + + case 8: /* top left landscape */ + left = 0.0; + bottom = paper_width - height; + break; + + case 9: /* top right landscape */ + left = paper_height - width; + bottom = paper_width - height; + break; + + case 10: /* bottom right landscape */ + left = paper_height - width; + bottom = 0.0; + break; + + case 11: /* bottom left landscape */ + left = 0.0; + bottom = 0.0; + break; + + case 12: /* center landscape */ + left = paper_height / 2.0 - width / 2.0; + bottom = paper_width / 2.0 - height / 2.0; + break; + } + + + if (paper_orientation >= 8) /* rotate with 90 degrees - landscape mode */ { degree = 90; - position_left = left; - position_bottom = bottom - paperwidth; - box_left = paperwidth - bottom - height * 72.0; - box_bottom = left; - box_right = (int) (box_left + height * 72.0); - box_top = (int) (box_bottom + width * 72.0); + position_left = left + paper_bottom_margin; + position_bottom = bottom - paper_width - paper_left_margin; + box_left = paper_width - paper_left_margin - bottom - height; + box_bottom = left + paper_bottom_margin; + box_right = box_left + ceil(height); + box_top = box_bottom + ceil(width); } - else /* do not rotate, eg for portrait mode */ + else /* do not rotate, portrait mode */ { degree = 0; - position_left = left; - position_bottom = bottom; - box_left = left; - box_bottom = bottom; - box_right = (int) (box_left + width * 72.0); - box_top = (int) (box_bottom + height * 72.0); + position_left = left + paper_left_margin; + position_bottom = bottom + paper_bottom_margin; + box_left = left + paper_left_margin; + box_bottom = bottom + paper_bottom_margin; + box_right = box_left + ceil(width); + box_top = box_bottom + ceil(height); } - if (image_info->depth == 16) + depth = image_info->depth; + + if (depth > 8) { - image_info->depth = 8; /* 16 bits/color are already reduced to 8 bits/color */ + depth = 8; } - fprintf(outfile, "%%!PS-Adobe-2.0 EPSF-2.0\n"); - fprintf(outfile, "%%%%Creator: xsane version %s (sane %d.%d)\n", VERSION, - SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), - SANE_VERSION_MINOR(xsane.sane_backend_versioncode)); + fprintf(outfile, "%%!PS-Adobe-3.0\n"); + fprintf(outfile, "%%%%Creator: XSane version %s (sane %d.%d) - by Oliver Rauch\n", VERSION, + SANE_VERSION_MAJOR(xsane.sane_backend_versioncode), + SANE_VERSION_MINOR(xsane.sane_backend_versioncode)); + fprintf(outfile, "%%%%DocumentData: Clean7Bit\n"); + fprintf(outfile, "%%%%Pages: 1\n"); fprintf(outfile, "%%%%BoundingBox: %d %d %d %d\n", box_left, box_bottom, box_right, box_top); - fprintf(outfile, "%%\n"); + fprintf(outfile, "%%%%EndComments\n"); fprintf(outfile, "/origstate save def\n"); fprintf(outfile, "20 dict begin\n"); + fprintf(outfile, "%%%%Page: 1 1\n"); - if (image_info->depth == 1) + if (depth == 1) { fprintf(outfile, "/pix %d string def\n", (image_info->image_width+7)/8); fprintf(outfile, "/grays %d string def\n", image_info->image_width); @@ -1483,9 +2338,9 @@ static void xsane_save_ps_create_header(FILE *outfile, Image_info *image_info, fprintf(outfile, "%d rotate\n", degree); fprintf(outfile, "%d %d translate\n", position_left, position_bottom); - fprintf(outfile, "%f %f scale\n", width * 72.0, height * 72.0); - fprintf(outfile, "%d %d %d\n", image_info->image_width, image_info->image_height, image_info->depth); - fprintf(outfile, "[%d %d %d %d %d %d]\n", image_info->image_width, 0, 0, -image_info->image_height, 0 , image_info->image_height); + fprintf(outfile, "%f %f scale\n", width, height); + fprintf(outfile, "%d %d %d\n", image_info->image_width, image_info->image_height, depth); + fprintf(outfile, "[%d %d %d %d %d %d]\n", image_info->image_width, 0, 0, -image_info->image_height, 0, image_info->image_height); fprintf(outfile, "{currentfile pix readhexstring pop}\n"); if (image_info->colors == 3) /* what about RGBA here ? */ @@ -1531,6 +2386,18 @@ static int xsane_save_ps_bw(FILE *outfile, FILE *imagefile, Image_info *image_in } fprintf(outfile, "\n"); + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + count = 0; if (*cancel_save) { @@ -1554,16 +2421,48 @@ static int xsane_save_ps_gray(FILE *outfile, FILE *imagefile, Image_info *image_ count = 0; for (y = 0; y < image_info->image_height; y++) { - for (x = 0; x < image_info->image_width; x++) + if (image_info->depth > 8) /* reduce 16 bit images */ { - fprintf(outfile, "%02x", fgetc(imagefile)); - if (++count >=40) + guint16 val; + + for (x = 0; x < image_info->image_width; x++) { - fprintf(outfile, "\n"); - count = 0; + fread(&val, 2, 1, imagefile); + fprintf(outfile, "%02x", val/256); + + if (++count >= 40) + { + fprintf(outfile, "\n"); + count = 0; + } } } + else /* 8 bits/sample */ + { + for (x = 0; x < image_info->image_width; x++) + { + fprintf(outfile, "%02x", fgetc(imagefile)); + if (++count >= 40) + { + fprintf(outfile, "\n"); + count = 0; + } + } + } + fprintf(outfile, "\n"); + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + count = 0; gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); while (gtk_events_pending()) @@ -1598,18 +2497,54 @@ static int xsane_save_ps_color(FILE *outfile, FILE *imagefile, Image_info *image gtk_main_iteration(); } - for (x = 0; x < image_info->image_width; x++) + if (image_info->depth > 8) /* reduce 16 bit images */ { - fprintf(outfile, "%02x", fgetc(imagefile)); - fprintf(outfile, "%02x", fgetc(imagefile)); - fprintf(outfile, "%02x", fgetc(imagefile)); - if (++count >=10) + guint16 val; + + for (x = 0; x < image_info->image_width; x++) { - fprintf(outfile, "\n"); - count = 0; + fread(&val, 2, 1, imagefile); + fprintf(outfile, "%02x", val/256); + fread(&val, 2, 1, imagefile); + fprintf(outfile, "%02x", val/256); + fread(&val, 2, 1, imagefile); + fprintf(outfile, "%02x", val/256); + + if (++count >= 10) + { + fprintf(outfile, "\n"); + count = 0; + } + } + } + else /* 8 bits/sample */ + { + for (x = 0; x < image_info->image_width; x++) + { + fprintf(outfile, "%02x", fgetc(imagefile)); + fprintf(outfile, "%02x", fgetc(imagefile)); + fprintf(outfile, "%02x", fgetc(imagefile)); + + if (++count >= 10) + { + fprintf(outfile, "\n"); + count = 0; + } } } fprintf(outfile, "\n"); + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + count = 0; if (*cancel_save) @@ -1623,13 +2558,17 @@ static int xsane_save_ps_color(FILE *outfile, FILE *imagefile, Image_info *image /* ---------------------------------------------------------------------------------------------------------------------- */ -int xsane_save_ps(FILE *outfile, FILE *imagefile, Image_info *image_info, int left, int bottom, float width, float height, - int paperheight, int paperwidth, int rotate, GtkProgressBar *progress_bar, int *cancel_save) +int xsane_save_ps(FILE *outfile, FILE *imagefile, Image_info *image_info, float width, float height, + int paper_left_margin, int paper_bottom_margin, int paperheight, int paperwidth, int paper_orientation, + GtkProgressBar *progress_bar, int *cancel_save) { DBG(DBG_proc, "xsane_save_ps\n"); - xsane_save_ps_create_header(outfile, image_info, - left, bottom, width, height, paperheight, paperwidth, rotate, progress_bar); + *cancel_save = 0; + + xsane_save_ps_create_header(outfile, image_info, width, height, + paper_left_margin, paper_bottom_margin, paperheight, paperwidth, paper_orientation, + progress_bar); if (image_info->colors == 1) /* lineart, halftone, grayscale */ { @@ -1651,22 +2590,61 @@ int xsane_save_ps(FILE *outfile, FILE *imagefile, Image_info *image_info, int le fprintf(outfile, "showpage\n"); fprintf(outfile, "end\n"); fprintf(outfile, "origstate restore\n"); + fprintf(outfile, "%%%%EOF\n"); fprintf(outfile, "\n"); + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + } + return (*cancel_save); } /* ---------------------------------------------------------------------------------------------------------------------- */ - #ifdef HAVE_LIBJPEG + +typedef struct +{ + struct jpeg_error_mgr pub;/* "public" fields */ + int *cancel_save; +} xsane_jpeg_error_mgr; + +typedef xsane_jpeg_error_mgr *xsane_jpeg_error_mgr_ptr; + +static void xsane_jpeg_error_exit(j_common_ptr cinfo) +{ + char buf[256]; + + /* cinfo->err points to a xsane_jpeg_error_mgr struct */ + xsane_jpeg_error_mgr_ptr xsane_jpeg_error_mgr_data = (xsane_jpeg_error_mgr_ptr) cinfo->err; + + + if (!*xsane_jpeg_error_mgr_data->cancel_save) + { + /* output original error message */ + (*cinfo->err->output_message) (cinfo); + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBJPEG); + xsane_back_gtk_error(buf, TRUE); + } + + *xsane_jpeg_error_mgr_data->cancel_save = 1; +} + int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int quality, GtkProgressBar *progress_bar, int *cancel_save) { unsigned char *data; char buf[256]; - int x,y; int components = 1; + int x,y; + int bytespp = 1; struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; + xsane_jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; DBG(DBG_proc, "xsane_save_jpeg\n"); @@ -1678,7 +2656,12 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int components = 3; } - data = malloc(image_info->image_width * components); + if (image_info->depth > 8) + { + bytespp = 2; + } + + data = malloc(image_info->image_width * components * bytespp); if (!data) { @@ -1687,7 +2670,10 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int return -1; /* error */ } - cinfo.err = jpeg_std_error(&jerr); + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = xsane_jpeg_error_exit; + jerr.cancel_save = cancel_save; + jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = image_info->image_width; @@ -1744,7 +2730,17 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int mask >>= 1; } } - else + else if (image_info->depth > 8) /* jpeg does not support 16 bits/sample, so we reduce it at first */ + { + guint16 *data16 = (guint16 *) data; + fread(data, components * 2, image_info->image_width, imagefile); + for (x = 0; x < image_info->image_width * components; x++) + { + data[x] = data16[x] / 256; + } + + } + else /* 8 bits/sample */ { fread(data, components, image_info->image_width, imagefile); } @@ -1842,7 +2838,7 @@ int xsane_save_tiff(const char *outfilename, FILE *imagefile, Image_info *image_ { snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM); xsane_back_gtk_error(buf, TRUE); - return -1; /* error */ + return -1; /* error */ } TIFFSetField(tiffile, TIFFTAG_IMAGEWIDTH, image_info->image_width); @@ -1899,7 +2895,16 @@ int xsane_save_tiff(const char *outfilename, FILE *imagefile, Image_info *image_ fread(data, 1, w, imagefile); - TIFFWriteScanline(tiffile, data, y, 0); + if (TIFFWriteScanline(tiffile, data, y, 0) != 1) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s", ERR_DURING_SAVE); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } if (*cancel_save) { @@ -1939,7 +2944,7 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { - snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBTIFF); + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_LIBPNG); xsane_back_gtk_error(buf, TRUE); return -1; /* error */ } @@ -2036,7 +3041,8 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c fread(data, components, byte_width, imagefile); row_ptr = data; - png_write_rows(png_ptr, &row_ptr, 1); + png_write_rows(png_ptr, &row_ptr, 1); /* errors are caught by test sor setjmp(...) */ + if (*cancel_save) { break; @@ -2149,7 +3155,7 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in for (x = 0; x < image_info->image_width * components; x++) /* this must be changed in dependance of endianess */ { fread(&val, 2, 1, imagefile); /* get data in machine order */ - data[x*2+0] = val/256; /* write data in network order (MSB first) */ + data[x*2+0] = val / 256; /* write data in network order (MSB first) */ data[x*2+1] = val & 255; } @@ -2172,19 +3178,16 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in /* ---------------------------------------------------------------------------------------------------------------------- */ -int xsane_save_pnm_16_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) +static int xsane_save_pnm_16_ascii_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) { int x,y; guint16 val; int count = 0; - DBG(DBG_proc, "xsane_save_pnm_16_gray\n"); + DBG(DBG_proc, "xsane_save_pnm_16_ascii_gray\n"); *cancel_save = 0; - /* write pgm ascii > 8 bpp */ - fprintf(outfile, "P2\n# SANE data follows\n%d %d\n65535\n", image_info->image_width, image_info->image_height); - for (y = 0; y < image_info->image_height; y++) { for (x = 0; x < image_info->image_width; x++) @@ -2199,6 +3202,18 @@ int xsane_save_pnm_16_gray(FILE *outfile, FILE *imagefile, Image_info *image_inf } } fprintf(outfile, "\n"); + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + count = 0; gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); @@ -2217,27 +3232,18 @@ int xsane_save_pnm_16_gray(FILE *outfile, FILE *imagefile, Image_info *image_inf /* ---------------------------------------------------------------------------------------------------------------------- */ -int xsane_save_pnm_16_color(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) +static int xsane_save_pnm_16_ascii_color(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) { int x,y; guint16 val; int count = 0; - DBG(DBG_proc, "xsane_save_pnm_16_color\n"); + DBG(DBG_proc, "xsane_save_pnm_16_ascii_color\n"); *cancel_save = 0; - /* write ppm ascii > 8 bpp */ - fprintf(outfile, "P3\n# SANE data follows\n%d %d\n65535\n", image_info->image_width, image_info->image_height); - for (y = 0; y < image_info->image_height; y++) { - gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); - while (gtk_events_pending()) - { - gtk_main_iteration(); - } - for (x = 0; x < image_info->image_width; x++) { fread(&val, 2, 1, imagefile); /* get data in machine order */ @@ -2256,8 +3262,130 @@ int xsane_save_pnm_16_color(FILE *outfile, FILE *imagefile, Image_info *image_in } } fprintf(outfile, "\n"); + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + count = 0; + gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (*cancel_save) + { + break; + } + } + + return (*cancel_save); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_save_pnm_16_binary_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) +{ + int x,y; + guint16 val; + + DBG(DBG_proc, "xsane_save_pnm_16_binary_gray\n"); + + *cancel_save = 0; + + for (y = 0; y < image_info->image_height; y++) + { + for (x = 0; x < image_info->image_width; x++) + { + fread(&val, 2, 1, imagefile); /* get data in machine order */ + fputc(val / 256, outfile); /* MSB fist */ + fputc(val & 255, outfile); /* LSB */ + } + + gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + + if (*cancel_save) + { + break; + } + } + + return (*cancel_save); +} + +/* ---------------------------------------------------------------------------------------------------------------------- */ + +static int xsane_save_pnm_16_binary_color(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save) +{ + int x,y; + guint16 val; + + DBG(DBG_proc, "xsane_save_pnm_16_binary_color\n"); + + *cancel_save = 0; + + for (y = 0; y < image_info->image_height; y++) + { + for (x = 0; x < image_info->image_width; x++) + { + /* red */ + fread(&val, 2, 1, imagefile); /* get data in machine order */ + fputc(val / 256, outfile); /* MSB fist */ + fputc(val & 255, outfile); /* LSB */ + + /* green */ + fread(&val, 2, 1, imagefile); /* get data in machine order */ + fputc(val / 256, outfile); /* MSB fist */ + fputc(val & 255, outfile); /* LSB */ + + /* blue */ + fread(&val, 2, 1, imagefile); /* get data in machine order */ + fputc(val / 256, outfile); /* MSB fist */ + fputc(val & 255, outfile); /* LSB */ + } + + gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height); + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + + if (ferror(outfile)) + { + char buf[255]; + + snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, strerror(errno)); + DBG(DBG_error, "%s\n", buf); + xsane_back_gtk_decision(ERR_HEADER_ERROR, (gchar **) error_xpm, buf, BUTTON_OK, NULL, TRUE /* wait */); + *cancel_save = 1; + break; + } + if (*cancel_save) { break; @@ -2273,13 +3401,31 @@ int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, Gt { DBG(DBG_proc, "xsane_save_pnm_16\n"); + *cancel_save = 0; + + xsane_write_pnm_header(outfile, image_info, preferences.save_pnm16_as_ascii); + if (image_info->colors > 1) { - xsane_save_pnm_16_color(outfile, imagefile, image_info, progress_bar, cancel_save); + if (preferences.save_pnm16_as_ascii) + { + xsane_save_pnm_16_ascii_color(outfile, imagefile, image_info, progress_bar, cancel_save); + } + else + { + xsane_save_pnm_16_binary_color(outfile, imagefile, image_info, progress_bar, cancel_save); + } } else { - xsane_save_pnm_16_gray(outfile, imagefile, image_info, progress_bar, cancel_save); + if (preferences.save_pnm16_as_ascii) + { + xsane_save_pnm_16_ascii_gray(outfile, imagefile, image_info, progress_bar, cancel_save); + } + else + { + xsane_save_pnm_16_binary_gray(outfile, imagefile, image_info, progress_bar, cancel_save); + } } return (*cancel_save); @@ -2289,7 +3435,7 @@ int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, Gt /* ---------------------------------------------------------------------------------------------------------------------- */ /* 0=ok, <0=error, 1=canceled */ -int xsane_save_image_as_lineart(char *input_filename, char *output_filename, GtkProgressBar *progress_bar, int *cancel_save) +int xsane_save_image_as_lineart(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save) { FILE *outfile; FILE *infile; @@ -2335,14 +3481,194 @@ int xsane_save_image_as_lineart(char *input_filename, char *output_filename, Gtk } /* ---------------------------------------------------------------------------------------------------------------------- */ + +int xsane_save_image_as_text(char *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save) +{ + char *arg[1000]; + char buf[256]; + int argnr; + pid_t pid; + int i; + int pipefd[2]; /* for progress communication with gocr */ + FILE *ocr_progress = NULL; + + DBG(DBG_proc, "xsane_save_image_as_text\n"); + + argnr = xsane_parse_options(preferences.ocr_command, arg); + + arg[argnr++] = strdup(preferences.ocr_inputfile_option); + arg[argnr++] = strdup(input_filename); + + arg[argnr++] = strdup(preferences.ocr_outputfile_option); + arg[argnr++] = strdup(output_filename); + + if (preferences.ocr_use_gui_pipe) + { + if (!pipe(pipefd)) /* success */ + { + DBG(DBG_info, "xsane_save_image_as_text: created pipe for progress communication\n"); + + arg[argnr++] = strdup(preferences.ocr_gui_outfd_option); + + snprintf(buf, sizeof(buf),"%d", pipefd[1]); + arg[argnr++] = strdup(buf); + } + else + { + DBG(DBG_info, "xsane_save_image_as_text: could not create pipe for progress communication\n"); + pipefd[0] = 0; + pipefd[1] = 0; + } + } + else + { + DBG(DBG_info, "xsane_save_image_as_text: no pipe for progress communication requested\n"); + pipefd[0] = 0; + pipefd[1] = 0; + } + + arg[argnr] = 0; + +#ifndef HAVE_OS2_H + pid = fork(); + + if (pid == 0) /* new process */ + { + FILE *ipc_file = NULL; + + if (xsane.ipc_pipefd[0]) /* did we create the progress pipe? */ + { + close(xsane.ipc_pipefd[0]); /* close reading end of pipe */ + ipc_file = fdopen(xsane.ipc_pipefd[1], "w"); + } + + if (pipefd[0]) /* did we create the progress pipe? */ + { + close(pipefd[0]); /* close reading end of pipe */ + } + + DBG(DBG_info, "trying to change user id for new subprocess:\n"); + DBG(DBG_info, "old effective uid = %d\n", (int) geteuid()); + setuid(getuid()); + DBG(DBG_info, "new effective uid = %d\n", (int) geteuid()); + + + execvp(arg[0], arg); /* does not return if successfully */ + DBG(DBG_error, "%s %s\n", ERR_FAILED_EXEC_OCR_CMD, preferences.ocr_command); + + /* send error message via IPC pipe to parent process */ + if (ipc_file) + { + fprintf(ipc_file, "%s %s:\n%s", ERR_FAILED_EXEC_OCR_CMD, preferences.ocr_command, strerror(errno)); + fflush(ipc_file); /* make sure message is displayed */ + fclose(ipc_file); + } + + _exit(0); /* do not use exit() here! otherwise gtk gets in trouble */ + } + +#else + pid = spawnvp(P_NOWAIT, arg[0], arg); + if (pid == -1) + { + DBG(DBG_error, "%s %s\n", ERR_FAILED_EXEC_OCR_CMD, preferences.ocr_command); + } +#endif + + if (pipefd[1]) + { + close(pipefd[1]); /* close writing end of pipe */ + ocr_progress = fdopen(pipefd[0], "r"); /* open reading end of pipe as file */ + } + + for (i=0; i<argnr; i++) + { + free(arg[i]); + } + + if (ocr_progress) /* pipe available */ + { + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); + + while (!feof(ocr_progress)) + { + int progress, subprogress; + float fprogress; + + fgets(buf, sizeof(buf), ocr_progress); + + if (!strncmp(preferences.ocr_progress_keyword, buf, strlen(preferences.ocr_progress_keyword))) + { + sscanf(buf + strlen(preferences.ocr_progress_keyword), "%d %d", &progress, &subprogress); + + snprintf(buf, sizeof(buf), "%s (%d:%d)", PROGRESS_OCR, progress, subprogress); + gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), buf); + + fprogress = progress / 100.0; + + if (fprogress < 0.0) + { + fprogress = 0.0; + } + + if (fprogress > 11.0) + { + fprogress = 1.0; + } + + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), fprogress); + } + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + } + + gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); + } + else /* no pipe available */ + { + while (pid) + { + int status = 0; + pid_t pid_status = waitpid(pid, &status, WNOHANG); + + if (pid == pid_status) + { + pid = 0; /* ok, child process has terminated */ + } + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + } + } + + if (pipefd[0]) + { + fclose(ocr_progress); /* close reading end of pipe */ + } + return (*cancel_save); +} +/* ---------------------------------------------------------------------------------------------------------------------- */ -int xsane_save_image_as(char *input_filename, char *output_filename, int output_format, GtkProgressBar *progress_bar, int *cancel_save) +/* save image in destination file format. lineart images that are stored as grayscale image are reduced to lineart! */ +int xsane_save_image_as(char *output_filename, char *input_filename, int output_format, GtkProgressBar *progress_bar, int *cancel_save) { FILE *outfile; FILE *infile; char buf[256]; Image_info image_info; + char lineart_filename[PATH_MAX]; + int remove_input_file = FALSE; + + DBG(DBG_proc, "xsane_save_image_as(output_file=%s, input_file=%s, type=%d)\n", output_filename, input_filename, output_format); + + *cancel_save = 0; infile = fopen(input_filename, "rb"); /* read binary (b for win32) */ if (infile == 0) @@ -2356,6 +3682,51 @@ int xsane_save_image_as(char *input_filename, char *output_filename, int output_ xsane_read_pnm_header(infile, &image_info); + if ((image_info.reduce_to_lineart) && (output_format != XSANE_PNM)) + { + DBG(DBG_info, "original image is a lineart => reduce to lineart\n"); + fclose(infile); + xsane_back_gtk_make_path(sizeof(lineart_filename), lineart_filename, 0, 0, "xsane-conversion-", xsane.dev_name, ".pbm", XSANE_PATH_TMP); + + snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_PACKING_DATA, output_filename); + + gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), buf); + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + xsane_save_image_as_lineart(lineart_filename, input_filename, progress_bar, cancel_save); + + input_filename = lineart_filename; + remove_input_file = TRUE; + + infile = fopen(input_filename, "rb"); /* read binary (b for win32) */ + if (infile == 0) + { + char buf[256]; + snprintf(buf, sizeof(buf), "%s `%s': %s", ERR_OPEN_FAILED, input_filename, strerror(errno)); + xsane_back_gtk_error(buf, TRUE); + + return -1; + } + + xsane_read_pnm_header(infile, &image_info); + } + + snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_SAVING_DATA, output_filename); + + gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), buf); + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + + #ifdef HAVE_LIBTIFF if (output_format == XSANE_TIFF) /* routines that want to have filename for saving */ { @@ -2378,7 +3749,14 @@ int xsane_save_image_as(char *input_filename, char *output_filename, int output_ switch(output_format) { case XSANE_PNM: - xsane_save_rotate_image(outfile, infile, &image_info, 0, progress_bar, cancel_save); + if (image_info.reduce_to_lineart) + { + xsane_save_grayscale_image_as_lineart(outfile, infile, &image_info, progress_bar, cancel_save); + } + else + { + xsane_copy_file(outfile, infile, progress_bar, cancel_save); + } break; #ifdef HAVE_LIBJPEG @@ -2410,22 +3788,27 @@ int xsane_save_image_as(char *input_filename, char *output_filename, int output_ { float imagewidth, imageheight; - imagewidth = image_info.image_width/image_info.resolution_x; /* width in inch */ - imageheight = image_info.image_height/image_info.resolution_y; /* height in inch */ + imagewidth = 72.0 * image_info.image_width/image_info.resolution_x; /* width in 1/72 inch */ + imageheight = 72.0 * image_info.image_height/image_info.resolution_y; /* height in 1/72 inch */ xsane_save_ps(outfile, infile, &image_info, - 0.0, /* left edge */ - 0.0, /* botoom edge */ imagewidth, imageheight, - 0.0, /* paperwidth */ - 0.0, /* paperheight */ - 0 /* portrait */, + 0, /* paper_left_margin */ + 0, /* paper_bottom_margin */ + (int) imagewidth, /* paper_width */ + (int) imageheight, /* paper_height */ + 0 /* portrait top left */, progress_bar, cancel_save); } break; /* switch format == XSANE_PS */ + case XSANE_TEXT: /* save as text using ocr program like gocr/jocr */ + { + xsane_save_image_as_text(output_filename, input_filename, progress_bar, cancel_save); + } + break; /* switch format == XSANE_TEXT */ default: snprintf(buf, sizeof(buf),"%s", ERR_UNKNOWN_SAVING_FORMAT); @@ -2436,6 +3819,19 @@ int xsane_save_image_as(char *input_filename, char *output_filename, int output_ remove(output_filename); /* no usable output: remove output file */ + if (remove_input_file) + { + remove(input_filename); /* remove lineart pbm file */ + } + + gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + return -2; break; /* switch format == default */ } @@ -2447,24 +3843,53 @@ int xsane_save_image_as(char *input_filename, char *output_filename, int output_ xsane_back_gtk_error(buf, TRUE); fclose(infile); + + if (remove_input_file) + { + remove(input_filename); /* remove lineart pbm file */ + } + + gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + return -2; } } fclose (infile); + if (remove_input_file) + { + remove(input_filename); /* remove lineart pbm file */ + } + if (*cancel_save) /* remove output file if saving has been canceled */ { remove(output_filename); } + gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), ""); + gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0); + + while (gtk_events_pending()) + { + gtk_main_iteration(); + } + return (*cancel_save); } /* ---------------------------------------------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------------------------- */ -#ifdef HAVE_LIBGIMP_GIMP_H +#ifdef HAVE_ANY_GIMP static int xsane_decode_devname(const char *encoded_devname, int n, char *buf) { char *dst, *limit; @@ -2695,10 +4120,17 @@ static void xsane_gimp_query(void) /* ---------------------------------------------------------------------------------------------------------------------- */ -static void xsane_gimp_run(char *name, int nparams, GimpParam * param, int *nreturn_vals, GimpParam ** return_vals) +#ifdef HAVE_GIMP_2 +static void xsane_gimp_run(const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) +{ + GimpRunMode run_mode; +#else /* GIMP-1.x */ +static void xsane_gimp_run(char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals) { - static GimpParam values[2]; GimpRunModeType run_mode; +#endif + + static GimpParam values[2]; char devname[1024]; char *args[2]; int nargs; @@ -2731,6 +4163,9 @@ static void xsane_gimp_run(char *name, int nparams, GimpParam * param, int *nret switch (run_mode) { case GIMP_RUN_INTERACTIVE: +#ifdef HAVE_GIMP_2 + gimp_extension_ack(); +#endif xsane_interface(nargs, args); values[0].data.d_status = GIMP_PDB_SUCCESS; break; @@ -2957,22 +4392,22 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i } } #ifdef SUPPORT_RGBA - else if (colors == 4) /* RGBA */ + else if (image_info.colors == 4) /* RGBA */ { int i; - switch (bits) + switch (image_info.depth) { case 8: /* 8 bit RGBA */ case 16: /* 16 bit RGBA already has been reduced to 8 bit */ - for (i = 0; i < pixel_width*pixel_height*4; ++i) + for (i = 0; i < image_info.image_width * image_info.image_height * 4; ++i) { tile[tile_offset++] = fgetc(imagefile); if (tile_offset % 4 == 0) { x++; - if (x >= pixel_width) + if (x >= image_info.image_width) { int tile_height = gimp_tile_height(); @@ -2981,11 +4416,11 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i if (y % tile_height == 0) { - gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, pixel_width, tile_height); + gimp_pixel_rgn_set_rect(®ion, tile, 0, y - tile_height, image_info.image_width, tile_height); tile_offset = 0; } - gtk_progress_bar_update(progress_bar, (float) y / pixel_height); /* update progress bar */ + gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */ while (gtk_events_pending()) { gtk_main_iteration(); @@ -3029,9 +4464,13 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i return 0; } -#endif /* HAVE_LIBGIMP_GIMP_H */ +#endif /* HAVE_ANY_GIMP */ /* ---------------------------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------------------------- */ + #ifdef XSANE_ACTIVATE_MAIL /* character base of base64 coding */ @@ -3070,7 +4509,7 @@ static void write_3chars_as_base64(unsigned char c1, unsigned char c2, unsigned void write_base64(int fd_socket, FILE *infile) { int c1, c2, c3; - int pos=0; + int pos = 0; while ((c1 = getc(infile)) != EOF) { @@ -3099,12 +4538,22 @@ void write_base64(int fd_socket, FILE *infile) pos = 0; } + + xsane.mail_progress_bytes += 3; + if ((int) ((xsane.mail_progress_bytes * 100) / xsane.mail_progress_size) != (int) (xsane.mail_progress_val * 100)) + { + xsane.mail_progress_val = (float) xsane.mail_progress_bytes / xsane.mail_progress_size; + xsane_front_gtk_mail_project_update_lockfile_status(); + } } if (pos) { write(fd_socket, "\n", 1); } + + xsane.mail_progress_val = 1.0; + xsane_front_gtk_mail_project_update_lockfile_status(); } /* ---------------------------------------------------------------------------------------------------------------------- */ @@ -3199,14 +4648,14 @@ void write_mail_mime_html(int fd_socket, char *boundary) /* ---------------------------------------------------------------------------------------------------------------------- */ -void write_mail_attach_image_png(int fd_socket, char *boundary, char *content_id, FILE *infile, char *filename) +void write_mail_attach_image(int fd_socket, char *boundary, char *content_id, char *content_type, FILE *infile, char *filename) { char buf[1024]; snprintf(buf, sizeof(buf), "--%s\n", boundary); write(fd_socket, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Content-Type: image/png\n"); + snprintf(buf, sizeof(buf), "Content-Type: %s\n", content_type); write(fd_socket, buf, strlen(buf)); if (content_id) @@ -3376,6 +4825,7 @@ int pop3_login(int fd_socket, char *user, char *passwd) /* ---------------------------------------------------------------------------------------------------------------------- */ /* not only a write routine, also reads data */ +/* returns -1 on error, 0 when ok */ int write_smtp_header(int fd_socket, char *from, char *to) { char buf[1024]; @@ -3398,6 +4848,19 @@ int write_smtp_header(int fd_socket, char *from, char *to) } DBG(DBG_info2, "< %s\n", buf); + if (buf[0] != '2') + { + DBG(DBG_info, "=> error\n"); + + if (xsane.mail_status) + { + free(xsane.mail_status); + } + xsane.mail_status = strdup(TEXT_MAIL_STATUS_SMTP_CONNECTION_FAILED); + xsane_front_gtk_mail_project_update_lockfile_status(); + return -1; + } + snprintf(buf, sizeof(buf), "MAIL FROM: %s\r\n", from); DBG(DBG_info2, "> %s", buf); write(fd_socket, buf, strlen(buf)); @@ -3408,6 +4871,20 @@ int write_smtp_header(int fd_socket, char *from, char *to) } DBG(DBG_info2, "< %s\n", buf); + if (buf[0] != '2') + { + DBG(DBG_info, "=> error\n"); + + if (xsane.mail_status) + { + free(xsane.mail_status); + } + xsane.mail_status = strdup(TEXT_MAIL_STATUS_SMTP_ERR_FROM); + xsane_front_gtk_mail_project_update_lockfile_status(); + return -1; + } + + snprintf(buf, sizeof(buf), "RCPT TO: %s\r\n", to); DBG(DBG_info2, "> %s", buf); write(fd_socket, buf, strlen(buf)); @@ -3418,6 +4895,19 @@ int write_smtp_header(int fd_socket, char *from, char *to) } DBG(DBG_info2, "< %s\n", buf); + if (buf[0] != '2') + { + DBG(DBG_info, "=> error\n"); + + if (xsane.mail_status) + { + free(xsane.mail_status); + } + xsane.mail_status = strdup(TEXT_MAIL_STATUS_SMTP_ERR_RCPT); + xsane_front_gtk_mail_project_update_lockfile_status(); + return -1; + } + snprintf(buf, sizeof(buf), "DATA\r\n"); DBG(DBG_info2, "> %s", buf); write(fd_socket, buf, strlen(buf)); @@ -3428,6 +4918,19 @@ int write_smtp_header(int fd_socket, char *from, char *to) } DBG(DBG_info2, "< %s\n", buf); + if ((buf[0] != '2') && (buf[0] != '3')) + { + DBG(DBG_info, "=> error\n"); + + if (xsane.mail_status) + { + free(xsane.mail_status); + } + xsane.mail_status = strdup(TEXT_MAIL_STATUS_SMTP_ERR_DATA); + xsane_front_gtk_mail_project_update_lockfile_status(); + return -1; + } + return 0; } @@ -3439,7 +4942,7 @@ int write_smtp_footer(int fd_socket) char buf[1024]; int len; - snprintf(buf, sizeof(buf), ".\r\n"); + snprintf(buf, sizeof(buf), "\r\n.\r\n"); DBG(DBG_info2, "> %s", buf); write(fd_socket, buf, strlen(buf)); len = read(fd_socket, buf, sizeof(buf)); |