summaryrefslogtreecommitdiff
path: root/src/xsane-save.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xsane-save.c')
-rw-r--r--src/xsane-save.c2013
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(&region, tile, 0, y - tile_height, pixel_width, tile_height);
+ gimp_pixel_rgn_set_rect(&region, 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));