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.c2482
1 files changed, 2132 insertions, 350 deletions
diff --git a/src/xsane-save.c b/src/xsane-save.c
index a56e2ce..cc5f934 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-2005 Oliver Rauch
+ Copyright (C) 1998-2007 Oliver Rauch
This file is part of the XSANE package.
This program is free software; you can redistribute it and/or modify
@@ -430,6 +430,7 @@ void xsane_read_pnm_header(FILE *file, Image_info *image_info)
image_info->resolution_x = 72.0;
image_info->resolution_y = 72.0;
image_info->reduce_to_lineart = FALSE;
+ image_info->enable_color_management = FALSE;
while (strcmp(buf, "# XSANE data follows\n"))
{
@@ -483,6 +484,26 @@ void xsane_read_pnm_header(FILE *file, Image_info *image_info)
&image_info->contrast_green,
&image_info->contrast_blue);
}
+ else if (!strncmp(buf, "# color-management=", 20))
+ {
+ sscanf(buf+20, "%d", &image_info->enable_color_management);
+ }
+ else if (!strncmp(buf, "# cms-function =", 20))
+ {
+ sscanf(buf+20, "%d", &image_info->cms_function);
+ }
+ else if (!strncmp(buf, "# cms-intent =", 20))
+ {
+ sscanf(buf+20, "%d", &image_info->cms_intent);
+ }
+ else if (!strncmp(buf, "# cms-bpc =", 20))
+ {
+ sscanf(buf+20, "%d", &image_info->cms_bpc);
+ }
+ else if (!strncmp(buf, "# icm-profile =", 20))
+ {
+ sscanf(buf+20, "%s", image_info->icm_profile);
+ }
else if (!strncmp(buf, "# reduce to lineart", 20))
{
image_info->reduce_to_lineart = TRUE;
@@ -510,11 +531,11 @@ void xsane_read_pnm_header(FILE *file, Image_info *image_info)
fgetc(file); /* read exactly one newline character */
- image_info->colors = 1;
+ image_info->channels = 1;
if (filetype_nr == 6) /* ppm RGB */
{
- image_info->colors = 3;
+ image_info->channels = 3;
}
}
#ifdef SUPPORT_RGBA
@@ -534,12 +555,12 @@ void xsane_read_pnm_header(FILE *file, Image_info *image_info)
image_info->depth = 16;
}
- image_info->colors = 4;
+ image_info->channels = 4;
}
#endif
DBG(DBG_info, "xsane_read_pnm_header: width=%d, height=%d, depth=%d, colors=%d, resolution_x=%f, resolution_y=%f\n",
- image_info->image_width, image_info->image_height, image_info->depth, image_info->colors,
+ image_info->image_width, image_info->image_height, image_info->depth, image_info->channels,
image_info->resolution_x, image_info->resolution_y);
}
@@ -573,7 +594,7 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a
}
- if (image_info->colors == 1)
+ if (image_info->channels == 1)
{
if (image_info->depth == 1)
{
@@ -618,6 +639,11 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a
"# gamma = %3.2f\n"
"# brightness = %4.1f\n"
"# contrast = %4.1f\n"
+ "# color-management= %d\n"
+ "# cms-function = %d\n"
+ "# cms-intent = %d\n"
+ "# cms-bpc = %d\n"
+ "# icm-profile = %s\n"
"# XSANE data follows\n"
"%05d %05d\n"
"%d\n",
@@ -627,11 +653,16 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a
image_info->gamma,
image_info->brightness,
image_info->contrast,
+ image_info->enable_color_management,
+ image_info->cms_function,
+ image_info->cms_intent,
+ image_info->cms_bpc,
+ image_info->icm_profile,
image_info->image_width, image_info->image_height,
maxval);
}
}
- else if (image_info->colors == 3)
+ else if (image_info->channels == 3)
{
fprintf(file, "P%d\n"
"# XSane settings:\n"
@@ -640,6 +671,11 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a
"# 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"
+ "# color-management= %d\n"
+ "# cms-function = %d\n"
+ "# cms-intent = %d\n"
+ "# cms-bpc = %d\n"
+ "# icm-profile = %s\n"
"# XSANE data follows\n"
"%05d %05d\n" \
"%d\n",
@@ -649,11 +685,16 @@ void xsane_write_pnm_header(FILE *file, Image_info *image_info, int save_pnm16_a
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->enable_color_management,
+ image_info->cms_function,
+ image_info->cms_intent,
+ image_info->cms_bpc,
+ image_info->icm_profile,
image_info->image_width, image_info->image_height,
maxval);
}
#ifdef SUPPORT_RGBA
- else if (image_info->colors == 4)
+ else if (image_info->channels == 4)
{
fprintf(file, "SANE_RGBA\n" \
"%d %d\n" \
@@ -793,6 +834,121 @@ int xsane_copy_file_by_name(char *output_filename, char *input_filename, GtkProg
/* ---------------------------------------------------------------------------------------------------------------------- */
+#ifdef HAVE_LIBLCMS
+cmsHTRANSFORM xsane_create_cms_transform(Image_info *image_info, int cms_function, int cms_intent, int cms_bpc)
+{
+ cmsHPROFILE hInProfile = NULL;
+ cmsHPROFILE hOutProfile = NULL;
+ cmsHTRANSFORM hTransform = NULL;
+ DWORD cms_input_format;
+ DWORD cms_output_format;
+ DWORD cms_flags = 0;
+
+ if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE)
+ {
+ return NULL;
+ }
+
+ DBG(DBG_info, "Prepare CMS transform\n");
+
+ cmsErrorAction(LCMS_ERROR_SHOW);
+
+ if (cms_bpc)
+ {
+ cms_flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
+ }
+
+ if (image_info->channels == 1) /* == 1 (grayscale) */
+ {
+ if (image_info->depth == 8)
+ {
+ cms_input_format = TYPE_GRAY_8;
+ cms_output_format = TYPE_GRAY_8;
+ }
+ else
+ {
+ cms_input_format = TYPE_GRAY_16;
+ cms_output_format = TYPE_GRAY_16;
+ }
+ }
+ else /* color */
+ {
+ if (image_info->depth == 8)
+ {
+ cms_input_format = TYPE_RGB_8;
+ cms_output_format = TYPE_RGB_8;
+ }
+ else
+ {
+ cms_input_format = TYPE_RGB_16;
+ cms_output_format = TYPE_RGB_16;
+ }
+ }
+
+ hInProfile = cmsOpenProfileFromFile(image_info->icm_profile, "r");
+ if (!hInProfile)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_SCANNER_ICM, image_info->icm_profile);
+ xsane_back_gtk_error(buf, TRUE);
+ }
+#if 0
+{
+ LPGAMMATABLE Gamma = cmsBuildGamma(256, 3.0);
+ hOutProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma);
+ cmsFreeGamma(Gamma);
+}
+#endif
+ if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_SRGB)
+ {
+ hOutProfile = cmsCreate_sRGBProfile();
+ }
+ else
+ {
+ hOutProfile = cmsOpenProfileFromFile(preferences.working_color_space_icm_profile, "r");
+ if (!hOutProfile)
+ {
+ char buf[TEXTBUFSIZE];
+
+ cmsCloseProfile(hInProfile);
+
+ snprintf(buf, sizeof(buf), "%s\n%s %s: %s\n", ERR_CMS_CONVERSION, ERR_CMS_OPEN_ICM_FILE, CMS_DISPLAY_ICM, preferences.display_icm_profile);
+ xsane_back_gtk_error(buf, TRUE);
+ }
+ }
+
+ if (!hOutProfile)
+ {
+ char buf[TEXTBUFSIZE];
+
+ cmsCloseProfile(hInProfile);
+
+ snprintf(buf, sizeof(buf), "%s\n", ERR_CMS_CONVERSION);
+ xsane_back_gtk_error(buf, TRUE);
+ }
+
+ hTransform = cmsCreateTransform(hInProfile, cms_input_format,
+ hOutProfile, cms_output_format,
+ cms_intent, cms_flags);
+
+ cmsCloseProfile(hInProfile);
+ cmsCloseProfile(hOutProfile);
+
+ if (!hTransform)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s\n%s\n", ERR_CMS_CONVERSION, ERR_CMS_CREATE_TRANSFORM);
+ xsane_back_gtk_error(buf, TRUE);
+ }
+
+ return hTransform;
+}
+#endif
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
int xsane_save_grayscale_image_as_lineart(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save)
{
int x, y, bit;
@@ -901,14 +1057,14 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
image_info->resolution_x *= x_scale;
image_info->resolution_y *= y_scale;
- original_line = malloc(original_image_width * image_info->colors * bytespp);
+ original_line = malloc(original_image_width * image_info->channels * 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);
+ new_line = malloc(new_image_width * image_info->channels * bytespp);
if (!new_line)
{
free(original_line);
@@ -916,7 +1072,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
return -1;
}
- pixel_val = malloc(new_image_width * image_info->colors * sizeof(float));
+ pixel_val = malloc(new_image_width * image_info->channels * sizeof(float));
if (!pixel_val)
{
free(original_line);
@@ -925,7 +1081,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
return -1;
}
- pixel_norm = malloc(new_image_width * image_info->colors * sizeof(float));
+ pixel_norm = malloc(new_image_width * image_info->channels * sizeof(float));
if (!pixel_norm)
{
free(original_line);
@@ -939,8 +1095,8 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
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));
+ memset(pixel_val, 0, new_image_width * image_info->channels * sizeof(float));
+ memset(pixel_norm, 0, new_image_width * image_info->channels * sizeof(float));
y_new = 0;
y_go = 1.0 / y_scale;
@@ -960,7 +1116,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
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 */
+ fread(original_line, original_image_width, image_info->channels * bytespp, imagefile); /* read one line */
original_line16 = (guint16 *) original_line;
}
@@ -970,23 +1126,22 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
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++)
+ for (c = 0; c < image_info->channels; c++)
{
if (bytespp == 1)
{
- color = original_line[((int) x) * image_info->colors + c];
+ color = original_line[((int) x) * image_info->channels + c];
}
else /* bytespp == 2 */
{
- color = original_line16[((int) x) * image_info->colors + c];
+ color = original_line16[((int) x) * image_info->channels + c];
}
- pixel_val [x_new * image_info->colors + c] += factor * color;
- pixel_norm[x_new * image_info->colors + c] += factor;
+ pixel_val [x_new * image_info->channels + c] += factor * color;
+ pixel_norm[x_new * image_info->channels + c] += factor;
}
x_go -= x_factor;
@@ -1023,7 +1178,7 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
if (bytespp == 1)
{
- for (x_new = 0; x_new < new_image_width * image_info->colors; x_new++)
+ for (x_new = 0; x_new < new_image_width * image_info->channels; x_new++)
{
new_line[x_new] = (int) (pixel_val[x_new] / pixel_norm[x_new]);
}
@@ -1032,13 +1187,13 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
{
guint16 *new_line16 = (guint16 *) new_line;
- for (x_new = 0; x_new < new_image_width * image_info->colors; x_new++)
+ for (x_new = 0; x_new < new_image_width * image_info->channels; 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 */
+ fwrite(new_line, new_image_width, image_info->channels * bytespp, outfile); /* write one line */
if (ferror(outfile))
{
@@ -1052,8 +1207,8 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
}
/* 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));
+ memset(pixel_val, 0, new_image_width * image_info->channels * sizeof(float));
+ memset(pixel_norm, 0, new_image_width * image_info->channels * sizeof(float));
y_new++;
y_go = 1.0 / y_scale;
@@ -1079,6 +1234,11 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
read_line = (oldy != (int) y);
}
+ if (read_line) /* we have to write one more line */
+ {
+ fwrite(new_line, new_image_width, image_info->channels * bytespp, outfile); /* write one line */
+ }
+
free(original_line);
free(new_line);
free(pixel_val);
@@ -1113,14 +1273,14 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
image_info->resolution_x *= x_scale;
image_info->resolution_y *= y_scale;
- original_line = malloc(original_image_width * image_info->colors * bytespp);
+ original_line = malloc(original_image_width * image_info->channels * 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);
+ new_line = malloc(new_image_width * image_info->channels * bytespp);
if (!new_line)
{
free(original_line);
@@ -1143,18 +1303,18 @@ int xsane_save_scaled_image(FILE *outfile, FILE *imagefile, Image_info *image_in
for (; ((int) original_y) - old_original_y; old_original_y += 1)
{
- fread(original_line, original_image_width, image_info->colors * bytespp, imagefile); /* read one line */
+ fread(original_line, original_image_width, image_info->channels * bytespp, imagefile); /* read one line */
}
for (x = 0; x < new_image_width; x++)
{
- for (i = 0; i < image_info->colors * bytespp; i++)
+ for (i = 0; i < image_info->channels * bytespp; i++)
{
- new_line[x * image_info->colors * bytespp + i] = original_line[((int) (x / x_scale)) * image_info->colors * bytespp + i];
+ new_line[x * image_info->channels * bytespp + i] = original_line[((int) (x / x_scale)) * image_info->channels * bytespp + i];
}
}
- fwrite(new_line, new_image_width, image_info->colors * bytespp, outfile); /* write one line */
+ fwrite(new_line, new_image_width, image_info->channels * bytespp, outfile); /* write one line */
original_y += 1/y_scale;
@@ -1187,7 +1347,7 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image
guint16 *color_cache_ptr;
int bytespp = 1;
int color_radius;
- int color_width = image_info->image_width * image_info->colors;
+ int color_width = image_info->image_width * image_info->channels;
radius--; /* correct radius : 1 means nothing happens */
@@ -1196,7 +1356,7 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image
radius = 1;
}
- color_radius = radius * image_info->colors;
+ color_radius = radius * image_info->channels;
if (image_info->depth > 8)
{
@@ -1252,7 +1412,7 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image
if (xmin < 0)
{
- xmin = x % image_info->colors;
+ xmin = x % image_info->channels;
}
if (xmax > color_width)
@@ -1271,11 +1431,11 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image
{
line_cache_ptr = line_cache + (sy-ymin) * color_width + xmin;
- for (sx = xmin; sx <= xmax; sx+=image_info->colors) /* x part */
+ for (sx = xmin; sx <= xmax; sx+=image_info->channels) /* x part */
{
*color_cache_ptr = *line_cache_ptr;
color_cache_ptr++;
- line_cache_ptr += image_info->colors;
+ line_cache_ptr += image_info->channels;
}
}
@@ -1314,11 +1474,11 @@ int xsane_save_despeckle_image(FILE *outfile, FILE *imagefile, Image_info *image
{
line_cache16_ptr = line_cache16 + (sy-ymin) * color_width + xmin;
- for (sx = xmin; sx <= xmax; sx+=image_info->colors)
+ for (sx = xmin; sx <= xmax; sx+=image_info->channels)
{
*color_cache_ptr = *line_cache16_ptr;
color_cache_ptr++;
- line_cache16_ptr += image_info->colors;
+ line_cache16_ptr += image_info->channels;
}
}
@@ -1407,14 +1567,14 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
xsane_write_pnm_header(outfile, image_info, 0);
- line_cache = malloc(image_info->image_width * image_info->colors * bytespp * (2 * intradius + 1));
+ line_cache = malloc(image_info->image_width * image_info->channels * 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);
+ fread(line_cache, image_info->image_width * image_info->channels * bytespp, (2 * intradius + 1), imagefile);
for (y = 0; y < image_info->image_height; y++)
{
@@ -1424,22 +1584,22 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
gtk_main_iteration();
}
- for (x = 0; x < image_info->image_width * image_info->colors; x++)
+ for (x = 0; x < image_info->image_width * image_info->channels; x++)
{
xmin_flag = xmax_flag = ymin_flag = ymax_flag = TRUE;
- xmin = x - intradius * image_info->colors;
- xmax = x + intradius * image_info->colors;
+ xmin = x - intradius * image_info->channels;
+ xmax = x + intradius * image_info->channels;
if (xmin < 0)
{
- xmin = x % image_info->colors;
+ xmin = x % image_info->channels;
xmin_flag = FALSE;
}
- if (xmax > image_info->image_width * image_info->colors)
+ if (xmax > image_info->image_width * image_info->channels)
{
- xmax = image_info->image_width * image_info->colors;
+ xmax = image_info->image_width * image_info->channels;
xmax_flag = FALSE;
}
@@ -1467,7 +1627,7 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
{
for (sy = ymin+1; sy <= ymax-1 ; sy++)
{
- val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->colors + xmin];
+ val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->channels + xmin];
norm += outer_factor;
}
}
@@ -1476,14 +1636,14 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
{
for (sy = ymin+1; sy <= ymax-1 ; sy++)
{
- val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->colors + xmax];
+ val += outer_factor * line_cache[(sy-ymin) * image_info->image_width * image_info->channels + 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)
+ for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels ; sx += image_info->channels)
{
val += outer_factor * line_cache[sx];
norm += outer_factor;
@@ -1492,18 +1652,18 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
if (ymax_flag) /* integrate over bottom margin */
{
- for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors)
+ for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels ; sx += image_info->channels)
{
- val += outer_factor * line_cache[(ymax-ymin) * image_info->image_width * image_info->colors + sx];
+ val += outer_factor * line_cache[(ymax-ymin) * image_info->image_width * image_info->channels + 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)
+ for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels; sx+=image_info->channels)
{
- val += line_cache[(sy-ymin) * image_info->image_width * image_info->colors + sx];
+ val += line_cache[(sy-ymin) * image_info->image_width * image_info->channels + sx];
norm += 1.0;
}
}
@@ -1519,7 +1679,7 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
{
for (sy = ymin+1; sy <= ymax-1 ; sy++)
{
- val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + xmin];
+ val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->channels + xmin];
norm += outer_factor;
}
}
@@ -1528,14 +1688,14 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
{
for (sy = ymin+1; sy <= ymax-1 ; sy++)
{
- val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + xmax];
+ val += outer_factor * line_cache16[(sy-ymin) * image_info->image_width * image_info->channels + 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)
+ for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels ; sx += image_info->channels)
{
val += outer_factor * line_cache16[sx];
norm += outer_factor;
@@ -1544,18 +1704,18 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
if (ymax_flag) /* integrate over bottom margin */
{
- for (sx = xmin+image_info->colors; sx <= xmax-image_info->colors ; sx += image_info->colors)
+ for (sx = xmin+image_info->channels; sx <= xmax-image_info->channels ; sx += image_info->channels)
{
- val += outer_factor * line_cache16[(ymax-ymin) * image_info->image_width * image_info->colors + sx];
+ val += outer_factor * line_cache16[(ymax-ymin) * image_info->image_width * image_info->channels + sx];
norm += outer_factor;
}
}
for (sy = ymin; sy <= ymax; sy++) /* integrate internal square */
{
- for (sx = xmin; sx <= xmax; sx+=image_info->colors)
+ for (sx = xmin; sx <= xmax; sx+=image_info->channels)
{
- val += line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + sx];
+ val += line_cache16[(sy-ymin) * image_info->image_width * image_info->channels + sx];
norm += 1.0;
}
}
@@ -1581,10 +1741,10 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
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);
+ memcpy(line_cache, line_cache + image_info->image_width * image_info->channels * bytespp,
+ image_info->image_width * image_info->channels * bytespp * 2 * intradius);
+ fread(line_cache + image_info->image_width * image_info->channels * bytespp * 2 * intradius,
+ image_info->image_width * image_info->channels * bytespp, 1, imagefile);
}
}
@@ -1616,14 +1776,14 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
xsane_write_pnm_header(outfile, image_info, 0);
- line_cache = malloc(image_info->image_width * image_info->colors * bytespp * (2 * radius + 1));
+ line_cache = malloc(image_info->image_width * image_info->channels * bytespp * (2 * radius + 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 * radius + 1), imagefile);
+ fread(line_cache, image_info->image_width * image_info->channels * bytespp, (2 * radius + 1), imagefile);
for (y = 0; y < image_info->image_height; y++)
{
@@ -1633,19 +1793,19 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
gtk_main_iteration();
}
- for (x = 0; x < image_info->image_width * image_info->colors; x++)
+ for (x = 0; x < image_info->image_width * image_info->channels; x++)
{
- xmin = x - radius * image_info->colors;
- xmax = x + radius * image_info->colors;
+ xmin = x - radius * image_info->channels;
+ xmax = x + radius * image_info->channels;
if (xmin < 0)
{
- xmin = x % image_info->colors;
+ xmin = x % image_info->channels;
}
- if (xmax > image_info->image_width * image_info->colors)
+ if (xmax > image_info->image_width * image_info->channels)
{
- xmax = image_info->image_width * image_info->colors;
+ xmax = image_info->image_width * image_info->channels;
}
ymin = y - radius;
@@ -1668,9 +1828,9 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
{
for (sy = ymin; sy <= ymax; sy++)
{
- for (sx = xmin; sx <= xmax; sx+=image_info->colors)
+ for (sx = xmin; sx <= xmax; sx+=image_info->channels)
{
- val += line_cache[(sy-ymin) * image_info->image_width * image_info->colors + sx];
+ val += line_cache[(sy-ymin) * image_info->image_width * image_info->channels + sx];
count++;
}
}
@@ -1684,9 +1844,9 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
for (sy = ymin; sy <= ymax; sy++)
{
- for (sx = xmin; sx <= xmax; sx+=image_info->colors)
+ for (sx = xmin; sx <= xmax; sx+=image_info->channels)
{
- val += line_cache16[(sy-ymin) * image_info->image_width * image_info->colors + sx];
+ val += line_cache16[(sy-ymin) * image_info->image_width * image_info->channels + sx];
count++;
}
}
@@ -1699,10 +1859,10 @@ int xsane_save_blur_image(FILE *outfile, FILE *imagefile, Image_info *image_info
if ((y > radius) && (y < image_info->image_height - radius))
{
- memcpy(line_cache, line_cache + image_info->image_width * image_info->colors * bytespp,
- image_info->image_width * image_info->colors * bytespp * 2 * radius);
- fread(line_cache + image_info->image_width * image_info->colors * bytespp * 2 * radius,
- image_info->image_width * image_info->colors * bytespp, 1, imagefile);
+ memcpy(line_cache, line_cache + image_info->image_width * image_info->channels * bytespp,
+ image_info->image_width * image_info->channels * bytespp * 2 * radius);
+ fread(line_cache + image_info->image_width * image_info->channels * bytespp * 2 * radius,
+ image_info->image_width * image_info->channels * bytespp, 1, imagefile);
}
}
@@ -1734,7 +1894,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in
pos0 = ftell(imagefile); /* mark position to skip header */
- bytespp = image_info->colors;
+ bytespp = image_info->channels;
if (image_info->depth > 8)
{
@@ -2227,7 +2387,7 @@ int xsane_save_rotate_image(FILE *outfile, FILE *imagefile, Image_info *image_in
/* ---------------------------------------------------------------------------------------------------------------------- */
-void xsane_save_ps_create_document_header(FILE *outfile, int pages, int flatdecode)
+void xsane_save_ps_create_document_header(FILE *outfile, int pages, int flatedecode)
{
DBG(DBG_proc, "xsane_save_ps_create_document_header\n");
@@ -2236,7 +2396,7 @@ void xsane_save_ps_create_document_header(FILE *outfile, int pages, int flatdeco
SANE_VERSION_MAJOR(xsane.sane_backend_versioncode),
SANE_VERSION_MINOR(xsane.sane_backend_versioncode));
fprintf(outfile, "%%%%DocumentData: Clean7Bit\n");
- if (flatdecode)
+ if (flatedecode)
{
fprintf(outfile, "%%%%LanguageLevel: 3\n");
}
@@ -2288,7 +2448,7 @@ static void xsane_save_ps_create_page_header(FILE *outfile, int page,
float width, float height,
int paper_left_margin, int paper_bottom_margin,
int paper_width, int paper_height,
- int paper_orientation, int flatdecode,
+ int paper_orientation, int flatedecode,
GtkProgressBar *progress_bar)
{
int degree, position_left, position_bottom, box_left, box_bottom, box_right, box_top, depth;
@@ -2377,7 +2537,7 @@ static void xsane_save_ps_create_page_header(FILE *outfile, int page,
if (depth > 8)
{
- depth = 8;
+ depth = 12;
}
fprintf(outfile, "\n");
@@ -2394,23 +2554,22 @@ static void xsane_save_ps_create_page_header(FILE *outfile, int page,
fprintf(outfile, "%d rotate\n", degree);
fprintf(outfile, "%d %d translate\n", position_left, position_bottom);
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\n");
- fprintf(outfile, "/ASCII85Decode filter\n");
+ fprintf(outfile, "<<\n");
+ fprintf(outfile, " /ImageType 1\n");
+ fprintf(outfile, " /Width %d\n", image_info->image_width);
+ fprintf(outfile, " /Height %d\n", image_info->image_height);
+ fprintf(outfile, " /BitsPerComponent %d\n", depth);
+ fprintf(outfile, " /Decode [0 1 0 1 0 1]\n");
+ fprintf(outfile, " /ImageMatrix [%d %d %d %d %d %d]\n", image_info->image_width, 0, 0, -image_info->image_height, 0, image_info->image_height);
+ fprintf(outfile, " /DataSource currentfile /ASCII85Decode filter");
#ifdef HAVE_LIBZ
- if (flatdecode)
+ if (flatedecode)
{
- fprintf(outfile, "/FlateDecode filter\n");
+ fprintf(outfile, " /FlateDecode filter");
}
#endif
-
- if (image_info->colors == 3) /* what about RGBA here ? */
- {
- fprintf(outfile, "false 3 colorimage\n");
- fprintf(outfile, "\n");
- }
- else
+ fprintf(outfile, "\n");
+ fprintf(outfile, ">>\n");
{
fprintf(outfile, "image\n");
fprintf(outfile, "\n");
@@ -2429,8 +2588,102 @@ static void xsane_save_ps_create_page_trailer(FILE *outfile)
/* ---------------------------------------------------------------------------------------------------------------------- */
#ifdef HAVE_LIBZ
+/* Utility function for the PDF output */
+static int xsane_write_flatedecode(FILE *outfile, unsigned char *line, int len, int finish)
+{
+ static unsigned char *cbuf = NULL;
+ static int cbuflen = 0;
+ static int linelen = 0;
+ int outlen;
+ static int init = 0;
+ static z_stream s;
+ int ret;
+ int flush;
+ static int count = 0;
+
+ DBG(DBG_proc, "xsane_write_flatedecode\n");
+
+ if (linelen != len)
+ {
+ linelen = len;
+ if (cbuf != NULL)
+ {
+ free(cbuf);
+ }
+ /* buffer length = length + 0.1 * length + 12 (mandatory) */
+ cbuflen = len + len / 10 + 12;
+ cbuf = malloc(cbuflen);
+ }
+
+ if (cbuf == NULL)
+ {
+ DBG(DBG_error, "cbuf allocation failed\n");
+ return 1;
+ }
+
+ if (!init)
+ {
+ s.zalloc = Z_NULL;
+ s.zfree = Z_NULL;
+ s.opaque = Z_NULL;
+
+ ret = deflateInit(&s, Z_DEFAULT_COMPRESSION);
+
+ if (ret != Z_OK)
+ {
+ DBG(DBG_error, "deflateInit failed\n");
+ free(cbuf);
+ return 1;
+ }
+
+ init = 1;
+ }
+
+ s.avail_in = len;
+ s.next_in = line;
+
+ do
+ {
+ s.avail_out = cbuflen;
+ s.next_out = cbuf;
+
+ flush = (finish) ? Z_FINISH : Z_NO_FLUSH;
+
+ ret = deflate(&s, flush);
+
+ if (ret == Z_STREAM_ERROR)
+ {
+ DBG(DBG_error, "deflate failed\n");
+ free(cbuf);
+ return 1;
+ }
+
+ outlen = cbuflen - s.avail_out;
+
+ fwrite(cbuf, outlen, 1, outfile);
+ } while (s.avail_out == 0);
+
+ if (finish)
+ {
+ DBG(DBG_info, "xsane_write_flatedecode finished\n");
+ deflateEnd(&s);
+ free(cbuf);
+ cbuf = NULL;
+ init = 0;
+ cbuflen = 0;
+ linelen = 0;
+ count = 0;
+ }
+
+ return 0;
+}
+#endif
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+#ifdef HAVE_LIBZ
/* Utility function for the PostScript output */
-static int xsane_write_compressed_a85_flatdecode(FILE *outfile, unsigned char *line, int len, int finish)
+static int xsane_write_compressed_a85_flatedecode(FILE *outfile, unsigned char *line, int len, int finish)
{
static unsigned char *cbuf = NULL;
static int cbuflen = 0;
@@ -2446,7 +2699,7 @@ static int xsane_write_compressed_a85_flatdecode(FILE *outfile, unsigned char *l
static unsigned char a85block[6] = {0, 0, 0, 0, 0, 0};
static int count = 0;
- DBG(DBG_proc, "xsane_write_compressed_a85_flatdecode\n");
+ DBG(DBG_proc, "xsane_write_compressed_a85_flatedecode\n");
if (linelen != len)
{
@@ -2741,7 +2994,91 @@ static int xsane_write_compressed_a85(FILE *outfile, unsigned char *line, int le
/* ---------------------------------------------------------------------------------------------------------------------- */
-static int xsane_save_ps_pdf_bw(FILE *outfile, FILE *imagefile, Image_info *image_info, int flatdecode, GtkProgressBar *progress_bar, int *cancel_save)
+#ifdef HAVE_LIBLCMS
+static int xsane_write_CSA(FILE *outfile, char *input_profile, int intent)
+{
+ cmsHPROFILE hProfile;
+ size_t n;
+ char* buffer;
+
+ hProfile = cmsOpenProfileFromFile(input_profile, "r");
+ if (!hProfile)
+ {
+ return -1;
+ }
+
+ n = cmsGetPostScriptCSA(hProfile, intent, NULL, 0);
+ if (n == 0)
+ {
+ return -2;
+ }
+
+ buffer = (char*) malloc(n + 1);
+ if (!buffer)
+ {
+ return -3;
+ }
+
+ cmsGetPostScriptCSA(hProfile, intent, buffer, n);
+ buffer[n] = 0;
+
+ fprintf(outfile, "%s", buffer);
+ fprintf(outfile, "setcolorspace\n");
+
+ free(buffer);
+ cmsCloseProfile(hProfile);
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_write_CRD(FILE *outfile, char *output_profile, int intent, int blackpointcompensation)
+{
+ cmsHPROFILE hProfile;
+ size_t n;
+ char* buffer;
+ DWORD flags = cmsFLAGS_NODEFAULTRESOURCEDEF;
+
+ hProfile = cmsOpenProfileFromFile(output_profile, "r");
+ if (!hProfile)
+ {
+ return -1;
+ }
+
+ if (blackpointcompensation)
+ {
+ flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
+ }
+
+ n = cmsGetPostScriptCRDEx(hProfile, intent, flags, NULL, 0);
+ if (n == 0)
+ {
+ return -2;
+ }
+
+ buffer = (char*) malloc(n + 1);
+ if (!buffer)
+ {
+ return -3;
+ }
+
+ cmsGetPostScriptCRDEx(hProfile, intent, flags, buffer, n);
+ buffer[n] = 0;
+
+ fprintf(outfile, "%s", buffer);
+ fprintf(outfile, "setcolorrendering\n");
+
+ free(buffer);
+ cmsCloseProfile(hProfile);
+
+ return 0;
+}
+#endif
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_save_ps_pdf_bw(FILE *outfile, FILE *imagefile, Image_info *image_info, int ascii85decode, int flatedecode, GtkProgressBar *progress_bar, int *cancel_save)
{
int x, y;
int bytes_per_line = (image_info->image_width+7)/8;
@@ -2778,15 +3115,26 @@ static int xsane_save_ps_pdf_bw(FILE *outfile, FILE *imagefile, Image_info *imag
line[x] = fgetc(imagefile) ^ 255;
}
+ if (ascii85decode)
+ {
#ifdef HAVE_LIBZ
- if (flatdecode)
+ if (flatedecode)
+ {
+ ret = xsane_write_compressed_a85_flatedecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1));
+ }
+ else
+#endif
+ {
+ ret = xsane_write_compressed_a85(outfile, line, bytes_per_line, (y == image_info->image_height - 1));
+ }
+ }
+ else if (flatedecode)
{
- ret = xsane_write_compressed_a85_flatdecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1));
+ ret = xsane_write_flatedecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1));
}
else
-#endif
{
- ret = xsane_write_compressed_a85(outfile, line, bytes_per_line, (y == image_info->image_height - 1));
+ fwrite(line, bytes_per_line, 1, outfile);
}
if ((ret != 0) || (ferror(outfile)))
@@ -2822,11 +3170,15 @@ static int xsane_save_ps_pdf_bw(FILE *outfile, FILE *imagefile, Image_info *imag
/* ---------------------------------------------------------------------------------------------------------------------- */
-static int xsane_save_ps_pdf_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, int flatdecode, GtkProgressBar *progress_bar, int *cancel_save)
+static int xsane_save_ps_pdf_gray(FILE *outfile, FILE *imagefile, Image_info *image_info, int ascii85decode, int flatedecode, cmsHTRANSFORM hTransform, int embed_scanner_icm_profile, GtkProgressBar *progress_bar, int *cancel_save)
{
- int x, y;
- int ret;
- unsigned char *line;
+ int x, y;
+ int ret;
+ unsigned char *line;
+#ifdef HAVE_LIBLCMS
+ unsigned char *line_raw = NULL;
+#endif
+
DBG(DBG_proc, "xsane_save_ps_pdf_gray\n");
@@ -2865,15 +3217,26 @@ static int xsane_save_ps_pdf_gray(FILE *outfile, FILE *imagefile, Image_info *im
}
}
+ if (ascii85decode)
+ {
#ifdef HAVE_LIBZ
- if (flatdecode)
+ if (flatedecode)
+ {
+ ret = xsane_write_compressed_a85_flatedecode(outfile, line, image_info->image_width, (y == image_info->image_height - 1));
+ }
+ else
+#endif
+ {
+ ret = xsane_write_compressed_a85(outfile, line, image_info->image_width, (y == image_info->image_height - 1));
+ }
+ }
+ else if (flatedecode)
{
- ret = xsane_write_compressed_a85_flatdecode(outfile, line, image_info->image_width, (y == image_info->image_height - 1));
+ ret = xsane_write_flatedecode(outfile, line, image_info->image_width, (y == image_info->image_height - 1));
}
else
-#endif
{
- ret = xsane_write_compressed_a85(outfile, line, image_info->image_width, (y == image_info->image_height - 1));
+ fwrite(line, image_info->image_width, 1, outfile);
}
if ((ret != 0) || (ferror(outfile)))
@@ -2915,28 +3278,106 @@ static int xsane_save_ps_pdf_gray(FILE *outfile, FILE *imagefile, Image_info *im
/* ---------------------------------------------------------------------------------------------------------------------- */
-static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *image_info, int flatdecode, GtkProgressBar *progress_bar, int *cancel_save)
+static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *image_info, int ascii85decode, int flatedecode,
+ cmsHTRANSFORM hTransform, int do_transform,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
int x, y;
int ret;
- unsigned char *line, *linep;
+ unsigned char *line = NULL, *linep = NULL, *line16 = NULL;
+ int bytes_per_line;
+ int bytes_per_line16 = 0;
+#ifdef HAVE_LIBLCMS
+ unsigned char *line_raw = NULL;
+#endif
DBG(DBG_proc, "xsane_save_ps_pdf_color\n");
*cancel_save = 0;
- line = (unsigned char *) malloc(image_info->image_width * 3);
+ if (image_info->depth > 8) /* reduce 16 bit images to 12 bit */
+ {
+ bytes_per_line16 = image_info->image_width * 3 * 2;
+
+ bytes_per_line = (image_info->image_width/2) * 3 * 3;
+ if (image_info->image_width & 1)
+ {
+ bytes_per_line += 5;
+ }
+
+ DBG(DBG_info, "bytes_per_line16 = %d\n", bytes_per_line16);
+ DBG(DBG_info, "bytes_per_line = %d\n", bytes_per_line);
+
+ line16 = (unsigned char *) malloc(bytes_per_line16);
+
+ if (line16 == NULL)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s malloc for line16 failed", 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;
+ return (*cancel_save);
+ }
+ DBG(DBG_info, "line16 allocated\n");
+ }
+ else
+ {
+ bytes_per_line = image_info->image_width * 3;
+ bytes_per_line16 = image_info->image_width * 3;
+ DBG(DBG_info, "bytes_per_line = %d\n", bytes_per_line);
+ }
+
+ line = (unsigned char *) malloc(bytes_per_line);
if (line == NULL)
{
char buf[TEXTBUFSIZE];
- snprintf(buf, sizeof(buf), "%s malloc failed", ERR_DURING_SAVE);
+ snprintf(buf, sizeof(buf), "%s malloc for line failed", 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 */);
+
+ if (line16)
+ {
+ free(line16);
+ }
+
*cancel_save = 1;
return (*cancel_save);
}
+ DBG(DBG_info, "line allocated\n");
+
+#ifdef HAVE_LIBLCMS
+ if (do_transform && (hTransform != NULL))
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ line_raw = (unsigned char *) malloc(bytes_per_line16);
+
+ if (line_raw == NULL)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s malloc for line_raw failed", 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 */);
+
+ free(line);
+
+ if (line16)
+ {
+ free(line16);
+ }
+
+ *cancel_save = 1;
+ return (*cancel_save);
+ }
+
+ DBG(DBG_info, "line_raw allocated\n");
+ }
+#endif
for (y = 0; y < image_info->image_height; y++)
{
@@ -2948,39 +3389,101 @@ static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *i
linep = line;
- if (image_info->depth > 8) /* reduce 16 bit images */
+ if (image_info->depth > 8) /* reduce 16 bit images to 12 bit */
{
- guint16 val;
+#ifdef HAVE_LIBLCMS
+ if (do_transform && (hTransform != NULL))
+ {
+ fread(line_raw, 6, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, line_raw, line16, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(line16, 6, image_info->image_width, imagefile);
+ }
- for (x = 0; x < image_info->image_width; x++)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ for (x = 0; x < image_info->image_width; x=x+2)
{
- fread(&val, 2, 1, imagefile);
- *linep++ = val/256;
- fread(&val, 2, 1, imagefile);
- *linep++ = val/256;
- fread(&val, 2, 1, imagefile);
- *linep++ = val/256;
+ *linep++ = line16[6*x+1]; /* red high+middle */
+ *linep++ = (line16[6*x+0] & 240) | (line16[6*x+3] >> 4); /* red low | green high */
+ *linep++ = ((line16[6*x+3] & 15) << 4) | ((line16[6*x+2] & 240) >> 4); /* green middle | green low */
+
+ *linep++ = line16[6*x+5]; /* blue high+middle */
+
+ if (x == image_info->image_width-1)
+ {
+ *linep++ = (line16[6*x+4] & 240); /* blue low */
+ break;
+ }
+
+ *linep++ = (line16[6*x+4] & 240) | (line16[6*x+7] >> 4); /* blue low | red high */
+ *linep++ = ((line16[6*x+7] & 15) << 4) | ((line16[6*x+6] & 240) >> 4); /* red middle | red low */
+
+ *linep++ = line16[6*x+9]; /* green high+middle */
+ *linep++ = (line16[6*x+8] & 240) | (line16[6*x+11] >> 4); /* green low | blue high */
+ *linep++ = ((line16[6*x+11] & 15) << 4) | ((line16[6*x+10] & 240) >> 4); /* blue middle | blue low */
}
+#else
+ for (x = 0; x < image_info->image_width; x=x+2)
+ {
+ *linep++ = line16[6*x+0]; /* red high+middle */
+ *linep++ = (line16[6*x+1] & 240) | (line16[6*x+2] >> 4); /* red low | green high */
+ *linep++ = ((line16[6*x+2] & 15) << 4) | ((line16[6*x+3] & 240) >> 4); /* green middle | green low */
+
+ *linep++ = line16[6*x+4]; /* blue high+middle */
+
+ if (x == image_info->image_width-1)
+ {
+ *linep++ = (line16[6*x+5] & 240); /* blue low */
+ break;
+ }
+
+ *linep++ = (line16[6*x+5] & 240) | (line16[6*x+6] >> 4); /* blue low | red high */
+ *linep++ = ((line16[6*x+6] & 15) << 4) | ((line16[6*x+7] & 240) >> 4); /* red middle | red low */
+
+ *linep++ = line16[6*x+8]; /* green high+middle */
+ *linep++ = (line16[6*x+9] & 240) | (line16[6*x+10] >> 4); /* green low | blue high */
+ *linep++ = ((line16[6*x+10] & 15) << 4) | ((line16[6*x+11] & 240) >> 4); /* blue middle | blue low */
+ }
+#endif
}
else /* 8 bits/sample */
{
- for (x = 0; x < image_info->image_width; x++)
+#ifdef HAVE_LIBLCMS
+ if (do_transform && (hTransform != NULL))
{
- *linep++ = fgetc(imagefile);
- *linep++ = fgetc(imagefile);
- *linep++ = fgetc(imagefile);
+ fread(line_raw, 3, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, line_raw, line, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(line, 3, image_info->image_width, imagefile);
}
}
+ if (ascii85decode)
+ {
#ifdef HAVE_LIBZ
- if (flatdecode)
+ if (flatedecode)
+ {
+ ret = xsane_write_compressed_a85_flatedecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1));
+ }
+ else
+#endif
+ {
+ ret = xsane_write_compressed_a85(outfile, line, bytes_per_line, (y == image_info->image_height - 1));
+ }
+ }
+ else if (flatedecode)
{
- ret = xsane_write_compressed_a85_flatdecode(outfile, line, (image_info->image_width * 3), (y == image_info->image_height - 1));
+ ret = xsane_write_flatedecode(outfile, line, bytes_per_line, (y == image_info->image_height - 1));
}
else
-#endif
{
- ret = xsane_write_compressed_a85(outfile, line, (image_info->image_width * 3), (y == image_info->image_height - 1));
+ fwrite(line, bytes_per_line, 1, outfile);
}
if ((ret != 0) || (ferror(outfile)))
@@ -3009,6 +3512,18 @@ static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *i
}
}
+#ifdef HAVE_LIBLCMS
+ if (line_raw)
+ {
+ free(line_raw);
+ }
+#endif
+
+ if (line16)
+ {
+ free(line16);
+ }
+
free(line);
return (*cancel_save);
@@ -3019,7 +3534,8 @@ static int xsane_save_ps_pdf_color(FILE *outfile, FILE *imagefile, Image_info *i
int xsane_save_ps_page(FILE *outfile, int page,
FILE *imagefile, Image_info *image_info, float width, float height,
int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation,
- int flatdecode,
+ int flatedecode,
+ cmsHTRANSFORM hTransform, int do_transform,
GtkProgressBar *progress_bar, int *cancel_save)
{
DBG(DBG_proc, "xsane_save_ps_page\n");
@@ -3027,23 +3543,23 @@ int xsane_save_ps_page(FILE *outfile, int page,
xsane_save_ps_create_page_header(outfile, page,
image_info, width, height,
paper_left_margin, paper_bottom_margin, paperwidth, paperheight, paper_orientation,
- flatdecode,
+ flatedecode,
progress_bar);
- if (image_info->colors == 1) /* lineart, halftone, grayscale */
+ if (image_info->channels == 1) /* lineart, halftone, grayscale */
{
if (image_info->depth == 1) /* lineart, halftone */
{
- xsane_save_ps_pdf_bw(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save);
+ xsane_save_ps_pdf_bw(outfile, imagefile, image_info, TRUE, flatedecode, progress_bar, cancel_save);
}
else /* grayscale */
{
- xsane_save_ps_pdf_gray(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save);
+ xsane_save_ps_pdf_gray(outfile, imagefile, image_info, TRUE, flatedecode, hTransform, do_transform, progress_bar, cancel_save);
}
}
else /* color RGB */
{
- xsane_save_ps_pdf_color(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save);
+ xsane_save_ps_pdf_color(outfile, imagefile, image_info, TRUE, flatedecode, hTransform, do_transform, progress_bar, cancel_save);
}
xsane_save_ps_create_page_trailer(outfile);
@@ -3065,19 +3581,46 @@ int xsane_save_ps_page(FILE *outfile, int page,
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 paperwidth, int paperheight, int paper_orientation,
- int flatdecode,
+ int flatedecode,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile, int embed_CSA, char *CSA_profile,
+ int embed_CRD, char *CRD_profile, int blackpointcompensation, int intent,
GtkProgressBar *progress_bar, int *cancel_save)
{
DBG(DBG_proc, "xsane_save_ps\n");
*cancel_save = 0;
- xsane_save_ps_create_document_header(outfile, 1 /* pages */, flatdecode);
+ xsane_save_ps_create_document_header(outfile, 1 /* pages */, flatedecode);
+
+#ifdef HAVE_LIBLCMS
+ if ((apply_ICM_profile) && (embed_CRD))
+ {
+ xsane_write_CRD(outfile, CRD_profile, intent, blackpointcompensation); /* write printer profile to ps file */
+ }
+
+
+ if ((apply_ICM_profile) && (embed_CSA))
+ {
+ xsane_write_CSA(outfile, CSA_profile, intent); /* write scanner profile to ps file */
+ }
+ else
+#endif
+ {
+ if (image_info->channels == 1) /* lineart, halftone, grayscale */
+ {
+ fprintf(outfile, "/DeviceGray setcolorspace\n");
+ }
+ else
+ {
+ fprintf(outfile, "/DeviceRGB setcolorspace\n");
+ }
+ }
xsane_save_ps_page(outfile, 1 /* page */,
imagefile, image_info, width, height,
paper_left_margin, paper_bottom_margin, paperwidth, paperheight, paper_orientation,
- flatdecode,
+ flatedecode,
+ hTransform, (apply_ICM_profile && (!embed_CSA) && (!embed_CRD)) /* do_transform */,
progress_bar, cancel_save);
xsane_save_ps_create_document_trailer(outfile, 0 /* we defined pages at beginning */);
@@ -3097,7 +3640,93 @@ int xsane_save_ps(FILE *outfile, FILE *imagefile, Image_info *image_info, float
/* ---------------------------------------------------------------------------------------------------------------------- */
-void xsane_save_pdf_create_document_header(FILE *outfile, struct pdf_xref *xref, int pages, int flatdecode)
+static int xsane_embed_pdf_icm_profile(FILE *outfile, struct pdf_xref *xref, char *icm_filename, int flatedecode, int icc_object)
+{
+ FILE *icm_profile;
+ size_t size, embed_len;
+ unsigned char *embed_buffer;
+ int ret;
+
+ DBG(DBG_proc, "xsane_embed_pdf_icm_profile(%s)\n", icm_filename);
+
+ icm_profile = fopen(icm_filename, "rb");
+ if (icm_profile == NULL)
+ {
+ DBG(DBG_error, "Could not open ICM profile \"%s\" for reading\n", icm_filename);
+ return -1;
+ }
+
+ fseek(icm_profile, 0, SEEK_END);
+ size = ftell(icm_profile);
+ fseek(icm_profile, 0, SEEK_SET);
+
+ embed_buffer = malloc(size + 1);
+ if (embed_buffer)
+ {
+ xref->obj[icc_object] = ftell(outfile);
+ fprintf(outfile, "%d 0 obj\n", icc_object);
+ fprintf(outfile, " << /N 3\n"); /* 3 channels */
+ fprintf(outfile, " /Alternate /DeviceRGB\n");
+#ifdef HAVE_LIBZ
+ if (flatedecode)
+ {
+ fprintf(outfile, " /Filter /FlateDecode\n");
+ }
+#endif
+
+ fprintf(outfile, " /Length >>\n");
+
+ /* Position of the stream length, to be written later on */
+ xref->slenp = ftell(outfile) - 15;
+
+ fprintf(outfile, "stream\n");
+
+ /* Start of the stream data */
+ xref->slen = ftell(outfile);
+
+ embed_len = fread(embed_buffer, 1, size, icm_profile);
+ embed_buffer[embed_len] = 0;
+ fclose(icm_profile);
+
+#ifdef HAVE_LIBZ
+ if (flatedecode)
+ {
+ ret = xsane_write_flatedecode(outfile, embed_buffer, size, TRUE);
+ }
+ else
+#endif
+ {
+ fwrite(embed_buffer, size, 1, outfile);
+ ret = 0;
+ }
+
+ /* Go back and write the length of the stream */
+ xref->slen = ftell(outfile) - xref->slen;
+ fseek(outfile, xref->slenp, SEEK_SET);
+ fprintf(outfile, "%lu", xref->slen);
+ fseek(outfile, 0L, SEEK_END);
+
+ fprintf(outfile, "endstream\n");
+ fprintf(outfile, "endobj\n");
+ fprintf(outfile, "\n");
+
+ free(embed_buffer);
+ }
+ else
+ {
+ DBG(DBG_info, "Embedding ICM profile \"%s\" to PDF: no mem\n", icm_filename);
+ fclose(icm_profile);
+ return -2;
+ }
+
+
+ DBG(DBG_info, "Embedding ICM profile \"%s\" to PDF file retuned with status %d\n", icm_filename, ret);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_save_pdf_create_document_header(FILE *outfile, struct pdf_xref *xref, int pages, int flatedecode)
{
int i;
@@ -3126,7 +3755,7 @@ void xsane_save_pdf_create_document_header(FILE *outfile, struct pdf_xref *xref,
fprintf(outfile, " /Kids [\n");
for (i=0; i < pages; i++)
{
- fprintf(outfile, " %d 0 R\n", i * 2 + 4);
+ fprintf(outfile, " %d 0 R\n", i * 2 + 6);
}
fprintf(outfile, " ]\n");
fprintf(outfile, " /Count %d\n", pages);
@@ -3143,7 +3772,8 @@ static void xsane_save_pdf_create_page_header(FILE *outfile, struct pdf_xref *xr
float width, float height,
int paper_left_margin, int paper_bottom_margin,
int paper_width, int paper_height,
- int paper_orientation, int flatdecode,
+ int paper_orientation,
+ int flatedecode, int icc_object,
GtkProgressBar *progress_bar)
{
int position_left, position_bottom, box_left, box_bottom, box_right, box_top, depth;
@@ -3231,26 +3861,26 @@ static void xsane_save_pdf_create_page_header(FILE *outfile, struct pdf_xref *xr
depth = image_info->depth;
- if (depth > 8)
+ if (depth > 8) /* PDF does not support 16bits/sample in a standard image */
{
depth = 8;
}
- xref->obj[page * 2 + 2] = ftell(outfile);
- fprintf(outfile, "%d 0 obj\n", page * 2 + 2);
+ xref->obj[page * 2 + 4] = ftell(outfile);
+ fprintf(outfile, "%d 0 obj\n", page * 2 + 4);
fprintf(outfile, " << /Type /Page\n");
fprintf(outfile, " /Parent 3 0 R\n");
fprintf(outfile, " /MediaBox [%d %d %d %d]\n", box_left, box_bottom, box_right, box_top);
- fprintf(outfile, " /Contents %d 0 R\n", page * 2 + 3);
- fprintf(outfile, " /Resources << /ProcSet %d 0 R >>\n", page * 2 + 4);
+ fprintf(outfile, " /Contents %d 0 R\n", page * 2 + 5);
+ fprintf(outfile, " /Resources << /ProcSet %d 0 R >>\n", page * 2 + 6);
fprintf(outfile, " >>\n");
fprintf(outfile, "endobj\n");
fprintf(outfile, "\n");
/* Offset of object 5, for xref */
- xref->obj[page * 2 + 3] = ftell(outfile);
+ xref->obj[page * 2 + 5] = ftell(outfile);
- fprintf(outfile, "%d 0 obj\n", page * 2 + 3);
+ fprintf(outfile, "%d 0 obj\n", page * 2 + 5);
fprintf(outfile, " << /Length >>\n");
/* Position of the stream length, to be written later on */
@@ -3269,9 +3899,17 @@ static void xsane_save_pdf_create_page_header(FILE *outfile, struct pdf_xref *xr
fprintf(outfile, " /W %d\n", image_info->image_width);
fprintf(outfile, " /H %d\n", image_info->image_height);
- if (image_info->colors == 3) /* what about RGBA here ? */
+ if ((icc_object) && (image_info->depth != 1))
+ {
+ fprintf(outfile, " /ColorSpace [/ICCBased %d 0 R]\n", icc_object);
+ }
+
+ if (image_info->channels == 3) /* what about RGBA here ? */
{
- fprintf(outfile, " /CS /RGB\n");
+ if (icc_object == 0)
+ {
+ fprintf(outfile, " /CS /RGB\n");
+ }
fprintf(outfile, " /BPC %d\n", depth);
}
else if (image_info->depth == 1) /* BW */
@@ -3281,22 +3919,20 @@ static void xsane_save_pdf_create_page_header(FILE *outfile, struct pdf_xref *xr
}
else /* gray */
{
- fprintf(outfile, " /CS /G\n");
- fprintf(outfile, " /BPC 8\n");
+ if (icc_object == 0)
+ {
+ fprintf(outfile, " /CS /G\n");
+ }
+ fprintf(outfile, " /BPC %d\n", depth);
}
#ifdef HAVE_LIBZ
- if (flatdecode)
- {
- fprintf(outfile, " /F [/A85 /FlateDecode]\n");
- }
- else
+ if (flatedecode)
{
- fprintf(outfile, " /F /A85\n");
+ fprintf(outfile, " /F /FlateDecode\n");
}
-#else
- fprintf(outfile, " /F /A85\n");
#endif
+
fprintf(outfile, "ID\n");
}
@@ -3311,17 +3947,17 @@ void xsane_save_pdf_create_document_trailer(FILE *outfile, struct pdf_xref *xref
/* PDF document trailer */
/* Offset of object 6, for xref */
- xref->obj[pages * 2 + 4] = ftell(outfile);
+ xref->obj[pages * 2 + 6] = ftell(outfile);
- fprintf(outfile, "%d 0 obj\n", pages * 2 + 4);
+ fprintf(outfile, "%d 0 obj\n", pages * 2 + 6);
fprintf(outfile, " [/PDF]\n");
fprintf(outfile, "endobj\n");
fprintf(outfile, "\n");
/* Offset of object 7, for xref */
- xref->obj[pages * 2 + 5] = ftell(outfile);
+ xref->obj[pages * 2 + 7] = ftell(outfile);
- fprintf(outfile, "%d 0 obj\n", pages * 2 + 5);
+ fprintf(outfile, "%d 0 obj\n", pages * 2 + 7);
fprintf(outfile, " << /Title (XSane scanned image)\n");
fprintf(outfile, " /Creator (XSane version %s (sane %d.%d) - by Oliver Rauch)\n",
VERSION,
@@ -3342,19 +3978,19 @@ void xsane_save_pdf_create_document_trailer(FILE *outfile, struct pdf_xref *xref
xref->xref = ftell(outfile);
fprintf(outfile, "xref\n");
- fprintf(outfile, "0 %d\n", pages * 2 + 6);
+ fprintf(outfile, "0 %d\n", pages * 2 + 8);
fprintf(outfile, "0000000000 65535 f \n");
- for (i=1; i <= pages * 2 + 5; i++)
+ for (i=1; i <= pages * 2 + 7; i++)
{
fprintf(outfile, "%010lu 00000 n \n", xref->obj[i]);
}
fprintf(outfile, "\n");
fprintf(outfile, "trailer\n");
- fprintf(outfile, " << /Size %d\n", pages * 2 + 6);
+ fprintf(outfile, " << /Size %d\n", pages * 2 + 8);
fprintf(outfile, " /Root 1 0 R\n");
- fprintf(outfile, " /Info %d 0 R\n", pages * 2 + 5);
+ fprintf(outfile, " /Info %d 0 R\n", pages * 2 + 7);
fprintf(outfile, " >>\n");
fprintf(outfile, "startxref\n");
fprintf(outfile, "%lu\n", xref->xref);
@@ -3370,7 +4006,7 @@ static void xsane_save_pdf_create_page_trailer(FILE *outfile, struct pdf_xref *x
fprintf(outfile, "Q\n");
/* Go back and write the length of the stream */
- xref->slen = ftell(outfile) - xref->slen - 1;
+ xref->slen = ftell(outfile) - xref->slen; /* we had a "-1" at the end but I do not understand the reason for -1, without looks better */
fseek(outfile, xref->slenp, SEEK_SET);
fprintf(outfile, "%lu", xref->slen);
fseek(outfile, 0L, SEEK_END);
@@ -3385,7 +4021,8 @@ static void xsane_save_pdf_create_page_trailer(FILE *outfile, struct pdf_xref *x
int xsane_save_pdf_page(FILE *outfile, struct pdf_xref *xref, int page,
FILE *imagefile, Image_info *image_info, float width, float height,
int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation,
- int flatdecode,
+ int flatedecode,
+ cmsHTRANSFORM hTransform, int do_transform, int icc_object,
GtkProgressBar *progress_bar, int *cancel_save)
{
@@ -3394,23 +4031,23 @@ int xsane_save_pdf_page(FILE *outfile, struct pdf_xref *xref, int page,
xsane_save_pdf_create_page_header(outfile, xref, page,
image_info, width, height,
paper_left_margin, paper_bottom_margin, paperwidth, paperheight, paper_orientation,
- flatdecode,
+ flatedecode, icc_object,
progress_bar);
- if (image_info->colors == 1) /* lineart, halftone, grayscale */
+ if (image_info->channels == 1) /* lineart, halftone, grayscale */
{
if (image_info->depth == 1) /* lineart, halftone */
{
- xsane_save_ps_pdf_bw(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save);
+ xsane_save_ps_pdf_bw(outfile, imagefile, image_info, FALSE, flatedecode, progress_bar, cancel_save);
}
else /* grayscale */
{
- xsane_save_ps_pdf_gray(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save);
+ xsane_save_ps_pdf_gray(outfile, imagefile, image_info, FALSE, flatedecode, hTransform, do_transform, progress_bar, cancel_save);
}
}
else /* color RGB */
{
- xsane_save_ps_pdf_color(outfile, imagefile, image_info, flatdecode, progress_bar, cancel_save);
+ xsane_save_ps_pdf_color(outfile, imagefile, image_info, FALSE, flatedecode, hTransform, do_transform, progress_bar, cancel_save);
}
xsane_save_pdf_create_page_trailer(outfile, xref);
@@ -3432,21 +4069,33 @@ int xsane_save_pdf_page(FILE *outfile, struct pdf_xref *xref, int page,
int xsane_save_pdf(FILE *outfile, FILE *imagefile, Image_info *image_info, float width, float height,
int paper_left_margin, int paper_bottom_margin, int paperwidth, int paperheight, int paper_orientation,
- int flatdecode,
+ int flatedecode,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function,
GtkProgressBar *progress_bar, int *cancel_save)
{
- struct pdf_xref xref;
+ struct pdf_xref xref;
+ int icc_object = 0;
DBG(DBG_proc, "xsane_save_pdf\n");
*cancel_save = 0;
- xsane_save_pdf_create_document_header(outfile, &xref, 1, flatdecode);
+ xsane_save_pdf_create_document_header(outfile, &xref, 1, flatedecode);
+
+ xref.obj[4] = ftell(outfile);
+ xref.obj[5] = ftell(outfile);
+
+ if (apply_ICM_profile && (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE))
+ {
+ icc_object = 4;
+ xsane_embed_pdf_icm_profile(outfile, &xref, image_info->icm_profile, flatedecode, icc_object);
+ }
xsane_save_pdf_page(outfile, &xref, 1,
imagefile, image_info, width, height,
paper_left_margin, paper_bottom_margin, paperwidth, paperheight, paper_orientation,
- flatdecode,
+ flatedecode,
+ hTransform, apply_ICM_profile && ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE)) /* do_transform */, icc_object,
progress_bar, cancel_save);
xsane_save_pdf_create_document_trailer(outfile, &xref, 1);
@@ -3465,8 +4114,8 @@ int xsane_save_pdf(FILE *outfile, FILE *imagefile, Image_info *image_info, float
}
/* ---------------------------------------------------------------------------------------------------------------------- */
-#ifdef HAVE_LIBJPEG
+#ifdef HAVE_LIBJPEG
typedef struct
{
struct jpeg_error_mgr pub;/* "public" fields */
@@ -3494,7 +4143,110 @@ static void xsane_jpeg_error_exit(j_common_ptr cinfo)
*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)
+/* ---------------------------------------------------------- */
+
+#ifdef HAVE_LIBLCMS
+static void xsane_jpeg_write_icm_profile(j_compress_ptr cinfo_ptr, const JOCTET *icm_data_ptr, unsigned int icm_data_len)
+{
+#define ICM_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICM */
+#define ICM_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
+#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
+#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICM_OVERHEAD_LEN)
+
+ unsigned int num_markers; /* total number of markers we'll write */
+ int cur_marker = 1; /* per spec, counting starts at 1 */
+ unsigned int length; /* number of bytes to write in this marker */
+
+ /* Calculate the number of markers we'll need, rounding up of course */
+ num_markers = icm_data_len / MAX_DATA_BYTES_IN_MARKER;
+ if (num_markers * MAX_DATA_BYTES_IN_MARKER != icm_data_len)
+ {
+ num_markers++;
+ }
+
+ while (icm_data_len > 0)
+ {
+ length = icm_data_len; /* length of profile to put in this marker */
+ if (length > MAX_DATA_BYTES_IN_MARKER)
+ {
+ length = MAX_DATA_BYTES_IN_MARKER;
+ }
+ icm_data_len -= length;
+
+ /* Write the JPEG marker header (APP2 code and marker length) */
+ jpeg_write_m_header(cinfo_ptr, ICM_MARKER, (unsigned int) (length + ICM_OVERHEAD_LEN));
+
+ /* Write the marker identifying string "ICC_PROFILE" (null-terminated).
+ * We code it in this less-than-transparent way so that the code works
+ * even if the local character set is not ASCII.
+ */
+ jpeg_write_m_byte(cinfo_ptr, 0x49);
+ jpeg_write_m_byte(cinfo_ptr, 0x43);
+ jpeg_write_m_byte(cinfo_ptr, 0x43);
+ jpeg_write_m_byte(cinfo_ptr, 0x5F);
+ jpeg_write_m_byte(cinfo_ptr, 0x50);
+ jpeg_write_m_byte(cinfo_ptr, 0x52);
+ jpeg_write_m_byte(cinfo_ptr, 0x4F);
+ jpeg_write_m_byte(cinfo_ptr, 0x46);
+ jpeg_write_m_byte(cinfo_ptr, 0x49);
+ jpeg_write_m_byte(cinfo_ptr, 0x4C);
+ jpeg_write_m_byte(cinfo_ptr, 0x45);
+ jpeg_write_m_byte(cinfo_ptr, 0x0);
+
+ /* Add the sequencing info */
+ jpeg_write_m_byte(cinfo_ptr, cur_marker);
+ jpeg_write_m_byte(cinfo_ptr, (int) num_markers);
+
+ /* Add the profile data */
+ while (length--)
+ {
+ jpeg_write_m_byte(cinfo_ptr, *icm_data_ptr);
+ icm_data_ptr++;
+ }
+ cur_marker++;
+ }
+}
+
+/* ---------------------------------------------------------- */
+
+static void xsane_jpeg_embed_scanner_icm_profile(j_compress_ptr cinfo_ptr, const char *icm_filename)
+{
+ FILE *icm_profile;
+ size_t size, embed_len;
+ LPBYTE embed_buffer;
+
+ DBG(DBG_proc, "xsane_jpeg_embed_scanner_icm_profile(%s)\n", icm_filename);
+
+ icm_profile = fopen(icm_filename, "rb");
+ if (icm_profile == NULL)
+ {
+ return;
+ }
+
+ fseek(icm_profile, 0, SEEK_END);
+ size = ftell(icm_profile);
+ fseek(icm_profile, 0, SEEK_SET);
+
+ embed_buffer = (LPBYTE) malloc(size + 1);
+ if (embed_buffer)
+ {
+ embed_len = fread(embed_buffer, 1, size, icm_profile);
+ fclose(icm_profile);
+ embed_buffer[embed_len] = 0;
+
+ xsane_jpeg_write_icm_profile(cinfo_ptr, embed_buffer, embed_len);
+ free(embed_buffer);
+
+ DBG(DBG_info, "ICM profile %s has been embedded to jpeg file\n", icm_filename);
+ }
+}
+#endif
+
+/* ---------------------------------------------------------- */
+
+int xsane_save_jpeg(FILE *outfile, int quality, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
unsigned char *data;
char buf[TEXTBUFSIZE];
@@ -3504,12 +4256,15 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int
struct jpeg_compress_struct cinfo;
xsane_jpeg_error_mgr jerr;
JSAMPROW row_pointer[1];
+#ifdef HAVE_LIBLCMS
+ unsigned char *data_raw = NULL;
+#endif
DBG(DBG_proc, "xsane_save_jpeg\n");
*cancel_save = 0;
- if (image_info->colors == 3)
+ if (image_info->channels == 3)
{
components = 3;
}
@@ -3528,6 +4283,24 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int
return -1; /* error */
}
+#ifdef HAVE_LIBLCMS
+ if (apply_ICM_profile && (cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL))
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info->image_width * components * bytespp);
+
+ if (!data_raw)
+ {
+ free(data);
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+ }
+#endif
+
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = xsane_jpeg_error_exit;
jerr.cancel_save = cancel_save;
@@ -3537,7 +4310,7 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int
cinfo.image_width = image_info->image_width;
cinfo.image_height = image_info->image_height;
cinfo.input_components = components;
- if (image_info->colors == 3)
+ if (image_info->channels == 3)
{
cinfo.in_color_space = JCS_RGB;
}
@@ -3560,6 +4333,20 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int
jpeg_start_compress(&cinfo, TRUE);
+#ifdef HAVE_LIBLCMS
+ if (apply_ICM_profile)
+ {
+ if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE)
+ {
+ xsane_jpeg_embed_scanner_icm_profile(&cinfo, image_info->icm_profile);
+ }
+ else if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS)
+ {
+ xsane_jpeg_embed_scanner_icm_profile(&cinfo, preferences.working_color_space_icm_profile);
+ }
+ }
+#endif
+
for (y = 0; y < image_info->image_height; y++)
{
gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height);
@@ -3596,7 +4383,18 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int
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);
+#ifdef HAVE_LIBLCMS
+ if (apply_ICM_profile && (cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL))
+ {
+ fread(data_raw, components * 2, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, components * 2, image_info->image_width, imagefile);
+ }
+
for (x = 0; x < image_info->image_width * components; x++)
{
data[x] = data16[x] / 256;
@@ -3605,7 +4403,17 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int
}
else /* 8 bits/sample */
{
- fread(data, components, image_info->image_width, imagefile);
+#ifdef HAVE_LIBLCMS
+ if (apply_ICM_profile && (cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL))
+ {
+ fread(data_raw, components, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, components, image_info->image_width, imagefile);
+ }
}
row_pointer[0] = data;
@@ -3619,6 +4427,13 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int
}
jpeg_finish_compress(&cinfo);
+
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
free(data);
return (*cancel_save);
@@ -3628,9 +4443,58 @@ int xsane_save_jpeg(FILE *outfile, FILE *imagefile, Image_info *image_info, int
/* ---------------------------------------------------------------------------------------------------------------------- */
#ifdef HAVE_LIBTIFF
+#ifdef HAVE_LIBLCMS
+static void xsane_tiff_embed_scanner_icm_profile(TIFF *tiffile, const char *icm_filename)
+{
+ FILE *icm_profile;
+ size_t size;
+ char *icm_profile_buffer;
+
+ DBG(DBG_proc, "xsane_tiff_embed_scanner_icm_profile(%s)\n", icm_filename);
+ if((icm_profile = fopen(icm_filename, "rb")))
+ {
+ fseek(icm_profile, 0, SEEK_END);
+ size = ftell(icm_profile);
+ fseek(icm_profile, 0, SEEK_SET);
+
+ icm_profile_buffer = (char *) malloc(size + 1);
+
+ if (icm_profile_buffer)
+ {
+ if (fread(icm_profile_buffer, 1, size, icm_profile) == size)
+ {
+ icm_profile_buffer[size] = 0;
+
+ TIFFSetField(tiffile, TIFFTAG_ICCPROFILE, size, icm_profile_buffer);
+ }
+ else
+ {
+ DBG(DBG_error, "Can not read ICM profile data\n");
+ }
+
+ free(icm_profile_buffer);
+ }
+ else
+ {
+ DBG(DBG_error, "Can not get enogh memory for ICM profile\n");
+ }
+
+
+ fclose(icm_profile);
+ }
+ else
+ {
+ DBG(DBG_error, "Can not embed ICM profile\n");
+ }
+}
+#endif
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
/* pages = 0 => single page tiff, page = 0 */
/* pages > 0 => page = [1 .. pages] */
-int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Image_info *image_info, int quality,
+int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, int quality, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function,
GtkProgressBar *progress_bar, int *cancel_save)
{
char *data;
@@ -3641,6 +4505,9 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im
int bytes;
struct tm *ptm;
time_t now;
+#ifdef HAVE_LIBLCMS
+ char *data_raw = NULL;
+#endif
DBG(DBG_proc, "xsane_save_tiff_page(%d/%d\n", page, pages);
@@ -3660,7 +4527,7 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im
}
- if (image_info->colors == 3)
+ if (image_info->channels == 3)
{
components = 3;
}
@@ -3686,6 +4553,25 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im
xsane_back_gtk_error(buf, TRUE);
return -1; /* error */
}
+
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL))
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = (char *) malloc(image_info->image_width * components * bytes);
+
+ if (!data_raw)
+ {
+ _TIFFfree(data);
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+ }
+#endif
+
TIFFSetField(tiffile, TIFFTAG_IMAGEWIDTH, image_info->image_width);
TIFFSetField(tiffile, TIFFTAG_IMAGELENGTH, image_info->image_height);
@@ -3717,7 +4603,7 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im
TIFFSetField(tiffile, TIFFTAG_JPEGQUALITY, quality);
}
- if (image_info->colors == 3)
+ if (image_info->channels == 3)
{
if (compression == COMPRESSION_JPEG)
{
@@ -3728,6 +4614,20 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im
{
TIFFSetField(tiffile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
}
+
+#ifdef HAVE_LIBLCMS
+ if (apply_ICM_profile)
+ {
+ if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE)
+ {
+ xsane_tiff_embed_scanner_icm_profile(tiffile, image_info->icm_profile);
+ }
+ else if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS)
+ {
+ xsane_tiff_embed_scanner_icm_profile(tiffile, preferences.working_color_space_icm_profile);
+ }
+ }
+#endif
}
else
{
@@ -3760,7 +4660,17 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im
gtk_main_iteration();
}
- fread(data, 1, w, imagefile);
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL))
+ {
+ fread(data_raw, 1, w, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 1, w, imagefile);
+ }
if (TIFFWriteScanline(tiffile, data, y, 0) != 1)
{
@@ -3784,6 +4694,13 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im
TIFFWriteDirectory(tiffile);
}
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
+
_TIFFfree(data);
return (*cancel_save);
}
@@ -3791,9 +4708,60 @@ int xsane_save_tiff_page(TIFF *tiffile, int page, int pages, FILE *imagefile, Im
/* ---------------------------------------------------------------------------------------------------------------------- */
+#if defined(PNG_iCCP_SUPPORTED)
+#ifdef HAVE_LIBLCMS
+static void xsane_png_embed_scanner_icm_profile(png_structp png_ptr, png_infop png_info_ptr, const char *icm_filename)
+{
+ FILE *icm_profile;
+ gchar *profile_buffer;
+ size_t size;
+
+ DBG(DBG_proc, "xsane_png_embed_scanner_icm_profile(%s)\n", icm_filename);
+ icm_profile = fopen(icm_filename, "rb");
+
+ if (icm_profile)
+ {
+ fseek(icm_profile, 0, SEEK_END);
+ size = ftell(icm_profile);
+ fseek(icm_profile, 0, SEEK_SET);
+
+ profile_buffer = malloc(size);
+
+ if (profile_buffer)
+ {
+ if (fread(profile_buffer, 1, size, icm_profile) == size)
+ {
+ png_set_iCCP(png_ptr, png_info_ptr, "ICC profile", 0, profile_buffer, size);
+ }
+ else
+ {
+ DBG(DBG_error, "can not read ICC profile data\n");
+ }
+
+ free(profile_buffer);
+ }
+ else
+ {
+ DBG(DBG_error, "can not allocate profile_buffer\n");
+ }
+
+ fclose(icm_profile);
+ }
+ else
+ {
+ DBG(DBG_error, "can not open ICM-profile\n");
+ }
+}
+#endif
+#endif
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
#ifdef HAVE_LIBPNG
#ifdef HAVE_LIBZ
-int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int compression, GtkProgressBar *progress_bar, int *cancel_save)
+int xsane_save_png(FILE *outfile, int compression, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
png_structp png_ptr;
png_infop png_info_ptr;
@@ -3803,6 +4771,9 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c
char buf[TEXTBUFSIZE];
int colortype, components, byte_width;
int y;
+#ifdef HAVE_LIBLCMS
+ unsigned char *data_raw = NULL;
+#endif
DBG(DBG_proc, "xsane_save_png\n");
@@ -3834,12 +4805,12 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c
byte_width = image_info->image_width;
- if (image_info->colors == 4) /* RGBA */
+ if (image_info->channels == 4) /* RGBA */
{
components = 4;
colortype = PNG_COLOR_TYPE_RGB_ALPHA;
}
- else if (image_info->colors == 3) /* RGB */
+ else if (image_info->channels == 3) /* RGB */
{
components = 3;
colortype = PNG_COLOR_TYPE_RGB;
@@ -3855,13 +4826,13 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c
png_set_IHDR(png_ptr, png_info_ptr, image_info->image_width, image_info->image_height, image_info->depth,
colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
- if (image_info->colors >=3)
+ if (image_info->channels >=3)
{
sig_bit.red = image_info->depth;
sig_bit.green = image_info->depth;
sig_bit.blue = image_info->depth;
- if (image_info->colors == 4)
+ if (image_info->channels == 4)
{
sig_bit.alpha = image_info->depth;
}
@@ -3884,6 +4855,23 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c
image_info->resolution_x * 100.0 / 2.54,
image_info->resolution_y * 100.0 / 2.54, PNG_RESOLUTION_METER);
#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+#ifdef HAVE_LIBLCMS
+ if (apply_ICM_profile)
+ {
+ if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE)
+ {
+ xsane_png_embed_scanner_icm_profile(png_ptr, png_info_ptr, image_info->icm_profile);
+ }
+ else if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS)
+ {
+ xsane_png_embed_scanner_icm_profile(png_ptr, png_info_ptr, preferences.working_color_space_icm_profile);
+ }
+ }
+#endif
+#endif
+
png_write_info(png_ptr, png_info_ptr);
png_set_shift(png_ptr, &sig_bit);
@@ -3897,6 +4885,25 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c
return -1; /* error */
}
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL))
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info->image_width * components);
+
+ if (!data_raw)
+ {
+ free(data);
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ png_destroy_write_struct(&png_ptr, (png_infopp) 0);
+ return -1; /* error */
+ }
+ }
+#endif
+
for (y = 0; y < image_info->image_height; y++)
{
gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height);
@@ -3905,7 +4912,17 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c
gtk_main_iteration();
}
- fread(data, components, byte_width, imagefile);
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL))
+ {
+ fread(data_raw, components, byte_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, components, byte_width, imagefile);
+ }
row_ptr = data;
png_write_rows(png_ptr, &row_ptr, 1); /* errors are caught by test sor setjmp(...) */
@@ -3916,6 +4933,12 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c
}
}
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
free(data);
png_write_end(png_ptr, png_info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp) 0);
@@ -3929,7 +4952,9 @@ int xsane_save_png(FILE *outfile, FILE *imagefile, Image_info *image_info, int c
#ifdef HAVE_LIBPNG
#ifdef HAVE_LIBZ
-int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, int compression, GtkProgressBar *progress_bar, int *cancel_save)
+int xsane_save_png_16(FILE *outfile, int compression, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile, int cms_function,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
png_structp png_ptr;
png_infop png_info_ptr;
@@ -3938,8 +4963,10 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in
unsigned char *data;
char buf[TEXTBUFSIZE];
int colortype, components;
- int x,y;
- guint16 val;
+ int y;
+#ifdef HAVE_LIBLCMS
+ unsigned char *data_raw = NULL;
+#endif
DBG(DBG_proc, "xsane_save_png16\n");
@@ -3969,12 +4996,12 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in
return -1; /* error */
}
- if (image_info->colors == 4) /* RGBA */
+ if (image_info->channels == 4) /* RGBA */
{
components = 4;
colortype = PNG_COLOR_TYPE_RGB_ALPHA;
}
- else if (image_info->colors == 3) /* RGB */
+ else if (image_info->channels == 3) /* RGB */
{
components = 3;
colortype = PNG_COLOR_TYPE_RGB;
@@ -3997,6 +5024,29 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in
sig_bit.gray = image_info->depth;
png_set_sBIT(png_ptr, png_info_ptr, &sig_bit);
+
+#if defined(PNG_pHYs_SUPPORTED)
+ png_set_pHYs(png_ptr, png_info_ptr,
+ image_info->resolution_x * 100.0 / 2.54,
+ image_info->resolution_y * 100.0 / 2.54, PNG_RESOLUTION_METER);
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+#ifdef HAVE_LIBLCMS
+ if (apply_ICM_profile)
+ {
+ if (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE)
+ {
+ xsane_png_embed_scanner_icm_profile(png_ptr, png_info_ptr, image_info->icm_profile);
+ }
+ else if (cms_function == XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS)
+ {
+ xsane_png_embed_scanner_icm_profile(png_ptr, png_info_ptr, preferences.working_color_space_icm_profile);
+ }
+ }
+#endif
+#endif
+
png_write_info(png_ptr, png_info_ptr);
png_set_shift(png_ptr, &sig_bit);
png_set_packing(png_ptr);
@@ -4011,6 +5061,25 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in
return -1; /* error */
}
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL))
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info->image_width * components * 2);
+
+ if (!data_raw)
+ {
+ free(data);
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ png_destroy_write_struct(&png_ptr, (png_infopp) 0);
+ return -1; /* error */
+ }
+ }
+#endif
+
for (y = 0; y < image_info->image_height; y++)
{
gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height);
@@ -4019,13 +5088,34 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in
gtk_main_iteration();
}
- for (x = 0; x < image_info->image_width * components; x++) /* this must be changed in dependance of endianess */
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && (hTransform != NULL))
+ {
+ fread(data_raw, components * 2, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
{
- 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+1] = val & 255;
+ fread(data, components * 2, image_info->image_width, imagefile);
}
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ /* we have to write data in network order (MSB first), so when we run on a low endian machine then we have to swap bytes */
+ {
+ int x;
+
+ for (x = 0; x < image_info->image_width * components; x++)
+ {
+ unsigned char help;
+
+ help = data[x*2+1];
+ data[x*2+0] = data[x*2+1];
+ data[x*2+1] = help;
+ }
+ }
+#endif /* LITTLE_ENDIAN */
+
row_ptr = data;
png_write_rows(png_ptr, &row_ptr, 1);
if (*cancel_save)
@@ -4034,6 +5124,12 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in
}
}
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
free(data);
png_write_end(png_ptr, png_info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp) 0);
@@ -4045,22 +5141,69 @@ int xsane_save_png_16(FILE *outfile, FILE *imagefile, Image_info *image_info, in
/* ---------------------------------------------------------------------------------------------------------------------- */
-static int xsane_save_pnm_16_ascii_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,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
int x,y;
- guint16 val;
+ guint16 *data;
int count = 0;
+#ifdef HAVE_LIBLCMS
+ guint16 *data_raw = NULL;
+#endif
DBG(DBG_proc, "xsane_save_pnm_16_ascii_gray\n");
*cancel_save = 0;
+ data = malloc(image_info->image_width * 2);
+
+ if (!data)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+
+#ifdef HAVE_LIBLCMS
+ if ((apply_ICM_profile) && (hTransform != NULL))
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info->image_width * 2);
+
+ if (!data_raw)
+ {
+ char buf[TEXTBUFSIZE];
+
+ free(data);
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+ }
+#endif
+
for (y = 0; y < image_info->image_height; y++)
{
+#ifdef HAVE_LIBLCMS
+ if ((apply_ICM_profile) && (hTransform != NULL))
+ {
+ fread(data_raw, 2, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 2, image_info->image_width, imagefile);
+ }
+
for (x = 0; x < image_info->image_width; x++)
{
- fread(&val, 2, 1, imagefile); /* get data in machine order */
- fprintf(outfile, "%d ", val);
+ fprintf(outfile, "%d ", data[x]);
if (++count >= 10)
{
@@ -4068,6 +5211,7 @@ static int xsane_save_pnm_16_ascii_gray(FILE *outfile, FILE *imagefile, Image_in
count = 0;
}
}
+
fprintf(outfile, "\n");
if (ferror(outfile))
@@ -4094,33 +5238,85 @@ static int xsane_save_pnm_16_ascii_gray(FILE *outfile, FILE *imagefile, Image_in
}
}
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
+ free(data);
+
return (*cancel_save);
}
/* ---------------------------------------------------------------------------------------------------------------------- */
-static int xsane_save_pnm_16_ascii_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,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
int x,y;
- guint16 val;
+ guint16 *data;
int count = 0;
+#ifdef HAVE_LIBLCMS
+ guint16 *data_raw = NULL;
+#endif
DBG(DBG_proc, "xsane_save_pnm_16_ascii_color\n");
*cancel_save = 0;
- for (y = 0; y < image_info->image_height; y++)
+
+ data = malloc(image_info->image_width * 6);
+
+ if (!data)
{
- for (x = 0; x < image_info->image_width; x++)
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+
+#ifdef HAVE_LIBLCMS
+ if ((apply_ICM_profile) && (hTransform != NULL))
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info->image_width * 6);
+
+ if (!data_raw)
{
- fread(&val, 2, 1, imagefile); /* get data in machine order */
- fprintf(outfile, "%d ", val);
+ char buf[TEXTBUFSIZE];
+
+ free(data);
- fread(&val, 2, 1, imagefile);
- fprintf(outfile, "%d ", val);
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+ }
+#endif
- fread(&val, 2, 1, imagefile);
- fprintf(outfile, "%d ", val);
+ for (y = 0; y < image_info->image_height; y++)
+ {
+#ifdef HAVE_LIBLCMS
+ if ((apply_ICM_profile) && (hTransform != NULL))
+ {
+ fread(data_raw, 6, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 6, image_info->image_width, imagefile);
+ }
+
+ for (x = 0; x < image_info->image_width; x++)
+ {
+ fprintf(outfile, "%d ", data[3*x+0]);
+ fprintf(outfile, "%d ", data[3*x+1]);
+ fprintf(outfile, "%d ", data[3*x+2]);
if (++count >= 3)
{
@@ -4155,27 +5351,82 @@ static int xsane_save_pnm_16_ascii_color(FILE *outfile, FILE *imagefile, Image_i
}
}
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
+ free(data);
+
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)
+static int xsane_save_pnm_16_binary_gray(FILE *outfile, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
int x,y;
- guint16 val;
+ guint16 *data;
+#ifdef HAVE_LIBLCMS
+ guint16 *data_raw = NULL;
+#endif
DBG(DBG_proc, "xsane_save_pnm_16_binary_gray\n");
*cancel_save = 0;
+ data = malloc(image_info->image_width * 2);
+
+ if (!data)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info->image_width * 2);
+
+ if (!data_raw)
+ {
+ char buf[TEXTBUFSIZE];
+
+ free(data);
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+ }
+#endif
+
for (y = 0; y < image_info->image_height; y++)
{
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ fread(data_raw, 2, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 2, image_info->image_width, imagefile);
+ }
+
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 */
+ fputc(data[3*x+0] / 256, outfile);
+ fputc(data[3*x+0] & 255, outfile);
}
gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height);
@@ -4201,38 +5452,289 @@ static int xsane_save_pnm_16_binary_gray(FILE *outfile, FILE *imagefile, Image_i
}
}
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
+ free(data);
+
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)
+static int xsane_save_pnm_16_binary_color(FILE *outfile, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
int x,y;
- guint16 val;
+ guint16 *data;
+#ifdef HAVE_LIBLCMS
+ guint16 *data_raw = NULL;
+#endif
DBG(DBG_proc, "xsane_save_pnm_16_binary_color\n");
*cancel_save = 0;
+ data = malloc(image_info->image_width * 6);
+
+ if (!data)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info->image_width * 6);
+
+ if (!data_raw)
+ {
+ char buf[TEXTBUFSIZE];
+
+ free(data);
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+ }
+#endif
+
for (y = 0; y < image_info->image_height; y++)
{
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ fread(data_raw, 6, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 6, image_info->image_width, imagefile);
+ }
+
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 */
+ fputc(data[3*x+0] / 256, outfile);
+ fputc(data[3*x+0] & 255, outfile);
+ fputc(data[3*x+1] / 256, outfile);
+ fputc(data[3*x+1] & 255, outfile);
+ fputc(data[3*x+2] / 256, outfile);
+ fputc(data[3*x+2] & 255, outfile);
+ }
+
+ gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height);
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+
+
+ if (ferror(outfile))
+ {
+ char buf[TEXTBUFSIZE];
+
+ 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;
+ }
+ }
+
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
+ free(data);
+
+ return (*cancel_save);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_save_pnm_8_gray(FILE *outfile, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile,
+ GtkProgressBar *progress_bar, int *cancel_save)
+{
+ int x,y;
+ guint8 *data;
+#ifdef HAVE_LIBLCMS
+ guint8 *data_raw = NULL;
+#endif
+
+ DBG(DBG_proc, "xsane_save_pnm_8_gray\n");
+
+ *cancel_save = 0;
+
+ data = malloc(image_info->image_width);
+
+ if (!data)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info->image_width);
+
+ if (!data_raw)
+ {
+ char buf[TEXTBUFSIZE];
- /* green */
- fread(&val, 2, 1, imagefile); /* get data in machine order */
- fputc(val / 256, outfile); /* MSB fist */
- fputc(val & 255, outfile); /* LSB */
+ free(data);
- /* blue */
- fread(&val, 2, 1, imagefile); /* get data in machine order */
- fputc(val / 256, outfile); /* MSB fist */
- fputc(val & 255, outfile); /* LSB */
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+ }
+#endif
+
+ for (y = 0; y < image_info->image_height; y++)
+ {
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ fread(data_raw, 1, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 1, image_info->image_width, imagefile);
+ }
+
+ for (x = 0; x < image_info->image_width; x++)
+ {
+ fputc(data[x], outfile);
+ }
+
+ gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height);
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+
+
+ if (ferror(outfile))
+ {
+ char buf[TEXTBUFSIZE];
+
+ 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;
+ }
+ }
+
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
+ free(data);
+
+ return (*cancel_save);
+}
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_save_pnm_8_color(FILE *outfile, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile,
+ GtkProgressBar *progress_bar, int *cancel_save)
+{
+ int x,y;
+ guint8 *data;
+#ifdef HAVE_LIBLCMS
+ guint8 *data_raw = NULL;
+#endif
+
+ DBG(DBG_proc, "xsane_save_pnm_8_color\n");
+
+ *cancel_save = 0;
+
+ data = malloc(image_info->image_width * 3);
+
+ if (!data)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info->image_width * 3);
+
+ if (!data_raw)
+ {
+ char buf[TEXTBUFSIZE];
+
+ free(data);
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+ }
+#endif
+
+ for (y = 0; y < image_info->image_height; y++)
+ {
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ fread(data_raw, 3, image_info->image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info->image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 3, image_info->image_width, imagefile);
+ }
+
+ for (x = 0; x < image_info->image_width; x++)
+ {
+ fputc(data[3*x+0], outfile);
+ fputc(data[3*x+1], outfile);
+ fputc(data[3*x+2], outfile);
}
gtk_progress_bar_update(progress_bar, (float) y / image_info->image_height);
@@ -4259,12 +5761,46 @@ static int xsane_save_pnm_16_binary_color(FILE *outfile, FILE *imagefile, Image_
}
}
+#ifdef HAVE_LIBLCMS
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
+ free(data);
+
+ return (*cancel_save);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_save_pnm_8(FILE *outfile, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile,
+ GtkProgressBar *progress_bar, int *cancel_save)
+{
+ DBG(DBG_proc, "xsane_save_pnm_8\n");
+
+ *cancel_save = 0;
+
+ xsane_write_pnm_header(outfile, image_info, preferences.save_pnm16_as_ascii);
+
+ if (image_info->channels > 1)
+ {
+ xsane_save_pnm_8_color(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save);
+ }
+ else
+ {
+ xsane_save_pnm_8_gray(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save);
+ }
+
return (*cancel_save);
}
/* ---------------------------------------------------------------------------------------------------------------------- */
-int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, GtkProgressBar *progress_bar, int *cancel_save)
+int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info,
+ cmsHTRANSFORM hTransform, int apply_ICM_profile,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
DBG(DBG_proc, "xsane_save_pnm_16\n");
@@ -4272,26 +5808,26 @@ int xsane_save_pnm_16(FILE *outfile, FILE *imagefile, Image_info *image_info, Gt
xsane_write_pnm_header(outfile, image_info, preferences.save_pnm16_as_ascii);
- if (image_info->colors > 1)
+ if (image_info->channels > 1)
{
if (preferences.save_pnm16_as_ascii)
{
- xsane_save_pnm_16_ascii_color(outfile, imagefile, image_info, progress_bar, cancel_save);
+ xsane_save_pnm_16_ascii_color(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save);
}
else
{
- xsane_save_pnm_16_binary_color(outfile, imagefile, image_info, progress_bar, cancel_save);
+ xsane_save_pnm_16_binary_color(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save);
}
}
else
{
if (preferences.save_pnm16_as_ascii)
{
- xsane_save_pnm_16_ascii_gray(outfile, imagefile, image_info, progress_bar, cancel_save);
+ xsane_save_pnm_16_ascii_gray(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save);
}
else
{
- xsane_save_pnm_16_binary_gray(outfile, imagefile, image_info, progress_bar, cancel_save);
+ xsane_save_pnm_16_binary_gray(outfile, imagefile, image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save);
}
}
@@ -4299,7 +5835,6 @@ 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 *output_filename, char *input_filename, GtkProgressBar *progress_bar, int *cancel_save)
@@ -4524,14 +6059,17 @@ int xsane_save_image_as_text(char *output_filename, char *input_filename, GtkPro
/* ---------------------------------------------------------------------------------------------------------------------- */
/* 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)
+int xsane_save_image_as(char *output_filename, char *input_filename, int output_format,
+ int apply_ICM_profile, int cms_function, int cms_intent, int cms_bpc,
+ GtkProgressBar *progress_bar, int *cancel_save)
{
FILE *outfile;
FILE *infile;
char buf[TEXTBUFSIZE];
Image_info image_info;
- char lineart_filename[PATH_MAX];
+ char temporary_filename[PATH_MAX];
int remove_input_file = FALSE;
+ cmsHTRANSFORM hTransform = NULL;
DBG(DBG_proc, "xsane_save_image_as(output_file=%s, input_file=%s, type=%d)\n", output_filename, input_filename, output_format);
@@ -4553,7 +6091,7 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_
{
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);
+ xsane_back_gtk_make_path(sizeof(temporary_filename), temporary_filename, 0, 0, "xsane-conversion-", xsane.dev_name, ".pbm", XSANE_PATH_TMP);
snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_PACKING_DATA, output_filename);
@@ -4565,9 +6103,9 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_
gtk_main_iteration();
}
- xsane_save_image_as_lineart(lineart_filename, input_filename, progress_bar, cancel_save);
+ xsane_save_image_as_lineart(temporary_filename, input_filename, progress_bar, cancel_save);
- input_filename = lineart_filename;
+ input_filename = temporary_filename;
remove_input_file = TRUE;
infile = fopen(input_filename, "rb"); /* read binary (b for win32) */
@@ -4583,8 +6121,23 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_
xsane_read_pnm_header(infile, &image_info);
}
- snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_SAVING_DATA, output_filename);
+#ifdef HAVE_LIBLCMS
+ if (apply_ICM_profile && ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) || ((output_format == XSANE_PNM) || (output_format == XSANE_PNM16))))
+ {
+ hTransform = xsane_create_cms_transform(&image_info, cms_function, cms_intent, cms_bpc);
+ }
+#endif
+
+ if (1)
+ {
+ snprintf(buf, sizeof(buf), "%s: %s", PROGRESS_SAVING_DATA, output_filename);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), "%s", PROGRESS_SAVING_DATA);
+ }
+ gtk_progress_bar_set_ellipsize(GTK_PROGRESS_BAR(progress_bar), PANGO_ELLIPSIZE_START); /* this is new API, can be removed for old GTK versions */
gtk_progress_set_format_string(GTK_PROGRESS(progress_bar), buf);
gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), 0.0);
@@ -4614,7 +6167,7 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_
return -1; /* error */
}
- xsane_save_tiff_page(tiffile, 0, 0, infile, &image_info, preferences.jpeg_quality, progress_bar, cancel_save);
+ xsane_save_tiff_page(tiffile, 0, 0, preferences.jpeg_quality, infile, &image_info, hTransform, apply_ICM_profile, cms_function, progress_bar, cancel_save);
TIFFClose(tiffile);
}
@@ -4641,13 +6194,13 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_
}
else
{
- xsane_copy_file(outfile, infile, progress_bar, cancel_save);
+ xsane_save_pnm_8(outfile, infile, &image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save);
}
break;
#ifdef HAVE_LIBJPEG
case XSANE_JPEG:
- xsane_save_jpeg(outfile, infile, &image_info, preferences.jpeg_quality, progress_bar, cancel_save);
+ xsane_save_jpeg(outfile, preferences.jpeg_quality, infile, &image_info, hTransform, apply_ICM_profile, cms_function, progress_bar, cancel_save);
break; /* switch format == XSANE_JPEG */
#endif
@@ -4656,18 +6209,18 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_
case XSANE_PNG:
if (image_info.depth <= 8)
{
- xsane_save_png(outfile, infile, &image_info, preferences.png_compression, progress_bar, cancel_save);
+ xsane_save_png(outfile, preferences.png_compression, infile, &image_info, hTransform, apply_ICM_profile, cms_function, progress_bar, cancel_save);
}
else
{
- xsane_save_png_16(outfile, infile, &image_info, preferences.png_compression, progress_bar, cancel_save);
+ xsane_save_png_16(outfile, preferences.png_compression, infile, &image_info, hTransform, apply_ICM_profile, cms_function, progress_bar, cancel_save);
}
break; /* switch format == XSANE_PNG */
#endif
#endif
case XSANE_PNM16:
- xsane_save_pnm_16(outfile, infile, &image_info, progress_bar, cancel_save);
+ xsane_save_pnm_16(outfile, infile, &image_info, hTransform, apply_ICM_profile, progress_bar, cancel_save);
break; /* switch fomat == XSANE_PNM16 */
case XSANE_PS: /* save postscript, use original size */
@@ -4685,7 +6238,11 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_
(int) imagewidth, /* paper_width */
(int) imageheight, /* paper_height */
0 /* portrait top left */,
- preferences.save_ps_flatdecoded,
+ preferences.save_ps_flatedecoded,
+ hTransform, apply_ICM_profile,
+ (cms_function == XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE), image_info.icm_profile,
+ 0, NULL, 0, /* no CRD */
+ 0 /* intent */,
progress_bar,
cancel_save);
}
@@ -4706,7 +6263,8 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_
(int) imagewidth, /* paper_width */
(int) imageheight, /* paper_height */
0 /* portrait top left */,
- preferences.save_pdf_flatdecoded,
+ preferences.save_pdf_flatedecoded,
+ hTransform, apply_ICM_profile, cms_function,
progress_bar,
cancel_save);
}
@@ -4771,6 +6329,13 @@ int xsane_save_image_as(char *output_filename, char *input_filename, int output_
fclose (infile);
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ cmsDeleteTransform(hTransform);
+ }
+#endif
+
if (remove_input_file)
{
remove(input_filename); /* remove lineart pbm file */
@@ -5098,8 +6663,9 @@ void null_print_func(gchar *msg)
}
/* ---------------------------------------------------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------------------------------------------------------- */
-int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, int *cancel_save)
+int xsane_transfer_to_gimp(char *input_filename, int apply_ICM_profile, int cms_function, GtkProgressBar *progress_bar, int *cancel_save)
{
int remaining;
size_t tile_size;
@@ -5114,6 +6680,13 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i
int i, x, y;
Image_info image_info;
FILE *imagefile;
+ int bytes;
+ unsigned char *data = NULL;
+ guint16 *data16 = NULL;
+#ifdef HAVE_LIBLCMS
+ unsigned char *data_raw = NULL;
+ cmsHTRANSFORM hTransform = NULL;
+#endif
DBG(DBG_info, "xsane_transer_to_gimp\n");
@@ -5131,18 +6704,64 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i
xsane_read_pnm_header(imagefile, &image_info);
+ if (image_info.depth == 16)
+ {
+ bytes = 2;
+ }
+ else
+ {
+ bytes = 1;
+ }
+
+ data = malloc(image_info.image_width * 3 * bytes);
+ data16 = (guint16 *) data;
+
+ if (!data)
+ {
+ char buf[TEXTBUFSIZE];
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (image_info.depth != 1))
+ {
+ hTransform = xsane_create_cms_transform(&image_info, cms_function, preferences.cms_intent, preferences.cms_bpc);
+ }
+
+ if (hTransform != NULL)
+ {
+ DBG(DBG_info, "Doing CMS color conversion\n");
+
+ data_raw = malloc(image_info.image_width * 3 * bytes);
+
+ if (!data_raw)
+ {
+ char buf[TEXTBUFSIZE];
+
+ free(data);
+
+ snprintf(buf, sizeof(buf), "%s %s", ERR_DURING_SAVE, ERR_NO_MEM);
+ xsane_back_gtk_error(buf, TRUE);
+ return -1; /* error */
+ }
+ }
+#endif
+
x = 0;
y = 0;
tile_offset = 0;
tile_size = image_info.image_width * gimp_tile_height();
- if (image_info.colors == 3) /* RGB */
+ if (image_info.channels == 3) /* RGB */
{
tile_size *= 3; /* 24 bits/pixel RGB */
image_type = GIMP_RGB;
drawable_type = GIMP_RGB_IMAGE;
}
- else if (image_info.colors == 4) /* RGBA */
+ else if (image_info.channels == 4) /* RGBA */
{
tile_size *= 4; /* 32 bits/pixel RGBA */
image_type = GIMP_RGB;
@@ -5151,6 +6770,55 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i
/* colors == 0/1 is predefined */
image_ID = gimp_image_new(image_info.image_width, image_info.image_height, image_type);
+
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_CONVERT_TO_SRGB) && apply_ICM_profile) /* embed profile */
+ {
+ GimpParasite *parasite;
+ FILE *icm_profile;
+ guchar *profile_buffer;
+ gint32 size;
+
+ DBG(DBG_error, "Opening ICM profile %s\n", image_info.icm_profile);
+ icm_profile = fopen(image_info.icm_profile, "rb");
+
+ if (icm_profile)
+ {
+ fseek(icm_profile, 0, SEEK_END);
+ size = ftell(icm_profile);
+ fseek(icm_profile, 0, SEEK_SET);
+
+ profile_buffer = malloc(size);
+
+ if (profile_buffer)
+ {
+ if (fread(profile_buffer, 1, size, icm_profile) == size)
+ {
+ parasite = gimp_parasite_new("icc-profile", 0, size, profile_buffer);
+ gimp_image_parasite_attach(image_ID, parasite);
+ gimp_parasite_free(parasite);
+ }
+ else
+ {
+ DBG(DBG_error, "can not read profile data\n");
+ }
+
+ free(profile_buffer);
+ }
+ else
+ {
+ DBG(DBG_error, "can not allocate profile_buffer\n");
+ }
+
+ fclose(icm_profile);
+ }
+ else
+ {
+ DBG(DBG_error, "can not open ICM-profile\n");
+ }
+ }
+#endif
+
/* the following is supported since gimp-1.1.? */
#ifdef GIMP_HAVE_RESOLUTION_INFO
@@ -5168,7 +6836,7 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i
tile = g_new(guchar, tile_size);
- if (image_info.colors == 1) /* gray */
+ if (image_info.channels == 1) /* gray */
{
switch (image_info.depth)
{
@@ -5217,30 +6885,79 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i
break; /* leave switch depth 1 */
case 8: /* 8 bit gray */
- case 16: /* 16 bit gray already has been reduced to 8 bit */
- for (i = 0; i < image_info.image_width * image_info.image_height; ++i)
+ for (y = 1; y <= image_info.image_height; y++)
{
- tile[tile_offset++] = fgetc(imagefile);
- x++;
+ int tile_height = gimp_tile_height();
- if (x >= image_info.image_width)
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (hTransform != NULL))
{
- int tile_height = gimp_tile_height();
+ fread(data_raw, 1, image_info.image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info.image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 1, image_info.image_width, imagefile);
+ }
- x = 0;
- y++;
+ for (x = 0; x < image_info.image_width; x++)
+ {
+ tile[tile_offset++] = data[x];
+ }
- if (y % tile_height == 0)
- {
- gimp_pixel_rgn_set_rect(&region, tile, 0, y - tile_height, image_info.image_width, tile_height);
- tile_offset = 0;
- }
+ if (y % tile_height == 0)
+ {
+ 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 / image_info.image_height); /* update progress bar */
- while (gtk_events_pending())
- {
- gtk_main_iteration();
- }
+ gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+
+ if (*cancel_save)
+ {
+ break;
+ }
+ }
+ break; /* case 8 */
+
+
+ case 16: /* 16 bit gray has to be reduced to 8 bit */
+ for (y = 1; y <= image_info.image_height; y++)
+ {
+ int tile_height = gimp_tile_height();
+
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (hTransform != NULL))
+ {
+ fread(data_raw, 2, image_info.image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info.image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 2, image_info.image_width, imagefile);
+ }
+
+ for (x = 0; x < image_info.image_width; x++)
+ {
+ tile[tile_offset++] = data16[x]/256;
+ }
+
+ if (y % tile_height == 0)
+ {
+ 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 / image_info.image_height); /* update progress bar */
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
}
if (*cancel_save)
@@ -5248,44 +6965,51 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i
break;
}
}
- break; /* leave switch depth */
+ break; /* case 16 */
default: /* bad depth */
break; /* default */
}
}
- else if (image_info.colors == 3) /* RGB */
+ else if (image_info.channels == 3) /* RGB */
{
switch (image_info.depth)
{
case 8: /* 8 bit RGB */
- case 16: /* 16 bit RGB already has been reduced to 8 bit */
- for (i = 0; i < image_info.image_width * image_info.image_height*3; ++i)
+
+ for (y = 1; y <= image_info.image_height; y++)
{
- tile[tile_offset++] = fgetc(imagefile);
- if (tile_offset % 3 == 0)
- {
- x++;
+ int tile_height = gimp_tile_height();
- if (x >= image_info.image_width)
- {
- int tile_height = gimp_tile_height();
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (hTransform != NULL))
+ {
+ fread(data_raw, 3, image_info.image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info.image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 3, image_info.image_width, imagefile);
+ }
- x = 0;
- y++;
+ for (x = 0; x < image_info.image_width; x++)
+ {
+ tile[tile_offset++] = data[3*x+0];
+ tile[tile_offset++] = data[3*x+1];
+ tile[tile_offset++] = data[3*x+2];
+ }
- if (y % tile_height == 0)
- {
- gimp_pixel_rgn_set_rect(&region, tile, 0, y - tile_height, image_info.image_width, tile_height);
- tile_offset = 0;
- }
+ if (y % tile_height == 0)
+ {
+ 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 / image_info.image_height); /* update progress bar */
- while (gtk_events_pending())
- {
- gtk_main_iteration();
- }
- }
+ gtk_progress_bar_update(progress_bar, (float) y / image_info.image_height); /* update progress bar */
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
}
if (*cancel_save)
@@ -5295,12 +7019,57 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i
}
break; /* case 8 */
+
+ case 16: /* 16 bit RGB has to be reduced to 8 bit */
+
+ for (y = 1; y <= image_info.image_height; y++)
+ {
+ int tile_height = gimp_tile_height();
+
+#ifdef HAVE_LIBLCMS
+ if ((cms_function != XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE) && apply_ICM_profile && (hTransform != NULL))
+ {
+ fread(data_raw, 6, image_info.image_width, imagefile);
+ cmsDoTransform(hTransform, data_raw, data, image_info.image_width);
+ }
+ else
+#endif
+ {
+ fread(data, 6, image_info.image_width, imagefile);
+ }
+
+ for (x = 0; x < image_info.image_width; x++)
+ {
+ tile[tile_offset++] = data16[3*x+0]/256;
+ tile[tile_offset++] = data16[3*x+1]/256;
+ tile[tile_offset++] = data16[3*x+2]/256;
+ }
+
+ if (y % tile_height == 0)
+ {
+ 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 / image_info.image_height); /* update progress bar */
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+
+ if (*cancel_save)
+ {
+ break;
+ }
+ }
+ break; /* case 16 */
+
default: /* bad depth */
break; /* default */
}
}
#ifdef SUPPORT_RGBA
- else if (image_info.colors == 4) /* RGBA */
+ else if (image_info.channels == 4) /* RGBA */
{
int i;
@@ -5370,6 +7139,19 @@ int xsane_transfer_to_gimp(char *input_filename, GtkProgressBar *progress_bar, i
fclose(imagefile);
+#ifdef HAVE_LIBLCMS
+ if (hTransform != NULL)
+ {
+ cmsDeleteTransform(hTransform);
+ }
+
+ if (data_raw)
+ {
+ free(data_raw);
+ }
+#endif
+ free(data);
+
return 0;
}
#endif /* HAVE_ANY_GIMP */
@@ -5414,7 +7196,7 @@ static void write_3chars_as_base64(unsigned char c1, unsigned char c2, unsigned
/* ---------------------------------------------------------------------------------------------------------------------- */
-void write_string_base64(int fd_socket, unsigned char *string, int len)
+void write_string_base64(int fd_socket, char *string, int len)
{
int i;
int pad;
@@ -5422,9 +7204,9 @@ void write_string_base64(int fd_socket, unsigned char *string, int len)
for (i = 0; i < len; i+=3)
{
- c1 = string[i];
- c2 = string[i+1];
- c3 = string[i+2];
+ c1 = (unsigned char) string[i];
+ c2 = (unsigned char) string[i+1];
+ c3 = (unsigned char) string[i+2];
pad = i - len + 3;
@@ -5477,7 +7259,7 @@ void write_base64(int fd_socket, FILE *infile)
pos += 4;
if (pos > 71)
{
- write(fd_socket, "\n", 1);
+ write(fd_socket, "\r\n", 2);
pos = 0;
}
@@ -5492,7 +7274,7 @@ void write_base64(int fd_socket, FILE *infile)
if (pos)
{
- write(fd_socket, "\n", 1);
+ write(fd_socket, "\r\n", 2);
}
xsane.email_progress_val = 1.0;
@@ -5505,33 +7287,33 @@ void write_email_header(int fd_socket, char *from, char *reply_to, char *to, cha
{
char buf[1024];
- snprintf(buf, sizeof(buf), "From: %s\n", from);
+ snprintf(buf, sizeof(buf), "From: %s\r\n", from);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Reply-To: %s\n", reply_to);
+ snprintf(buf, sizeof(buf), "Reply-To: %s\r\n", reply_to);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "To: %s\n", to);
+ snprintf(buf, sizeof(buf), "To: %s\r\n", to);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Subject: %s\n", subject);
+ snprintf(buf, sizeof(buf), "Subject: %s\r\n", subject);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "MIME-Version: 1.0\n");
+ snprintf(buf, sizeof(buf), "MIME-Version: 1.0\r\n");
write(fd_socket, buf, strlen(buf));
if (related) /* related means that we need a special link in the html part to display the image */
{
- snprintf(buf, sizeof(buf), "Content-Type: multipart/related;\n");
+ snprintf(buf, sizeof(buf), "Content-Type: multipart/related;\r\n");
write(fd_socket, buf, strlen(buf));
}
else
{
- snprintf(buf, sizeof(buf), "Content-Type: multipart/mixed;\n");
+ snprintf(buf, sizeof(buf), "Content-Type: multipart/mixed;\r\n");
write(fd_socket, buf, strlen(buf));
}
- snprintf(buf, sizeof(buf), " boundary=\"%s\"\n\n", boundary);
+ snprintf(buf, sizeof(buf), " boundary=\"%s\"\r\n\r\n", boundary);
write(fd_socket, buf, strlen(buf));
}
@@ -5541,7 +7323,7 @@ void write_email_footer(int fd_socket, char *boundary)
{
char buf[1024];
- snprintf(buf, sizeof(buf), "--%s--\n", boundary);
+ snprintf(buf, sizeof(buf), "--%s--\r\n", boundary);
write(fd_socket, buf, strlen(buf));
}
@@ -5551,16 +7333,16 @@ void write_email_mime_ascii(int fd_socket, char *boundary)
{
char buf[1024];
- snprintf(buf, sizeof(buf), "--%s\n", boundary);
+ snprintf(buf, sizeof(buf), "--%s\r\n", boundary);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Content-Type: text/plain;\n");
+ snprintf(buf, sizeof(buf), "Content-Type: text/plain;\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), " charset=\"iso-8859-1\"\n");
+ snprintf(buf, sizeof(buf), " charset=\"iso-8859-1\"\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 8bit\n\n");
+ snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 8bit\r\n\r\n");
write(fd_socket, buf, strlen(buf));
}
@@ -5570,22 +7352,22 @@ void write_email_mime_html(int fd_socket, char *boundary)
{
char buf[1024];
- snprintf(buf, sizeof(buf), "--%s\n", boundary);
+ snprintf(buf, sizeof(buf), "--%s\r\n", boundary);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Content-Type: text/html;\n");
+ snprintf(buf, sizeof(buf), "Content-Type: text/html;\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), " charset=\"us-ascii\"\n");
+ snprintf(buf, sizeof(buf), " charset=\"us-ascii\"\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 7bit\n\n");
+ snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: 7bit\r\n\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">\n");
+ snprintf(buf, sizeof(buf), "<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "<html>\n");
+ snprintf(buf, sizeof(buf), "<html>\r\n");
write(fd_socket, buf, strlen(buf));
}
@@ -5595,28 +7377,28 @@ void write_email_attach_image(int fd_socket, char *boundary, char *content_id, c
{
char buf[1024];
- snprintf(buf, sizeof(buf), "--%s\n", boundary);
+ snprintf(buf, sizeof(buf), "--%s\r\n", boundary);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Content-Type: %s\n", content_type);
+ snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", content_type);
write(fd_socket, buf, strlen(buf));
if (content_id)
{
- snprintf(buf, sizeof(buf), "Content-ID: <%s>\n", content_id);
+ snprintf(buf, sizeof(buf), "Content-ID: <%s>\r\n", content_id);
write(fd_socket, buf, strlen(buf));
}
- snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\n");
+ snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Content-Disposition: inline;\n");
+ snprintf(buf, sizeof(buf), "Content-Disposition: inline;\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), " filename=\"%s\"\n", filename);
+ snprintf(buf, sizeof(buf), " filename=\"%s\"\r\n", filename);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "\n");
+ snprintf(buf, sizeof(buf), "\r\n");
write(fd_socket, buf, strlen(buf));
write_base64(fd_socket, infile);
@@ -5628,25 +7410,25 @@ void write_email_attach_file(int fd_socket, char *boundary, FILE *infile, char *
{
char buf[1024];
- snprintf(buf, sizeof(buf), "--%s\n", boundary);
+ snprintf(buf, sizeof(buf), "--%s\r\n", boundary);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Content-Type: application/octet-stream\n");
+ snprintf(buf, sizeof(buf), "Content-Type: application/octet-stream\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), " name=\"%s\"\n", filename);
+ snprintf(buf, sizeof(buf), " name=\"%s\"\r\n", filename);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\n");
+ snprintf(buf, sizeof(buf), "Content-Transfer-Encoding: base64\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "Content-Disposition: attachment;\n");
+ snprintf(buf, sizeof(buf), "Content-Disposition: attachment;\r\n");
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), " filename=\"%s\"\n", filename);
+ snprintf(buf, sizeof(buf), " filename=\"%s\"\r\n", filename);
write(fd_socket, buf, strlen(buf));
- snprintf(buf, sizeof(buf), "\n");
+ snprintf(buf, sizeof(buf), "\r\n");
write(fd_socket, buf, strlen(buf));
write_base64(fd_socket, infile);