/*
* Gutenprint based raster filter for the Common UNIX Printing System.
*
* Copyright 1993-2008 by Mike Sweet.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Contents:
*
* main() - Main entry and processing of driver.
* cups_writefunc() - Write data to a file...
* cancel_job() - Cancel the current job...
* Image_get_appname() - Get the application we are running.
* Image_get_row() - Get one row of the image.
* Image_height() - Return the height of an image.
* Image_init() - Initialize an image.
* Image_conclude() - Close the progress display.
* Image_width() - Return the width of an image.
*/
/*
* Include necessary headers...
*/
#if 0
#define ENABLE_CUPS_LOAD_SAVE_OPTIONS
#endif
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_LIMITS_H
#include
#endif
#include "i18n.h"
#include
/* Solaris with gcc has problems because gcc's limits.h doesn't #define */
/* this */
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
/*
* Structure for page raster data...
*/
#if (CUPS_VERSION_MAJOR > 1 || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1))
#define CUPS_HEADER_T cups_page_header2_t
#define CUPS_READ_HEADER cupsRasterReadHeader2
#else
#define CUPS_HEADER_T cups_page_header_t
#define CUPS_READ_HEADER cupsRasterReadHeader
#endif
typedef struct
{
cups_raster_t *ras; /* Raster stream to read from */
int page; /* Current page number */
int row; /* Current row number */
int left;
int right;
int bottom;
int top;
int width;
int height;
int left_trim;
int right_trim;
int top_trim;
int bottom_trim;
int adjusted_width;
int adjusted_height;
stp_dimension_t d_left;
stp_dimension_t d_right;
stp_dimension_t d_bottom;
stp_dimension_t d_top;
stp_dimension_t d_width;
stp_dimension_t d_height;
stp_dimension_t d_left_trim;
stp_dimension_t d_right_trim;
stp_dimension_t d_bottom_trim;
stp_dimension_t d_top_trim;
int last_percent;
int shrink_to_fit;
CUPS_HEADER_T header; /* Page header from file */
} cups_image_t;
static void cups_writefunc(void *file, const char *buf, size_t bytes);
static void cups_errfunc(void *file, const char *buf, size_t bytes);
static void cups_dbgfunc(void *file, const char *buf, size_t bytes);
static void cancel_job(int sig);
static const char *Image_get_appname(stp_image_t *image);
static stp_image_status_t Image_get_row(stp_image_t *image,
unsigned char *data,
size_t byte_limit, int row);
static int Image_height(stp_image_t *image);
static int Image_width(stp_image_t *image);
static void Image_conclude(stp_image_t *image);
static void Image_init(stp_image_t *image);
static stp_image_t theImage =
{
Image_init,
NULL, /* reset */
Image_width,
Image_height,
Image_get_row,
Image_get_appname,
Image_conclude,
NULL
};
static volatile stp_image_status_t Image_status = STP_IMAGE_STATUS_OK;
static double total_bytes_printed = 0;
static int print_messages_as_errors = 0;
static int suppress_messages = 0;
static int suppress_verbose_messages = 0;
static const stp_string_list_t *po = NULL;
#ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
static const char *save_file_name = NULL;
static const char *load_file_name = NULL;
#endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
static inline void *
cast_safe(const void *ptr)
{
return (void *)ptr;
}
#pragma GCC diagnostic pop
static void
set_string_parameter(stp_vars_t *v, const char *name, const char *val)
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set special string %s to %s\n", name, val);
stp_set_string_parameter(v, name, val);
}
static void
set_special_parameter(stp_vars_t *v, const char *name, int choice)
{
stp_parameter_t desc;
stp_describe_parameter(v, name, &desc);
if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
{
#if 0
if (stp_check_string_parameter(v, name, STP_PARAMETER_ACTIVE))
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Not overriding special parameter %s (%s)\n",
name, stp_get_string_parameter(v, name));
}
else
#endif
if (choice < 0)
{
stp_clear_string_parameter(v, name);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Clear special parameter %s\n",
name);
}
else if (choice >= stp_string_list_count(desc.bounds.str))
{
if (! suppress_messages)
stp_i18n_printf(po, _("ERROR: Unable to set Gutenprint option %s "
"(%d > %d)!\n"), name, choice,
stp_string_list_count(desc.bounds.str));
}
else
{
stp_set_string_parameter
(v, name, stp_string_list_param(desc.bounds.str, choice)->name);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set special parameter %s to choice %d (%s)\n",
name, choice,
stp_string_list_param(desc.bounds.str, choice)->name);
}
}
else
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Unable to set special %s: not a string\n",
name);
}
stp_parameter_description_destroy(&desc);
}
static void
print_debug_block(const stp_vars_t *v, const cups_image_t *cups)
{
fprintf(stderr, "DEBUG: Gutenprint: Page data:\n");
fprintf(stderr, "DEBUG: Gutenprint: MediaClass = \"%s\"\n", cups->header.MediaClass);
fprintf(stderr, "DEBUG: Gutenprint: MediaColor = \"%s\"\n", cups->header.MediaColor);
fprintf(stderr, "DEBUG: Gutenprint: MediaType = \"%s\"\n", cups->header.MediaType);
fprintf(stderr, "DEBUG: Gutenprint: OutputType = \"%s\"\n", cups->header.OutputType);
fprintf(stderr, "DEBUG: Gutenprint: AdvanceDistance = %d\n", cups->header.AdvanceDistance);
fprintf(stderr, "DEBUG: Gutenprint: AdvanceMedia = %d\n", cups->header.AdvanceMedia);
fprintf(stderr, "DEBUG: Gutenprint: Collate = %d\n", cups->header.Collate);
fprintf(stderr, "DEBUG: Gutenprint: CutMedia = %d\n", cups->header.CutMedia);
fprintf(stderr, "DEBUG: Gutenprint: Duplex = %d\n", cups->header.Duplex);
fprintf(stderr, "DEBUG: Gutenprint: HWResolution = [ %d %d ]\n", cups->header.HWResolution[0],
cups->header.HWResolution[1]);
fprintf(stderr, "DEBUG: Gutenprint: ImagingBoundingBox = [ %d %d %d %d ]\n",
cups->header.ImagingBoundingBox[0], cups->header.ImagingBoundingBox[1],
cups->header.ImagingBoundingBox[2], cups->header.ImagingBoundingBox[3]);
fprintf(stderr, "DEBUG: Gutenprint: InsertSheet = %d\n", cups->header.InsertSheet);
fprintf(stderr, "DEBUG: Gutenprint: Jog = %d\n", cups->header.Jog);
fprintf(stderr, "DEBUG: Gutenprint: LeadingEdge = %d\n", cups->header.LeadingEdge);
fprintf(stderr, "DEBUG: Gutenprint: Margins = [ %d %d ]\n", cups->header.Margins[0],
cups->header.Margins[1]);
fprintf(stderr, "DEBUG: Gutenprint: ManualFeed = %d\n", cups->header.ManualFeed);
fprintf(stderr, "DEBUG: Gutenprint: MediaPosition = %d\n", cups->header.MediaPosition);
fprintf(stderr, "DEBUG: Gutenprint: MediaWeight = %d\n", cups->header.MediaWeight);
fprintf(stderr, "DEBUG: Gutenprint: MirrorPrint = %d\n", cups->header.MirrorPrint);
fprintf(stderr, "DEBUG: Gutenprint: NegativePrint = %d\n", cups->header.NegativePrint);
fprintf(stderr, "DEBUG: Gutenprint: NumCopies = %d\n", cups->header.NumCopies);
fprintf(stderr, "DEBUG: Gutenprint: Orientation = %d\n", cups->header.Orientation);
fprintf(stderr, "DEBUG: Gutenprint: OutputFaceUp = %d\n", cups->header.OutputFaceUp);
fprintf(stderr, "DEBUG: Gutenprint: PageSize = [ %d %d ]\n", cups->header.PageSize[0],
cups->header.PageSize[1]);
fprintf(stderr, "DEBUG: Gutenprint: Separations = %d\n", cups->header.Separations);
fprintf(stderr, "DEBUG: Gutenprint: TraySwitch = %d\n", cups->header.TraySwitch);
fprintf(stderr, "DEBUG: Gutenprint: Tumble = %d\n", cups->header.Tumble);
fprintf(stderr, "DEBUG: Gutenprint: cupsWidth = %d\n", cups->header.cupsWidth);
fprintf(stderr, "DEBUG: Gutenprint: cupsHeight = %d\n", cups->header.cupsHeight);
fprintf(stderr, "DEBUG: Gutenprint: cups->width = %d\n", cups->width);
fprintf(stderr, "DEBUG: Gutenprint: cups->height = %d\n", cups->height);
fprintf(stderr, "DEBUG: Gutenprint: cups->adjusted_width = %d\n", cups->adjusted_width);
fprintf(stderr, "DEBUG: Gutenprint: cups->adjusted_height = %d\n", cups->adjusted_height);
fprintf(stderr, "DEBUG: Gutenprint: cupsMediaType = %d\n", cups->header.cupsMediaType);
fprintf(stderr, "DEBUG: Gutenprint: cupsBitsPerColor = %d\n", cups->header.cupsBitsPerColor);
fprintf(stderr, "DEBUG: Gutenprint: cupsBitsPerPixel = %d\n", cups->header.cupsBitsPerPixel);
fprintf(stderr, "DEBUG: Gutenprint: cupsBytesPerLine = %d\n", cups->header.cupsBytesPerLine);
fprintf(stderr, "DEBUG: Gutenprint: cupsColorOrder = %d\n", cups->header.cupsColorOrder);
fprintf(stderr, "DEBUG: Gutenprint: cupsColorSpace = %d\n", cups->header.cupsColorSpace);
fprintf(stderr, "DEBUG: Gutenprint: cupsCompression = %d\n", cups->header.cupsCompression);
fprintf(stderr, "DEBUG: Gutenprint: cupsRowCount = %d\n", cups->header.cupsRowCount);
fprintf(stderr, "DEBUG: Gutenprint: cupsRowFeed = %d\n", cups->header.cupsRowFeed);
fprintf(stderr, "DEBUG: Gutenprint: cupsRowStep = %d\n", cups->header.cupsRowStep);
fprintf(stderr, "DEBUG: Gutenprint: shrink page to fit %d\n", cups->shrink_to_fit);
stp_vars_print_error(v, "DEBUG");
fprintf(stderr, "DEBUG: Gutenprint: End page data\n");
}
static int
printer_supports_bw(const stp_vars_t *v)
{
stp_parameter_t desc;
int status = 0;
stp_describe_parameter(v, "PrintingMode", &desc);
if (stp_string_list_is_present(desc.bounds.str, "BW"))
status = 1;
stp_parameter_description_destroy(&desc);
return status;
}
static void
validate_options(stp_vars_t *v, cups_image_t *cups)
{
stp_parameter_list_t params = stp_get_parameter_list(v);
int nparams = stp_parameter_list_count(params);
int i;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Validating options\n");
for (i = 0; i < nparams; i++)
{
const stp_parameter_t *param = stp_parameter_list_param(params, i);
stp_parameter_t desc;
stp_describe_parameter(v, param->name, &desc);
if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
{
if (!stp_string_list_is_present
(desc.bounds.str, stp_get_string_parameter(v, desc.name)))
{
if (! suppress_messages)
{
const char *val = stp_get_string_parameter(v, desc.name);
fprintf(stderr, "DEBUG: Gutenprint: Clearing string %s (%s)\n",
desc.name, val ? val : "(null)");
}
stp_clear_string_parameter(v, desc.name);
if (!desc.read_only && desc.is_mandatory && desc.is_active)
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Setting default string %s to %s\n",
desc.name, desc.deflt.str ? desc.deflt.str : "(null)");
stp_set_string_parameter(v, desc.name, desc.deflt.str);
if (strcmp(desc.name, "PageSize") == 0)
{
const stp_papersize_t *ps =
stp_describe_papersize(v, desc.deflt.str);
if (ps->width > 0)
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Setting page width to %.3f\n",
ps->width);
if (ps->width < stp_get_page_width(v))
stp_set_page_width(v, ps->width);
}
if (ps->height > 0)
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Setting page height to %.3f\n",
ps->height);
if (ps->height < stp_get_page_height(v))
stp_set_page_height(v, ps->height);
}
}
}
}
}
stp_parameter_description_destroy(&desc);
}
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Done validating options\n");
stp_parameter_list_destroy(params);
}
static stp_vars_t *
initialize_page(cups_image_t *cups, const stp_vars_t *default_settings,
const char *page_size_name)
{
stp_dimension_t tmp_left, tmp_right, tmp_top, tmp_bottom;
stp_vars_t *v = stp_vars_create_copy(default_settings);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Initialize page\n");
if (cups->header.cupsBitsPerColor == 16)
set_string_parameter(v, "ChannelBitDepth", "16");
else
set_string_parameter(v, "ChannelBitDepth", "8");
switch (cups->header.cupsColorSpace)
{
case CUPS_CSPACE_W :
/* DyeSub photo printers don't support black & white ink! */
if (printer_supports_bw(v))
set_string_parameter(v, "PrintingMode", "BW");
set_string_parameter(v, "InputImageType", "Whitescale");
break;
case CUPS_CSPACE_K :
/* DyeSub photo printers don't support black & white ink! */
if (printer_supports_bw(v))
set_string_parameter(v, "PrintingMode", "BW");
set_string_parameter(v, "InputImageType", "Grayscale");
break;
case CUPS_CSPACE_RGB :
set_string_parameter(v, "PrintingMode", "Color");
set_string_parameter(v, "InputImageType", "RGB");
break;
case CUPS_CSPACE_CMY :
set_string_parameter(v, "PrintingMode", "Color");
set_string_parameter(v, "InputImageType", "CMY");
break;
case CUPS_CSPACE_CMYK :
set_string_parameter(v, "PrintingMode", "Color");
set_string_parameter(v, "InputImageType", "CMYK");
break;
case CUPS_CSPACE_KCMY :
set_string_parameter(v, "PrintingMode", "Color");
set_string_parameter(v, "InputImageType", "KCMY");
break;
default :
stp_i18n_printf(po, _("ERROR: Gutenprint detected a bad colorspace "
"(%d)!\n"), cups->header.cupsColorSpace);
break;
}
set_special_parameter(v, "Resolution", cups->header.cupsCompression - 1);
set_special_parameter(v, "Quality", cups->header.cupsRowFeed - 1);
if (strlen(cups->header.MediaClass) > 0)
set_string_parameter(v, "InputSlot", cups->header.MediaClass);
if (strlen(cups->header.MediaType) > 0)
set_string_parameter(v, "MediaType", cups->header.MediaType);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: PageSize = %dx%d\n", cups->header.PageSize[0],
cups->header.PageSize[1]);
if (page_size_name)
{
if (strcmp(page_size_name, "Custom") == 0)
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Using custom page size for (%d, %d)\n",
cups->header.PageSize[1], cups->header.PageSize[0]);
stp_set_page_width(v, cups->header.PageSize[0]);
stp_set_page_height(v, cups->header.PageSize[1]);
}
else if (stp_describe_papersize(v, page_size_name))
{
stp_dimension_t width, height;
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Using page size %s with (%d, %d)\n",
page_size_name, cups->header.PageSize[1], cups->header.PageSize[0]);
set_string_parameter(v, "PageSize", page_size_name);
stp_get_media_size(v, &width, &height);
if (width > 0)
stp_set_page_width(v, width);
else
stp_set_page_width(v, cups->header.PageSize[0]);
if (height > 0)
stp_set_page_height(v, height);
else
stp_set_page_height(v, cups->header.PageSize[1]);
}
else
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Can't find page size %s with (%d, %d), using custom page size\n",
page_size_name, cups->header.PageSize[1], cups->header.PageSize[0]);
stp_set_page_width(v, cups->header.PageSize[0]);
stp_set_page_height(v, cups->header.PageSize[1]);
}
}
else
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: No named media size for (%d, %d)\n",
cups->header.PageSize[1], cups->header.PageSize[0]);
stp_set_page_width(v, cups->header.PageSize[0]);
stp_set_page_height(v, cups->header.PageSize[1]);
}
/*
* Duplex
* Note that the names MUST match those in the printer driver(s)
*/
if (cups->header.Duplex != 0)
{
if (cups->header.Tumble != 0)
set_string_parameter(v, "Duplex", "DuplexTumble");
else
set_string_parameter(v, "Duplex", "DuplexNoTumble");
}
cups->shrink_to_fit =
(stp_check_int_parameter(v, "CUPSShrinkPage", STP_PARAMETER_ACTIVE) ?
stp_get_int_parameter(v, "CUPSShrinkPage") : 0);
set_string_parameter(v, "JobMode", "Job");
validate_options(v, cups);
stp_get_media_size(v, &(cups->d_width), &(cups->d_height));
stp_get_maximum_imageable_area(v, &tmp_left, &tmp_right,
&tmp_bottom, &tmp_top);
stp_get_imageable_area(v, &(cups->d_left), &(cups->d_right),
&(cups->d_bottom), &(cups->d_top));
if (! suppress_messages)
{
fprintf(stderr, "DEBUG: Gutenprint: limits w %.3f l %.3f r %.3f h %.3f t %.3f b %.3f\n",
cups->d_width, cups->d_left, cups->d_right, cups->d_height, cups->d_top, cups->d_bottom);
fprintf(stderr, "DEBUG: Gutenprint: max limits l %.3f r %.3f t %.3f b %.3f\n",
tmp_left, tmp_right, tmp_top, tmp_bottom);
}
if (tmp_left < 0)
tmp_left = 0;
if (tmp_top < 0)
tmp_top = 0;
if (tmp_right > tmp_left + cups->d_width)
tmp_right = cups->d_width;
if (tmp_bottom > tmp_top + cups->d_height)
tmp_bottom = cups->d_height;
if (tmp_left < cups->d_left)
{
if (cups->shrink_to_fit != 1)
{
cups->d_left_trim = cups->d_left - tmp_left;
tmp_left = cups->d_left;
}
else
cups->d_left_trim = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: left margin %.3f\n", cups->d_left_trim);
}
else
{
cups->d_left_trim = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Adjusting left margin from %.3f to %.3f\n",
cups->d_left, tmp_left);
cups->d_left = tmp_left;
}
if (tmp_right > cups->d_right)
{
if (cups->shrink_to_fit != 1)
{
cups->d_right_trim = tmp_right - cups->d_right;
tmp_right = cups->d_right;
}
else
cups->d_right_trim = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: right margin %.3f\n", cups->d_right_trim);
}
else
{
cups->d_right_trim = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Adjusting right margin from %.3f to %.3f\n",
cups->d_right, tmp_right);
cups->d_right = tmp_right;
}
if (tmp_top < cups->d_top)
{
if (cups->shrink_to_fit != 1)
{
cups->d_top_trim = cups->d_top - tmp_top;
tmp_top = cups->d_top;
}
else
cups->d_top_trim = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: top margin %.3f\n", cups->d_top_trim);
}
else
{
cups->d_top_trim = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Adjusting top margin from %.3f to %.3f\n",
cups->d_top, tmp_top);
cups->d_top = tmp_top;
}
if (tmp_bottom > cups->d_bottom)
{
if (cups->shrink_to_fit != 1)
{
cups->d_bottom_trim = tmp_bottom - cups->d_bottom;
tmp_bottom = cups->d_bottom;
}
else
cups->d_bottom_trim = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: bottom margin %.3f\n", cups->d_bottom_trim);
}
else
{
cups->d_bottom_trim = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Adjusting bottom margin from %.3f to %.3f\n",
cups->d_bottom, tmp_bottom);
cups->d_bottom = tmp_bottom;
}
if (cups->shrink_to_fit == 2)
{
stp_dimension_t t_left, t_right, t_bottom, t_top;
stp_get_imageable_area(v, &(t_left), &(t_right), &(t_bottom), &(t_top));
stp_set_width(v, t_right - t_left);
stp_set_height(v, t_bottom - t_top);
stp_set_left(v, t_left);
stp_set_top(v, t_top);
}
else
{
stp_set_width(v, cups->d_right - cups->d_left);
stp_set_height(v, cups->d_bottom - cups->d_top);
stp_set_left(v, cups->d_left);
stp_set_top(v, cups->d_top);
}
cups->d_right = cups->d_width - cups->d_right;
if (cups->shrink_to_fit == 1)
cups->d_width = tmp_right - tmp_left;
else
cups->d_width = cups->d_width - cups->d_left - cups->d_right;
cups->width = cups->header.HWResolution[0] * cups->d_width / 72;
cups->left = cups->header.HWResolution[0] * cups->d_left / 72;
cups->right = cups->header.HWResolution[0] * cups->d_right / 72;
cups->left_trim = cups->header.HWResolution[0] * cups->d_left_trim / 72;
cups->right_trim = cups->header.HWResolution[0] * cups->d_right_trim / 72;
cups->adjusted_width = cups->width;
if (cups->adjusted_width > cups->header.cupsWidth)
cups->adjusted_width = cups->header.cupsWidth;
cups->d_bottom = cups->d_height - cups->d_bottom;
if (cups->shrink_to_fit == 1)
cups->d_height = tmp_bottom - tmp_top;
else
cups->d_height = cups->d_height - cups->d_top - cups->d_bottom;
cups->height = cups->header.HWResolution[1] * cups->d_height / 72;
cups->top = cups->header.HWResolution[1] * cups->d_top / 72;
cups->bottom = cups->header.HWResolution[1] * cups->d_bottom / 72;
cups->top_trim = cups->header.HWResolution[1] * cups->d_top_trim / 72;
cups->bottom_trim = cups->header.HWResolution[1] * cups->d_bottom_trim / 72;
cups->adjusted_height = cups->height;
if (cups->adjusted_height > cups->header.cupsHeight)
cups->adjusted_height = cups->header.cupsHeight;
if (! suppress_messages)
{
fprintf(stderr, "DEBUG: Gutenprint: CUPS settings w %d l %d r %d h %d t %d b %d\n",
cups->width, cups->left, cups->right,
cups->height, cups->top, cups->bottom);
fprintf(stderr, "DEBUG: Gutenprint: adjusted w %d h %d\n",
cups->adjusted_width, cups->adjusted_height);
}
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: End initialize page\n");
return v;
}
static void
purge_excess_data(cups_image_t *cups)
{
char *buffer = stp_malloc(cups->header.cupsBytesPerLine);
if (buffer)
{
if (! suppress_messages && ! suppress_verbose_messages )
fprintf(stderr, "DEBUG2: Gutenprint: Purging %d row%s\n",
cups->header.cupsHeight - cups->row,
((cups->header.cupsHeight - cups->row) == 1 ? "" : "s"));
while (cups->row < cups->header.cupsHeight)
{
cupsRasterReadPixels(cups->ras, (unsigned char *)buffer,
cups->header.cupsBytesPerLine);
cups->row ++;
}
}
stp_free(buffer);
}
static void
set_all_options(stp_vars_t *v, cups_option_t *options, int num_options,
ppd_file_t *ppd)
{
stp_parameter_list_t params = stp_get_parameter_list(v);
int nparams = stp_parameter_list_count(params);
int i;
const char *val; /* CUPS option value */
ppd_option_t *ppd_option;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set options:\n");
val = cupsGetOption("StpiShrinkOutput", num_options, options);
if (!val)
{
ppd_option = ppdFindOption(ppd, "StpiShrinkOutput");
if (ppd_option)
val = ppd_option->defchoice;
}
if (val)
{
if (!strcasecmp(val, "crop"))
stp_set_int_parameter(v, "CUPSShrinkPage", 0);
else if (!strcasecmp(val, "expand"))
stp_set_int_parameter(v, "CUPSShrinkPage", 2);
else
stp_set_int_parameter(v, "CUPSShrinkPage", 1);
}
else
stp_set_int_parameter(v, "CUPSShrinkPage", 1);
for (i = 0; i < nparams; i++)
{
const stp_parameter_t *param = stp_parameter_list_param(params, i);
stp_parameter_t desc;
char *ppd_option_name = stp_malloc(strlen(param->name) + 8); /* StpFineFOO\0 */
stp_describe_parameter(v, param->name, &desc);
if (desc.p_type == STP_PARAMETER_TYPE_DOUBLE)
{
sprintf(ppd_option_name, "Stp%s", desc.name);
val = cupsGetOption(ppd_option_name, num_options, options);
if (!val)
{
ppd_option = ppdFindOption(ppd, ppd_option_name);
if (ppd_option)
val = ppd_option->defchoice;
}
if (val && !strncasecmp(val, "Custom.", 7))
{
double dval = atof(val + 7);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set float %s to %f\n",
desc.name, dval);
if (dval > desc.bounds.dbl.upper)
dval = desc.bounds.dbl.upper;
stp_set_float_parameter(v, desc.name, dval);
}
else if (val && strlen(val) > 0 && strcmp(val, "None") != 0)
{
double fine_val = 0;
if (strchr(val, (int) '.'))
{
fine_val = atof(val);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set float %s to %f (%s)\n",
desc.name, fine_val, val);
}
else
{
double coarse_val = atof(val) * 0.001;
sprintf(ppd_option_name, "StpFine%s", desc.name);
val = cupsGetOption(ppd_option_name, num_options, options);
if (!val)
{
ppd_option = ppdFindOption(ppd, ppd_option_name);
if (ppd_option)
val = ppd_option->defchoice;
}
if (val && strlen(val) > 0 && strcmp(val, "None") != 0)
fine_val = atof(val) * 0.001;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set float %s to %f + %f\n",
desc.name, coarse_val, fine_val);
fine_val += coarse_val;
}
if (fine_val > desc.bounds.dbl.upper)
fine_val = desc.bounds.dbl.upper;
if (fine_val < desc.bounds.dbl.lower)
fine_val = desc.bounds.dbl.lower;
stp_set_float_parameter(v, desc.name, fine_val);
}
}
else
{
sprintf(ppd_option_name, "Stp%s", desc.name);
val = cupsGetOption(ppd_option_name, num_options, options);
if (!val)
{
ppd_option = ppdFindOption(ppd, ppd_option_name);
if (ppd_option)
val = ppd_option->defchoice;
}
if (val && ((strlen(val) > 0 && strcmp(val, "None") != 0) ||
(desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)))
{
stp_curve_t *curve;
stp_raw_t *raw;
switch (desc.p_type)
{
case STP_PARAMETER_TYPE_STRING_LIST:
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set string %s to %s\n",
desc.name, val);
set_string_parameter(v, desc.name, val);
break;
case STP_PARAMETER_TYPE_INT:
if (!strncasecmp(val, "Custom.", 7))
val += 7;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set int %s to %s (%d)\n",
desc.name, val, atoi(val));
stp_set_int_parameter(v, desc.name, atoi(val));
break;
case STP_PARAMETER_TYPE_DIMENSION:
if (!strncasecmp(val, "Custom.", 7))
val += 7;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set dimension %s to %s (%d)\n",
desc.name, val, atoi(val));
stp_set_dimension_parameter(v, desc.name, atoi(val));
break;
case STP_PARAMETER_TYPE_BOOLEAN:
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set bool %s to %s (%d)\n",
desc.name, val, strcasecmp(val, "true") == 0 ? 1 : 0);
stp_set_boolean_parameter
(v, desc.name, strcasecmp(val, "true") == 0 ? 1 : 0);
break;
case STP_PARAMETER_TYPE_CURVE:
curve = stp_curve_create_from_string(val);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set curve %s to %s\n",
desc.name, curve ? val : "(NULL)");
if (curve)
{
stp_set_curve_parameter(v, desc.name, curve);
stp_curve_destroy(curve);
}
break;
case STP_PARAMETER_TYPE_RAW: /* figure this out later, too */
raw = stp_xmlstrtoraw(val);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Set raw %s to %s\n",
desc.name, raw ? val : "(NULL)");
if (raw)
{
stp_set_raw_parameter(v, desc.name, raw->data, raw->bytes);
stp_free(cast_safe(raw->data));
stp_free(raw);
}
break;
case STP_PARAMETER_TYPE_FILE: /* Probably not, security hole */
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Ignoring option %s %s type %d\n",
desc.name, val, desc.p_type);
break;
default:
break;
}
}
else if (val)
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Not setting %s to '%s'\n",
desc.name, val);
}
else
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Not setting %s to (null)\n",
desc.name);
}
}
stp_parameter_description_destroy(&desc);
stp_free(ppd_option_name);
}
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: End options\n");
stp_parameter_list_destroy(params);
}
#ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
static void
save_options(const char *save_name, const stp_vars_t *v)
{
FILE *f_options;
int i;
stp_vars_t *c = stp_vars_create();
stp_parameter_list_t params = stp_get_parameter_list(v);
stp_parameter_t desc;
stp_mxml_node_t *mxml = NULL;
int param_count;
if (!params)
{
stp_vars_destroy(c);
return;
}
f_options = fopen(save_name, "w");
if (!f_options)
{
stp_parameter_list_destroy(params);
stp_vars_destroy(c);
return;
}
param_count = stp_parameter_list_count(params);
stp_set_driver(c, stp_get_driver(v));
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Saving parameters to %s\n", save_name);
for (i = 0; i < param_count; i++)
{
const stp_parameter_t *lparam =
stp_parameter_list_param(params, i);
stp_describe_parameter(v, lparam->name, &desc);
if (desc.read_only || !strcmp(desc.name, "ChannelBitDepth") ||
!stp_parameter_has_category_value(v, &desc, "Color", "Yes"))
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: skipping non-color %s\n",
desc.name);
stp_parameter_description_destroy(&desc);
continue;
}
switch (desc.p_type)
{
case STP_PARAMETER_TYPE_STRING_LIST:
if (stp_check_string_parameter(v, desc.name,
STP_PARAMETER_DEFAULTED))
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING string %s %s\n",
desc.name, stp_get_string_parameter(v, desc.name));
stp_set_string_parameter(c, desc.name,
stp_get_string_parameter(v, desc.name));
}
else if (desc.is_mandatory)
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING defaulted string %s %s\n",
desc.name, desc.deflt.str);
stp_set_string_parameter(c, desc.name, desc.deflt.str);
}
else if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: skipping string %s\n", desc.name);
break;
case STP_PARAMETER_TYPE_RAW:
if (stp_check_raw_parameter(v, desc.name,
STP_PARAMETER_DEFAULTED))
{
const stp_raw_t *raw = stp_get_raw_parameter(v, desc.name);
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING raw %s\n", desc.name);
stp_set_raw_parameter(c, desc.name, raw->data, raw->bytes);
}
else if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: skipping raw %s\n",
desc.name);
break;
case STP_PARAMETER_TYPE_BOOLEAN:
if (stp_check_boolean_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING bool %s %d\n",
desc.name, stp_get_boolean_parameter(v, desc.name));
stp_set_boolean_parameter(c, desc.name,
stp_get_boolean_parameter(v, desc.name));
}
else if (desc.is_mandatory)
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING defaulted bool %s %d\n",
desc.name, desc.deflt.boolean);
stp_set_boolean_parameter(c, desc.name, desc.deflt.boolean);
}
else if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: skipping bool %s\n", desc.name);
break;
case STP_PARAMETER_TYPE_INT:
if (stp_check_int_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING int %s %d\n",
desc.name, stp_get_int_parameter(v, desc.name));
stp_set_int_parameter(c, desc.name, stp_get_int_parameter(v, desc.name));
}
else if (desc.is_mandatory)
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING defaulted int %s %d\n",
desc.name, desc.deflt.integer);
stp_set_int_parameter(c, desc.name, desc.deflt.integer);
}
else if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: skipping int %s\n", desc.name);
break;
case STP_PARAMETER_TYPE_DOUBLE:
if (stp_check_float_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING float %s %f\n",
desc.name, stp_get_float_parameter(v, desc.name));
stp_set_float_parameter(c, desc.name,
stp_get_float_parameter(v, desc.name));
}
else if (desc.is_mandatory)
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING defaulted float %s %f\n",
desc.name, desc.deflt.dbl);
stp_set_float_parameter(c, desc.name, desc.deflt.dbl);
}
else if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: skipping float %s\n", desc.name);
break;
case STP_PARAMETER_TYPE_DIMENSION:
if (stp_check_dimension_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING dimension %s %d\n",
desc.name, stp_get_dimension_parameter(v, desc.name));
stp_set_dimension_parameter(c, desc.name,
stp_get_dimension_parameter(v, desc.name));
}
else if (desc.is_mandatory)
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING defaulted dimension %s %d\n",
desc.name, desc.deflt.dimension);
stp_set_dimension_parameter(c, desc.name, desc.deflt.dimension);
}
else if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: skipping dimension %s\n", desc.name);
break;
case STP_PARAMETER_TYPE_CURVE:
if (stp_check_curve_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING curve %s\n", desc.name);
stp_set_curve_parameter(c, desc.name,
stp_get_curve_parameter(v, desc.name));
}
else if (desc.is_mandatory)
{
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: SAVING defaulted curve %s\n", desc.name);
stp_set_curve_parameter(c, desc.name, desc.deflt.curve);
}
else if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: skipping curve %s\n",
desc.name);
break;
default:
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Ignoring unknown type parameter %s (%d)\n",
desc.name, desc.p_type);
break;
}
stp_parameter_description_destroy(&desc);
}
stp_parameter_list_destroy(params);
mxml = stp_xmltree_create_from_vars(c);
if (mxml)
{
fputs("\n\n", f_options);
stp_mxmlSaveFile(mxml, f_options, STP_MXML_NO_CALLBACK);
stp_mxmlDelete(mxml);
}
(void) fclose(f_options);
stp_vars_destroy(c);
if (!suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Done saving parameters to %s\n", save_name);
}
static stp_vars_t *
load_options(const char *load_name)
{
FILE *f_options = fopen(load_name, "r");
if (f_options)
{
stp_vars_t *settings = NULL;
stp_mxml_node_t *mxml;
mxml = stp_mxmlLoadFile(NULL, f_options, STP_MXML_NO_CALLBACK);
if (mxml)
{
stp_mxml_node_t *nxml =
stp_mxmlFindElement(mxml, mxml, "vars", NULL, NULL,
STP_MXML_DESCEND);
if (nxml)
{
settings = stp_vars_create_from_xmltree_ref(nxml->child, mxml);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: loading options from %s\n",
load_file_name);
if (! suppress_messages)
stp_vars_print_error(settings, "DEBUG");
}
}
else
fprintf(stderr, "DEBUG: Unable to load options from %s\n",
load_file_name);
fclose(f_options);
return settings;
}
return NULL;
}
#endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
/*
* 'main()' - Main entry and processing of driver.
*/
int /* O - Exit status */
main(int argc, /* I - Number of command-line arguments */
char *argv[]) /* I - Command-line arguments */
{
int fd; /* File descriptor */
cups_image_t cups; /* CUPS image */
const char *ppdfile; /* PPD environment variable */
ppd_file_t *ppd; /* PPD file */
ppd_size_t *size;
const stp_printer_t *printer; /* Printer driver */
int num_options; /* Number of CUPS options */
cups_option_t *options; /* CUPS options */
stp_vars_t *v = NULL;
stp_vars_t *default_settings;
int initialized_job = 0;
const char *version_id;
struct tms tms;
long clocks_per_sec;
struct timeval t1, t2;
char *page_size_name = NULL;
int aborted = 0;
#ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
stp_vars_t *loaded_settings = NULL;
#endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
/*
* Don't buffer error/status messages...
*/
setbuf(stderr, NULL);
if (getenv("STP_SUPPRESS_MESSAGES"))
suppress_messages = 1;
if (getenv("STP_SUPPRESS_VERBOSE_MESSAGES"))
suppress_verbose_messages = 1;
/*
* Initialize libgutenprint
*/
po = stp_i18n_load(getenv("LANG"));
theImage.rep = ∪︀
(void) gettimeofday(&t1, NULL);
stp_set_global_errfunc(cups_errfunc);
stp_set_global_dbgfunc(cups_dbgfunc);
stp_set_global_errdata(stderr);
stp_set_global_dbgdata(stderr);
stp_init();
version_id = stp_get_version();
default_settings = stp_vars_create();
stp_set_outfunc(default_settings, cups_writefunc);
stp_set_outdata(default_settings, stdout);
/*
* Check for valid arguments...
*/
if (argc < 6 || argc > 7)
{
/*
* We don't have the correct number of arguments; write an error message
* and return.
*/
stp_i18n_printf(po, _("Usage: rastertoprinter job-id user title copies "
"options [file]\n"));
return (1);
}
if (! suppress_messages)
{
fprintf(stderr, "DEBUG: Gutenprint: ============================================================\n");
fprintf(stderr, "DEBUG: Gutenprint: VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
fprintf(stderr, "DEBUG: Gutenprint: %s Starting\n", version_id);
fprintf(stderr, "DEBUG: Gutenprint: command line: %s '%s' '%s' '%s' '%s' %s%s%s%s\n",
argv[0], argv[1], argv[2], argv[3], argv[4], "",
argc >= 7 ? " '" : "",
argc >= 7 ? argv[6] : "",
argc >= 7 ? "'" : "");
}
/*
* Get the PPD file...
*/
if ((ppdfile = getenv("PPD")) == NULL)
{
stp_i18n_printf(po, _("ERROR: No PPD file, unable to continue!\n"));
return (1);
}
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: using PPD file %s\n", ppdfile);
if ((ppd = ppdOpenFile(ppdfile)) == NULL)
{
stp_i18n_printf(po, _("ERROR: Gutenprint was unable to load PPD file "
"\"%s\"!\n"), ppdfile);
return (1);
}
if (ppd->modelname == NULL)
{
stp_i18n_printf(po, _("ERROR: Gutenprint did not find a ModelName "
"attribute in PPD file \"%s\"!\n"), ppdfile);
ppdClose(ppd);
return (1);
}
if (ppd->nickname == NULL)
{
stp_i18n_printf(po, _("ERROR: Gutenprint did not find a NickName attribute "
"in PPD file \"%s\"!\n"), ppdfile);
ppdClose(ppd);
return (1);
}
else if (strlen(ppd->nickname) <
strlen(ppd->modelname) + strlen(CUPS_PPD_NICKNAME_STRING) + 3)
{
stp_i18n_printf(po, _("ERROR: Gutenprint found a corrupted NickName "
"attribute in PPD file \"%s\"!\n"), ppdfile);
ppdClose(ppd);
return (1);
}
else if (strcmp(ppd->nickname + strlen(ppd->modelname) +
strlen(CUPS_PPD_NICKNAME_STRING), version_id) != 0 &&
(strlen(ppd->nickname + strlen(ppd->modelname) +
strlen(CUPS_PPD_NICKNAME_STRING)) < strlen(version_id) ||
!((strncmp(ppd->nickname + strlen(ppd->modelname) +
strlen(CUPS_PPD_NICKNAME_STRING), version_id,
strlen(version_id)) == 0) &&
*(ppd->nickname + strlen(ppd->modelname) +
strlen(CUPS_PPD_NICKNAME_STRING)) != ' ')))
{
stp_i18n_printf(po, _("ERROR: The PPD version (%s) is not compatible with "
"Gutenprint %s. Please run `%scups-genppdupdate' as administrator.\n"),
ppd->nickname+strlen(ppd->modelname)+strlen(CUPS_PPD_NICKNAME_STRING),
version_id, SBINDIR);
fprintf(stderr, "DEBUG: Gutenprint: If you have upgraded your version of Gutenprint\n");
fprintf(stderr, "DEBUG: Gutenprint: recently, you must reinstall all printer queues.\n");
fprintf(stderr, "DEBUG: Gutenprint: If the previous installed version of Gutenprint\n");
fprintf(stderr, "DEBUG: Gutenprint: was 5.0.0 or higher, you can use the `cups-genppdupdate'\n");
fprintf(stderr, "DEBUG: Gutenprint: program to do this; if the previous installed version\n");
fprintf(stderr, "DEBUG: Gutenprint: was older, you can use the Modify Printer command via\n");
fprintf(stderr, "DEBUG: Gutenprint: the CUPS web interface: http://localhost:631/printers.\n");
ppdClose(ppd);
return 1;
}
/*
* Get the STP options, if any...
*/
num_options = cupsParseOptions(argv[5], 0, &options);
ppdMarkDefaults(ppd);
cupsMarkOptions(ppd, num_options, options);
size = ppdPageSize(ppd, NULL);
if (size)
page_size_name = stp_strdup(size->name);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: CUPS option count is %d (%d bytes)\n",
num_options, (int)strlen(argv[5]));
if (num_options > 0)
{
int i;
for (i = 0; i < num_options; i++)
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: CUPS option %d %s = %s\n",
i, options[i].name, options[i].value);
#ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
if (!strcmp(options[i].name, "SaveFileName"))
save_file_name = options[i].value;
if (!strcmp(options[i].name, "LoadFileName"))
load_file_name = options[i].value;
#endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
}
}
/*
* Figure out which driver to use...
*/
printer = stp_get_printer_by_driver(ppd->modelname);
if (!printer)
printer = stp_get_printer_by_long_name(ppd->modelname);
if (printer == NULL)
{
stp_i18n_printf(po, _("ERROR: Unable to find Gutenprint driver named "
"\"%s\"!\n"), ppd->modelname);
ppdClose(ppd);
return (1);
}
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Driver %s\n", ppd->modelname);
/*
* Open the page stream...
*/
if (argc == 7)
{
if ((fd = open(argv[6], O_RDONLY)) == -1)
{
stp_i18n_printf(po, _("ERROR: Gutenprint was unable to open raster file "
"\"%s\" - %s"), argv[6], strerror(errno));
sleep(1);
return (1);
}
}
else
fd = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Using fd %d\n", fd);
stp_set_printer_defaults(default_settings, printer);
#ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
if (load_file_name)
loaded_settings = load_options(load_file_name);
#endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
stp_set_float_parameter(default_settings, "AppGamma", 1.0);
set_all_options(default_settings, options, num_options, ppd);
cupsFreeOptions(num_options, options);
ppdClose(ppd);
cups.ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
/*
* Process pages as needed...
*/
cups.page = 0;
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: About to start printing loop.\n");
/*
* Read the first page header, which we need in order to set up
* the page.
*/
signal(SIGTERM, cancel_job);
while (CUPS_READ_HEADER(cups.ras, &cups.header))
{
/*
* We don't know how many pages we're going to print, and
* we need to call stp_end_job at the completion of the job.
* Therefore, we need to keep v in scope after the termination
* of the loop to permit calling stp_end_job then. Therefore,
* we have to free the previous page's stp_vars_t at the start
* of the loop.
*/
if (v)
stp_vars_destroy(v);
/*
* Setup printer driver variables...
*/
if (! suppress_messages)
{
fprintf(stderr, "DEBUG: Gutenprint: ================ Printing page %d ================\n", cups.page + 1);
fprintf(stderr, "PAGE: %d %d\n", cups.page + 1, cups.header.NumCopies);
}
v = initialize_page(&cups, default_settings, page_size_name);
#ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
if (loaded_settings)
stp_copy_vars_from(v, loaded_settings);
if (save_file_name)
{
save_options(save_file_name, v);
save_file_name = NULL;
}
#endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
if (! suppress_messages)
{
fprintf(stderr, "DEBUG: Gutenprint: Interim page settings:\n");
stp_vars_print_error(v, "DEBUG");
}
stp_merge_printvars(v, stp_printer_get_defaults(printer));
/* Pass along Collation settings */
stp_set_boolean_parameter(v, "Collate", cups.header.Collate);
stp_set_boolean_parameter_active(v, "Collate", STP_PARAMETER_ACTIVE);
/* Pass along Copy settings */
stp_set_int_parameter(v, "NumCopies", cups.header.NumCopies);
stp_set_int_parameter_active(v, "NumCopies", STP_PARAMETER_ACTIVE);
/* Pass along the page number */
stp_set_int_parameter(v, "PageNumber", cups.page);
cups.row = 0;
if (! suppress_messages)
print_debug_block(v, &cups);
print_messages_as_errors = 1;
if (!initialized_job)
{
stp_start_job(v, &theImage);
initialized_job = 1;
}
if (!stp_print(v, &theImage))
{
if (Image_status != STP_IMAGE_STATUS_ABORT)
{
fprintf(stderr, "DEBUG: Gutenprint: Options failed to verify.\n");
fprintf(stderr, "DEBUG: Gutenprint: Make sure that you are using ESP Ghostscript rather\n");
fprintf(stderr, "DEBUG: Gutenprint: than GNU or AFPL Ghostscript with CUPS.\n");
fprintf(stderr, "DEBUG: Gutenprint: If this is not the cause, set LogLevel to debug to identify the problem.\n");
}
aborted = 1;
break;
}
print_messages_as_errors = 0;
fflush(stdout);
/*
* Purge any remaining bitmap data...
*/
if (cups.row < cups.header.cupsHeight)
purge_excess_data(&cups);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: ================ Done printing page %d ================\n", cups.page + 1);
cups.page ++;
}
if (v)
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: %s job\n",
aborted ? "Aborted" : "Ending");
stp_end_job(v, &theImage);
fflush(stdout);
stp_vars_destroy(v);
}
cupsRasterClose(cups.ras);
(void) times(&tms);
(void) gettimeofday(&t2, NULL);
clocks_per_sec = sysconf(_SC_CLK_TCK);
fprintf(stderr, "DEBUG: Gutenprint: stats %.0fB, %.3fu, %.3fs, %.3fel\n",
total_bytes_printed,
(double) tms.tms_utime / clocks_per_sec,
(double) tms.tms_stime / clocks_per_sec,
(double) (t2.tv_sec - t1.tv_sec) +
((double) (t2.tv_usec - t1.tv_usec)) / 1000000.0);
if (!suppress_messages)
{
fprintf(stderr, "DEBUG: Gutenprint: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
fprintf(stderr, "DEBUG: Gutenprint: ============================================================\n");
}
stp_vars_destroy(default_settings);
if (page_size_name)
stp_free(page_size_name);
if (fd != 0)
close(fd);
return aborted ? 1 : 0;
}
/*
* 'cups_writefunc()' - Write data to a file...
*/
static void
cups_writefunc(void *file, const char *buf, size_t bytes)
{
FILE *prn = (FILE *)file;
total_bytes_printed += bytes;
fwrite(buf, 1, bytes, prn);
}
static void
cups_errfunc(void *file, const char *buf, size_t bytes)
{
size_t next_nl = 0;
size_t where = 0;
FILE *prn = (FILE *)file;
while (where < bytes)
{
if (bytes - where > 6 && strncmp(buf, "ERROR:", 6) == 0)
{
fputs("ERROR: Gutenprint:", prn);
buf += 6;
}
else if (print_messages_as_errors)
fputs("ERROR: Gutenprint: ", prn);
else if (strncmp(buf, "DEBUG", 5) != 0)
fputs("DEBUG: Gutenprint: ", prn);
while (next_nl < bytes)
{
if (buf[next_nl++] == '\n')
break;
}
fwrite(buf + where, 1, next_nl - where, prn);
where = next_nl;
}
}
static void
cups_dbgfunc(void *file, const char *buf, size_t bytes)
{
size_t next_nl = 0;
size_t where = 0;
FILE *prn = (FILE *)file;
while (where < bytes)
{
if (bytes - where > 6 && strncmp(buf, "ERROR:", 6) == 0)
{
fputs("ERROR: Gutenprint:", prn);
buf += 6;
}
else if (strncmp(buf, "DEBUG", 5) != 0)
fputs("DEBUG: Gutenprint: ", prn);
while (next_nl < bytes)
{
if (buf[next_nl++] == '\n')
break;
}
fwrite(buf + where, 1, next_nl - where, prn);
where = next_nl;
}
}
/*
* 'cancel_job()' - Cancel the current job...
*/
static void
cancel_job(int sig) /* I - Signal */
{
(void)sig;
Image_status = STP_IMAGE_STATUS_ABORT;
}
/*
* 'Image_get_appname()' - Get the application we are running.
*/
static const char * /* O - Application name */
Image_get_appname(stp_image_t *image) /* I - Image */
{
(void)image;
return ("CUPS driver based on Gutenprint");
}
/*
* 'Image_get_row()' - Get one row of the image.
*/
static void
throwaway_data(int amount, cups_image_t *cups)
{
unsigned char trash[4096]; /* Throwaway */
int block_count = amount / 4096;
int leftover = amount % 4096;
while (block_count > 0)
{
cupsRasterReadPixels(cups->ras, trash, 4096);
block_count--;
}
if (leftover)
cupsRasterReadPixels(cups->ras, trash, leftover);
}
static stp_image_status_t
Image_get_row(stp_image_t *image, /* I - Image */
unsigned char *data, /* O - Row */
size_t byte_limit, /* I - how many bytes in data */
int row) /* I - Row number (unused) */
{
cups_image_t *cups; /* CUPS image */
int i; /* Looping var */
int bytes_per_line;
int margin;
stp_image_status_t tmp_image_status = Image_status;
unsigned char *orig = data; /* Temporary pointer */
static int warned = 0; /* Error warning printed? */
int new_percent;
int left_margin, right_margin;
if ((cups = (cups_image_t *)(image->rep)) == NULL)
{
stp_i18n_printf(po, _("ERROR: Gutenprint image is not initialized! "
"Please report this bug to "
"gimp-print-devel@lists.sourceforge.net\n"));
return STP_IMAGE_STATUS_ABORT;
}
bytes_per_line =
((cups->adjusted_width * cups->header.cupsBitsPerPixel) + CHAR_BIT - 1) /
CHAR_BIT;
left_margin = ((cups->left_trim * cups->header.cupsBitsPerPixel) + CHAR_BIT - 1) /
CHAR_BIT;
right_margin = ((cups->right_trim * cups->header.cupsBitsPerPixel) + CHAR_BIT - 1) /
CHAR_BIT;
margin = cups->header.cupsBytesPerLine - left_margin - bytes_per_line -
right_margin;
if (cups->row < cups->header.cupsHeight)
{
if (! suppress_messages && ! suppress_verbose_messages)
fprintf(stderr, "DEBUG2: Gutenprint: Reading %d %d\n",
bytes_per_line, cups->row);
while (cups->row <= row && cups->row < cups->header.cupsHeight)
{
if (left_margin > 0)
{
if (! suppress_messages && ! suppress_verbose_messages)
fprintf(stderr, "DEBUG2: Gutenprint: Tossing left %d (%d)\n",
left_margin, cups->left_trim);
throwaway_data(left_margin, cups);
}
cupsRasterReadPixels(cups->ras, data, bytes_per_line);
cups->row ++;
if (margin + right_margin > 0)
{
if (! suppress_messages && ! suppress_verbose_messages)
fprintf(stderr, "DEBUG2: Gutenprint: Tossing right %d (%d) + %d\n",
right_margin, cups->right_trim, margin);
throwaway_data(margin + right_margin, cups);
}
}
}
else
{
switch (cups->header.cupsColorSpace)
{
case CUPS_CSPACE_K:
case CUPS_CSPACE_CMYK:
case CUPS_CSPACE_KCMY:
case CUPS_CSPACE_CMY:
memset(data, 0, bytes_per_line);
break;
case CUPS_CSPACE_RGB:
case CUPS_CSPACE_W:
memset(data, ((1 << CHAR_BIT) - 1), bytes_per_line);
break;
default:
stp_i18n_printf(po, _("ERROR: Gutenprint detected a bad colorspace "
"(%d)!\n"), cups->header.cupsColorSpace);
return STP_IMAGE_STATUS_ABORT;
}
}
/*
* This exists to print non-ADSC input which has messed up the job
* input, such as that generated by psnup. The output is barely
* legible, but it's better than the garbage output otherwise.
*/
data = orig;
if (cups->header.cupsBitsPerPixel == 1)
{
if (warned == 0)
{
fputs(_("WARNING: Gutenprint detected a bad color depth (1). "
"Output quality is degraded. Are you using psnup or "
"non-ADSC PostScript?\n"), stderr);
warned = 1;
}
for (i = cups->adjusted_width - 1; i >= 0; i--)
{
if ( (data[i/8] >> (7 - i%8)) &0x1)
data[i]=255;
else
data[i]=0;
}
}
new_percent = (int) (100.0 * cups->row / cups->header.cupsHeight);
if (new_percent > cups->last_percent)
{
if (! suppress_verbose_messages)
{
stp_i18n_printf(po, _("INFO: Printing page %d, %d%%\n"),
cups->page + 1, new_percent);
fprintf(stderr, "ATTR: job-media-progress=%d\n", new_percent);
}
cups->last_percent = new_percent;
}
if (tmp_image_status != STP_IMAGE_STATUS_OK)
{
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Image status %d\n", tmp_image_status);
}
return tmp_image_status;
}
/*
* 'Image_height()' - Return the height of an image.
*/
static int /* O - Height in pixels */
Image_height(stp_image_t *image) /* I - Image */
{
cups_image_t *cups; /* CUPS image */
if ((cups = (cups_image_t *)(image->rep)) == NULL)
return (0);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Image_height %d\n", cups->adjusted_height);
return (cups->adjusted_height);
}
/*
* 'Image_init()' - Initialize an image.
*/
static void
Image_init(stp_image_t *image) /* I - Image */
{
cups_image_t *cups; /* CUPS image */
if ((cups = (cups_image_t *)(image->rep)) == NULL)
return;
cups->last_percent = 0;
if (! suppress_messages)
stp_i18n_printf(po, _("INFO: Starting page %d...\n"), cups->page + 1);
/* cups->page + 1 because users expect 1-based counting */
}
/*
* 'Image_progress_conclude()' - Close the progress display.
*/
static void
Image_conclude(stp_image_t *image) /* I - Image */
{
cups_image_t *cups; /* CUPS image */
if ((cups = (cups_image_t *)(image->rep)) == NULL)
return;
if (! suppress_messages)
stp_i18n_printf(po, _("INFO: Finished page %d...\n"), cups->page + 1);
}
/*
* 'Image_width()' - Return the width of an image.
*/
static int /* O - Width in pixels */
Image_width(stp_image_t *image) /* I - Image */
{
cups_image_t *cups; /* CUPS image */
if ((cups = (cups_image_t *)(image->rep)) == NULL)
return (0);
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Image_width %d\n", cups->adjusted_width);
return (cups->adjusted_width);
}