/*
- * PostScript filter function for cups-filters.
+ * PostScript filter function and image file to PostScript filter function
+ * for cups-filters.
*
* Copyright © 2020 by Till Kamppeter
* Copyright © 2007-2018 by Apple Inc.
* Include necessary headers...
*/
-#include "filter.h"
+#include <cupsfilters/filter.h>
+#include <cupsfilters/image.h>
+#include <cupsfilters/raster.h>
+#include <cupsfilters/image-private.h>
+#include <ppd/ppd.h>
+#include <cups/file.h>
+#include <cups/array.h>
#include <limits.h>
#include <math.h>
#include <ctype.h>
#include <signal.h>
+#include <string.h>
#include <errno.h>
-#include <cups/file.h>
-#include <cups/array.h>
-#include <ppd/ppd.h>
#include <sys/types.h>
#include <sys/wait.h>
int Orientation, /* 0 = portrait, 1 = landscape, etc. */
Duplex, /* Duplexed? */
LanguageLevel, /* PS Language level of printer */
- ColorDevice; /* Color printer? */
+ Color; /* Color printer? */
float PageLeft, /* Left margin */
PageRight, /* Right margin */
PageBottom, /* Bottom margin */
static void do_prolog(pstops_doc_t *doc, ppd_file_t *ppd);
static void do_setup(pstops_doc_t *doc, ppd_file_t *ppd);
static void doc_printf(pstops_doc_t *doc, const char *format, ...);
+static void doc_putc(pstops_doc_t *doc, const char c);
static void doc_puts(pstops_doc_t *doc, const char *s);
static void doc_write(pstops_doc_t *doc, const char *s, size_t len);
static void end_nup(pstops_doc_t *doc, int number);
cups_option_t **options);
static char *parse_text(const char *start, char **end, char *buffer,
size_t bufsize);
+static void ps_hex(pstops_doc_t *doc, cf_ib_t *data, int length,
+ int last_line);
+static void ps_ascii85(pstops_doc_t *doc, cf_ib_t *data, int length,
+ int last_line);
static int set_pstops_options(pstops_doc_t *doc, ppd_file_t *ppd,
int job_id, char *job_user,
char *job_title, int copies,
char *line, ssize_t linelen, size_t linesize);
static void start_nup(pstops_doc_t *doc, int number,
int show_border, const int *bounding_box);
+static void write_common(pstops_doc_t *doc);
static void write_label_prolog(pstops_doc_t *doc, const char *label,
float bottom, float top,
float width);
* Write any "exit server" options that have been selected...
*/
- ppdEmit(data->ppd, outputfp, PPD_ORDER_EXIT);
+ ppdEmit(data->ppd, outputfp, PPD_ORDER_EXIT);
+
+ /*
+ * Write any JCL commands that are needed to print PostScript code...
+ */
+
+ if (doc.emit_jcl)
+ ppdEmitJCL(data->ppd, outputfp, doc.job_id, doc.user, doc.title);
+
+ /*
+ * Start with a DSC header...
+ */
+
+ doc_puts(&doc, "%!PS-Adobe-3.0\n");
+
+ /*
+ * Skip leading PJL in the document...
+ */
+
+ while (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))
+ {
+ /*
+ * Yup, we have leading PJL fun, so skip it until we hit the line
+ * with "ENTER LANGUAGE"...
+ */
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterPSToPS: Skipping PJL header...");
+
+ while (strstr(line, "ENTER LANGUAGE") == NULL && strncmp(line, "%!", 2))
+ if ((len = (ssize_t)cupsFileGetLine(inputfp, line, sizeof(line))) == 0)
+ break;
+
+ if (!strncmp(line, "%!", 2))
+ break;
+
+ if ((len = (ssize_t)cupsFileGetLine(inputfp, line, sizeof(line))) == 0)
+ break;
+ }
+
+ /*
+ * Now see if the document conforms to the Adobe Document Structuring
+ * Conventions...
+ */
+
+ if (!strncmp(line, "%!PS-Adobe-", 11))
+ {
+ /*
+ * Yes, filter the document...
+ */
+
+ copy_dsc(&doc, data->ppd, line, len, sizeof(line));
+ }
+ else
+ {
+ /*
+ * No, display an error message and treat the file as if it contains
+ * a single page...
+ */
+
+ copy_non_dsc(&doc, data->ppd, line, len, sizeof(line));
+ }
+
+ /*
+ * Send %%EOF as needed...
+ */
+
+ if (!doc.saw_eof)
+ doc_puts(&doc, "%%EOF\n");
+
+ /*
+ * End the job with the appropriate JCL command or CTRL-D...
+ */
+
+ if (doc.emit_jcl)
+ {
+ if (data->ppd && data->ppd->jcl_end)
+ ppdEmitJCLEnd(data->ppd, doc.outputfp);
+ else
+ doc_putc(&doc, 0x04);
+ }
+
+ /*
+ * Close files and remove the temporary file if needed...
+ */
+
+ if (doc.temp)
+ {
+ cupsFileClose(doc.temp);
+ unlink(doc.tempfile);
+ }
+
+ if (doc.pages)
+ {
+ for (pageinfo = (pstops_page_t *)cupsArrayFirst(doc.pages);
+ pageinfo; pageinfo = (pstops_page_t *)cupsArrayNext(doc.pages))
+ {
+ if (pageinfo->label)
+ free(pageinfo->label);
+ if (pageinfo->num_options && pageinfo->options)
+ cupsFreeOptions(pageinfo->num_options, pageinfo->options);
+ free(pageinfo);
+ }
+ cupsArrayDelete(doc.pages);
+ doc.pages = NULL;
+ }
+
+ if(doc.inputPageRange)
+ {
+ retry_wait:
+ if (waitpid (pstops_pid, &childStatus, 0) == -1) {
+ if (errno == EINTR)
+ goto retry_wait;
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "cfFilterPSToPS: Error while waiting for input_page_ranges to finish - %s.",
+ strerror(errno));
+ }
+ /* How did the sub-process terminate */
+ if (childStatus) {
+ if (WIFEXITED(childStatus)) {
+ /* Via exit() anywhere or return() in the main() function */
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "cfFilterPSToPS: input-page-ranges filter (PID %d) stopped with status %d",
+ pstops_pid, WEXITSTATUS(childStatus));
+ } else {
+ /* Via signal */
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "cfFilterPSToPS: imput-page-ranges filter (PID %d) crashed on signal %d",
+ pstops_pid, WTERMSIG(childStatus));
+ }
+ status=1;
+ } else {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterPSToPS: input-page-ranges-filter (PID %d) exited with no errors.",
+ pstops_pid);
+ }
+ }
+
+ cupsFileClose(inputfp);
+ close(inputfd);
+
+ fclose(outputfp);
+ close(outputfd);
+
+ return (status);
+}
+
+
+/*
+ * 'cfFilterImageToPS()' - Filter function to convert many common image file
+ * formats into PostScript
+ */
+
+int /* O - Error status */
+cfFilterImageToPS(int inputfd, /* I - File descriptor input stream */
+ int outputfd, /* I - File descriptor output stream*/
+ int inputseekable, /* I - Is input stream seekable?
+ (unused) */
+ cf_filter_data_t *data, /* I - Job and printer data */
+ void *parameters) /* I - Filter-specific parameters
+ (unused) */
+{
+ pstops_doc_t doc; /* Document information */
+ cf_image_t *img; /* Image to print */
+ float xprint, /* Printable area */
+ yprint,
+ xinches, /* Total size in inches */
+ yinches;
+ float xsize, /* Total size in points */
+ ysize,
+ xsize2,
+ ysize2;
+ float aspect; /* Aspect ratio */
+ int xpages, /* # x pages */
+ ypages, /* # y pages */
+ xpage, /* Current x page */
+ ypage, /* Current y page */
+ page; /* Current page number */
+ int xc0, yc0, /* Corners of the page in image coords*/
+ xc1, yc1;
+ cf_ib_t *row; /* Current row */
+ int y; /* Current Y coordinate in image */
+ int colorspace; /* Output colorspace */
+ int out_offset, /* Offset into output buffer */
+ out_length; /* Length of output buffer */
+ ppd_file_t *ppd; /* PPD file */
+ ppd_choice_t *choice; /* PPD option choice */
+ int num_options; /* Number of print options */
+ cups_option_t *options; /* Print options */
+ const char *val; /* Option value */
+ int slowcollate; /* Collate copies the slow way */
+ float g; /* Gamma correction value */
+ float b; /* Brightness factor */
+ float zoom; /* Zoom facter */
+ int xppi, yppi; /* Pixels-per-inch */
+ int hue, sat; /* Hue and saturation adjustment */
+ int realcopies, /* Real copies being printed */
+ emit_jcl; /* Emit JCL? */
+ float left, top; /* Left and top of image */
+ time_t curtime; /* Current time */
+ struct tm *curtm; /* Current date */
+ char curdate[255]; /* Current date string */
+ int fillprint = 0; /* print-scaling = fill */
+ int cropfit = 0; /* -o crop-to-fit = true */
+ cups_page_header2_t h; /* CUPS Raster page header, to */
+ /* accommodate results of command */
+ /* line parsing for PPD-less queue */
+ int Flip, /* Flip/mirror pages */
+ XPosition, /* Horizontal position on page */
+ YPosition, /* Vertical position on page */
+ Collate, /* Collate copies? */
+ Copies; /* Number of copies */
+ char tempfile[1024]; /* Name of file to print */
+ FILE *inputfp; /* Input file */
+ int fd; /* File descriptor for temp file */
+ char buf[BUFSIZ];
+ int bytes;
+ cf_logfunc_t log = data->logfunc;
+ void *ld = data->logdata;
+ cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
+ void *icd = data->iscanceleddata;
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Ignore broken pipe signals...
+ */
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Initialize data structure
+ */
+
+ Flip = 0;
+ XPosition = 0;
+ YPosition = 0;
+ Collate = 0;
+ Copies = 1;
+
+ /*
+ * Initialize document information structure...
+ */
+
+ memset(&doc, 0, sizeof(pstops_doc_t));
+
+ /*
+ * Open the input data stream specified by the inputfd ...
+ */
+
+ if ((inputfp = fdopen(inputfd, "r")) == NULL)
+ {
+ if (!iscanceled || !iscanceled(icd))
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "cfFilterImageToPS: Unable to open input data stream.");
+ }
+
+ return (1);
+ }
+
+ /*
+ * Copy input into temporary file if needed ...
+ */
+
+ if (!inputseekable) {
+ if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "cfFilterImageToPS: Unable to copy input: %s",
+ strerror(errno));
+ return (1);
+ }
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Copying input to temp file \"%s\"",
+ tempfile);
+
+ while ((bytes = fread(buf, 1, sizeof(buf), inputfp)) > 0)
+ bytes = write(fd, buf, bytes);
+
+ fclose(inputfp);
+ close(fd);
+
+ /*
+ * Open the temporary file to read it instead of the original input ...
+ */
+
+ if ((inputfp = fopen(tempfile, "r")) == NULL)
+ {
+ if (!iscanceled || !iscanceled(icd))
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "cfFilterImageToPS: Unable to open temporary file.");
+ }
+
+ unlink(tempfile);
+ return (1);
+ }
+ }
+
+ /*
+ * Open the output data stream specified by the outputfd...
+ */
+
+ if ((doc.outputfp = fdopen(outputfd, "w")) == NULL)
+ {
+ if (!iscanceled || !iscanceled(icd))
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "cfFilterImageToPS: Unable to open output data stream.");
+ }
+
+ fclose(inputfp);
+
+ if (!inputseekable)
+ unlink(tempfile);
+ return (1);
+ }
+
+ /*
+ * Process command-line options and write the prolog...
+ */
+
+ zoom = 1.0;
+ xppi = 0;
+ yppi = 0;
+ hue = 0;
+ sat = 100;
+ g = 1.0;
+ b = 1.0;
+
+ Copies = data->copies;
+
+ /*
+ * Option list...
+ */
+
+ options = data->options;
+ num_options = data->num_options;
+
+ /*
+ * Process job options...
+ */
+
+ ppd = data->ppd;
+ cfFilterSetCommonOptions(ppd, num_options, options, 0,
+ &doc.Orientation, &doc.Duplex,
+ &doc.LanguageLevel, &doc.Color,
+ &doc.PageLeft, &doc.PageRight,
+ &doc.PageTop, &doc.PageBottom,
+ &doc.PageWidth, &doc.PageLength,
+ log, ld);
+
+ /* The cfFilterSetCommonOptions() does not set doc.Color
+ according to option settings (user's demand for color/gray),
+ so we parse the options and set the mode here */
+ cfRasterParseIPPOptions(&h, data, 0, 1);
+ if (doc.Color)
+ doc.Color = h.cupsNumColors <= 1 ? 0 : 1;
+ if (!ppd) {
+ /* Without PPD use also the other findings of cfRasterParseIPPOptions() */
+ doc.Orientation = h.Orientation;
+ doc.Duplex = h.Duplex;
+ doc.LanguageLevel = 2;
+ doc.PageWidth = h.cupsPageSize[0] != 0.0 ? h.cupsPageSize[0] :
+ (float)h.PageSize[0];
+ doc.PageLength = h.cupsPageSize[1] != 0.0 ? h.cupsPageSize[1] :
+ (float)h.PageSize[1];
+ doc.PageLeft = h.cupsImagingBBox[0] != 0.0 ? h.cupsImagingBBox[0] :
+ (float)h.ImagingBoundingBox[0];
+ doc.PageBottom = h.cupsImagingBBox[1] != 0.0 ? h.cupsImagingBBox[1] :
+ (float)h.ImagingBoundingBox[1];
+ doc.PageRight = h.cupsImagingBBox[2] != 0.0 ? h.cupsImagingBBox[2] :
+ (float)h.ImagingBoundingBox[2];
+ doc.PageTop = h.cupsImagingBBox[3] != 0.0 ? h.cupsImagingBBox[3] :
+ (float)h.ImagingBoundingBox[3];
+ Flip = h.MirrorPrint ? 1 : 0;
+ Collate = h.Collate ? 1 : 0;
+ Copies = h.NumCopies;
+ }
+
+ if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
+ {
+ /*
+ * This IPP attribute is unnecessarily complicated...
+ *
+ * single-document, separate-documents-collated-copies, and
+ * single-document-new-sheet all require collated copies.
+ *
+ * separate-documents-uncollated-copies allows for uncollated copies.
+ */
+
+ Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
+ }
+
+ if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
+ strcasecmp(val, "True") == 0)
+ Collate = 1;
+
+ if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
+ {
+ /*
+ * Get gamma value from 1 to 10000...
+ */
+
+ g = atoi(val) * 0.001f;
+
+ if (g < 0.001f)
+ g = 0.001f;
+ else if (g > 10.0f)
+ g = 10.0f;
+ }
+
+ if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
+ {
+ /*
+ * Get brightness value from 10 to 1000.
+ */
+
+ b = atoi(val) * 0.01f;
+
+ if (b < 0.1f)
+ b = 0.1f;
+ else if (b > 10.0f)
+ b = 10.0f;
+ }
+
+ if ((val = cupsGetOption("ppi", num_options, options)) != NULL)
+ {
+ sscanf(val, "%d", &xppi);
+ yppi = xppi;
+ zoom = 0.0;
+ }
+
+ if ((val = cupsGetOption("position", num_options, options)) != NULL)
+ {
+ if (strcasecmp(val, "center") == 0)
+ {
+ XPosition = 0;
+ YPosition = 0;
+ }
+ else if (strcasecmp(val, "top") == 0)
+ {
+ XPosition = 0;
+ YPosition = 1;
+ }
+ else if (strcasecmp(val, "left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 0;
+ }
+ else if (strcasecmp(val, "right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 0;
+ }
+ else if (strcasecmp(val, "top-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 1;
+ }
+ else if (strcasecmp(val, "top-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 1;
+ }
+ else if (strcasecmp(val, "bottom") == 0)
+ {
+ XPosition = 0;
+ YPosition = -1;
+ }
+ else if (strcasecmp(val, "bottom-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = -1;
+ }
+ else if (strcasecmp(val, "bottom-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = -1;
+ }
+ }
+
+ if ((val = cupsGetOption("saturation", num_options, options)) != NULL)
+ sat = atoi(val);
+
+ if ((val = cupsGetOption("hue", num_options, options)) != NULL)
+ hue = atoi(val);
+
+ if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
+ {
+ val = choice->choice;
+ choice->marked = 0;
+ }
+ else
+ val = cupsGetOption("mirror", num_options, options);
+
+ if (val && (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+ !strcasecmp(val, "yes")))
+ Flip = 1;
+
+ if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
+ (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
+ !strcasecmp(val, "no") || !strcmp(val, "0")))
+ emit_jcl = 0;
+ else
+ emit_jcl = 1;
+
+ /*
+ * Open the input image to print...
+ */
+
+ colorspace = doc.Color ? CF_IMAGE_RGB_CMYK : CF_IMAGE_WHITE;
+
+ img = cfImageOpenFP(inputfp, colorspace, CF_IMAGE_WHITE, sat, hue, NULL);
+ if (img != NULL) {
+
+ int margin_defined = 0;
+ int fidelity = 0;
+ int document_large = 0;
+
+ if (ppd && (ppd->custom_margins[0] || ppd->custom_margins[1] ||
+ ppd->custom_margins[2] || ppd->custom_margins[3]))
+ /* In case of custom margins */
+ margin_defined = 1;
+ if (doc.PageLength != doc.PageTop - doc.PageBottom ||
+ doc.PageWidth != doc.PageRight - doc.PageLeft)
+ margin_defined = 1;
+
+ if((val = cupsGetOption("ipp-attribute-fidelity", num_options, options))
+ != NULL)
+ {
+ if(!strcasecmp(val, "true") || !strcasecmp(val, "yes") ||
+ !strcasecmp(val, "on")) {
+ fidelity = 1;
+ }
+ }
+
+ float w = (float)cfImageGetWidth(img);
+ float h = (float)cfImageGetHeight(img);
+ float pw = doc.PageRight - doc.PageLeft;
+ float ph = doc.PageTop - doc.PageBottom;
+ int tempOrientation = doc.Orientation;
+ if ((val = cupsGetOption("orientation-requested", num_options, options)) !=
+ NULL)
+ tempOrientation = atoi(val);
+ else if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
+ {
+ if(!strcasecmp(val, "true") || !strcasecmp(val, "yes"))
+ tempOrientation = 4;
+ }
+ if (tempOrientation == 0) {
+ if (((pw > ph) && (w < h)) || ((pw < ph) && (w > h)))
+ tempOrientation = 4;
+ }
+ if (tempOrientation == 4 || tempOrientation == 5)
+ {
+ int tmp = pw;
+ pw = ph;
+ ph = tmp;
+ }
+ if (w * 72.0 / img->xppi > pw || h * 72.0 / img->yppi > ph)
+ document_large = 1;
+
+ if ((val = cupsGetOption("print-scaling", num_options, options)) != NULL)
+ {
+ if (!strcasecmp(val, "auto"))
+ {
+ if (fidelity || document_large) {
+ if (margin_defined)
+ zoom = 1.0; // fit method
+ else
+ fillprint = 1; // fill method
+ }
+ else
+ cropfit = 1; // none method
+ }
+ else if (!strcasecmp(val, "auto-fit"))
+ {
+ if (fidelity || document_large)
+ zoom = 1.0; // fit method
+ else
+ cropfit = 1; // none method
+ }
+ else if (!strcasecmp(val, "fill"))
+ fillprint = 1; // fill method
+ else if (!strcasecmp(val, "fit"))
+ zoom = 1.0; // fitplot = 1 or fit method
+ else
+ cropfit = 1; // none or crop-to-fit
+ }
+ else
+ { // print-scaling is not defined, look for alternate options.
+ if ((val = cupsGetOption("scaling", num_options, options)) != NULL)
+ zoom = atoi(val) * 0.01;
+ else if (((val =
+ cupsGetOption("fit-to-page", num_options, options)) != NULL) ||
+ ((val = cupsGetOption("fitplot", num_options, options)) != NULL))
+ {
+ if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
+ !strcasecmp(val, "true"))
+ zoom = 1.0;
+ else
+ zoom = 0.0;
+ }
+ else if ((val = cupsGetOption("natural-scaling", num_options, options)) !=
+ NULL)
+ zoom = 0.0;
+
+ if ((val = cupsGetOption("fill", num_options,options)) != NULL)
+ {
+ if (!strcasecmp(val, "true") || !strcasecmp(val, "yes"))
+ fillprint = 1;
+ }
+
+ if ((val = cupsGetOption("crop-to-fit", num_options,options)) != NULL)
+ {
+ if (!strcasecmp(val, "true") || !strcasecmp(val, "yes"))
+ cropfit=1;
+ }
+ }
+ if (fillprint || cropfit)
+ {
+ /* For cropfit do the math without the unprintable margins to get correct
+ centering */
+ if (cropfit)
+ {
+ pw = doc.PageWidth;
+ ph = doc.PageLength;
+ doc.PageBottom = 0.0;
+ doc.PageTop = doc.PageLength;
+ doc.PageLeft = 0.0;
+ doc.PageRight = doc.PageWidth;
+ }
+ tempOrientation = doc.Orientation;
+ int flag = 3;
+ if ((val = cupsGetOption("orientation-requested", num_options,
+ options)) != NULL)
+ tempOrientation = atoi(val);
+ else if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
+ {
+ if (!strcasecmp(val,"true") || !strcasecmp(val,"yes"))
+ tempOrientation = 4;
+ }
+ if (tempOrientation > 0)
+ {
+ if (tempOrientation == 4 || tempOrientation == 5)
+ {
+ float temp = pw;
+ pw = ph;
+ ph = temp;
+ flag = 4;
+ }
+ }
+ if (tempOrientation==0)
+ {
+ if (((pw > ph) && (w < h)) || ((pw < ph) && (w > h)))
+ {
+ int temp = pw;
+ pw = ph;
+ ph = temp;
+ flag = 4;
+ }
+ }
+ if (fillprint) {
+ float final_w, final_h;
+ if (w * ph / pw <= h) {
+ final_w = w;
+ final_h = w * ph / pw;
+ }
+ else
+ {
+ final_w = h * pw / ph;
+ final_h = h;
+ }
+ float posw = (w - final_w) / 2, posh = (h - final_h) / 2;
+ posw = (1 + XPosition) * posw;
+ posh = (1 - YPosition) * posh;
+ cf_image_t *img2 = cfImageCrop(img, posw, posh, final_w, final_h);
+ cfImageClose(img);
+ img = img2;
+ }
+ else
+ {
+ float final_w = w, final_h = h;
+ if (w > pw * img->xppi / 72.0)
+ final_w = pw * img->xppi / 72.0;
+ if (h > ph * img->yppi / 72.0)
+ final_h = ph * img->yppi / 72.0;
+ float posw = (w - final_w) / 2, posh = (h - final_h) / 2;
+ posw = (1 + XPosition) * posw;
+ posh = (1 - YPosition) * posh;
+ cf_image_t *img2 = cfImageCrop(img, posw, posh, final_w, final_h);
+ cfImageClose(img);
+ img = img2;
+ if (flag == 4)
+ {
+ doc.PageBottom += (doc.PageLength - final_w * 72.0 / img->xppi) / 2;
+ doc.PageTop = doc.PageBottom + final_w * 72.0 / img->xppi;
+ doc.PageLeft += (doc.PageWidth - final_h * 72.0 / img->yppi) / 2;
+ doc.PageRight = doc.PageLeft + final_h * 72.0 / img->yppi;
+ }
+ else
+ {
+ doc.PageBottom += (doc.PageLength - final_h * 72.0 / img->yppi) / 2;
+ doc.PageTop = doc.PageBottom + final_h * 72.0 / img->yppi;
+ doc.PageLeft += (doc.PageWidth - final_w * 72.0 / img->xppi) / 2;
+ doc.PageRight = doc.PageLeft + final_w * 72.0 / img->xppi;
+ }
+ if (doc.PageBottom < 0) doc.PageBottom = 0;
+ if (doc.PageLeft < 0) doc.PageLeft = 0;
+ }
+ }
+ }
+
+ if (!inputseekable)
+ unlink(tempfile);
+
+ if (img == NULL)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "cfFilterImageToPS: The print file could not be opened - %s",
+ strerror(errno));
+ return (1);
+ }
+
+ colorspace = cfImageGetColorSpace(img);
+
+ /*
+ * Scale as necessary...
+ */
+
+ if (zoom == 0.0 && xppi == 0)
+ {
+ xppi = cfImageGetXPPI(img);
+ yppi = cfImageGetYPPI(img);
+ }
+
+ if (yppi == 0)
+ yppi = xppi;
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Before scaling: xppi=%d, yppi=%d, zoom=%.2f",
+ xppi, yppi, zoom);
+
+ if (xppi > 0)
+ {
+ /*
+ * Scale the image as neccesary to match the desired pixels-per-inch.
+ */
+
+ if (doc.Orientation & 1)
+ {
+ xprint = (doc.PageTop - doc.PageBottom) / 72.0;
+ yprint = (doc.PageRight - doc.PageLeft) / 72.0;
+ }
+ else
+ {
+ xprint = (doc.PageRight - doc.PageLeft) / 72.0;
+ yprint = (doc.PageTop - doc.PageBottom) / 72.0;
+ }
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
+ xprint, yprint);
+
+ xinches = (float)cfImageGetWidth(img) / (float)xppi;
+ yinches = (float)cfImageGetHeight(img) / (float)yppi;
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Image size is %.1f x %.1f inches...",
+ xinches, yinches);
+
+ if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
+ {
+ xinches = xinches * atoi(val) / 100;
+ yinches = yinches * atoi(val) / 100;
+ }
+
+ if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * Rotate the image if it will fit landscape but not portrait...
+ */
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Auto orientation...");
+
+ if ((xinches > xprint || yinches > yprint) &&
+ xinches <= yprint && yinches <= xprint)
+ {
+ /*
+ * Rotate the image as needed...
+ */
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Using landscape orientation...");
+
+ doc.Orientation = (doc.Orientation + 1) & 3;
+ xsize = yprint;
+ yprint = xprint;
+ xprint = xsize;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Scale percentage of page size...
+ */
+
+ xprint = (doc.PageRight - doc.PageLeft) / 72.0;
+ yprint = (doc.PageTop - doc.PageBottom) / 72.0;
+ aspect = (float)cfImageGetYPPI(img) / (float)cfImageGetXPPI(img);
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
+ xprint, yprint);
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: cfImageGetXPPI(img) = %d, "
+ "cfImageGetYPPI(img) = %d, aspect = %f",
+ cfImageGetXPPI(img), cfImageGetYPPI(img), aspect);
+
+ xsize = xprint * zoom;
+ ysize = xsize * cfImageGetHeight(img) / cfImageGetWidth(img) / aspect;
+
+ if (ysize > (yprint * zoom))
+ {
+ ysize = yprint * zoom;
+ xsize = ysize * cfImageGetWidth(img) * aspect /
+ cfImageGetHeight(img);
+ }
+
+ xsize2 = yprint * zoom;
+ ysize2 = xsize2 * cfImageGetHeight(img) / cfImageGetWidth(img) /
+ aspect;
+
+ if (ysize2 > (xprint * zoom))
+ {
+ ysize2 = xprint * zoom;
+ xsize2 = ysize2 * cfImageGetWidth(img) * aspect /
+ cfImageGetHeight(img);
+ }
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Portrait size is %.2f x %.2f inches",
+ xsize, ysize);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Landscape size is %.2f x %.2f inches",
+ xsize2, ysize2);
+
+ if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * Choose the rotation with the largest area, but prefer
+ * portrait if they are equal...
+ */
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Auto orientation...");
+
+ if ((xsize * ysize) < (xsize2 * xsize2))
+ {
+ /*
+ * Do landscape orientation...
+ */
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Using landscape orientation...");
+
+ doc.Orientation = 1;
+ xinches = xsize2;
+ yinches = ysize2;
+ xprint = (doc.PageTop - doc.PageBottom) / 72.0;
+ yprint = (doc.PageRight - doc.PageLeft) / 72.0;
+ }
+ else
+ {
+ /*
+ * Do portrait orientation...
+ */
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Using portrait orientation...");
+
+ doc.Orientation = 0;
+ xinches = xsize;
+ yinches = ysize;
+ }
+ }
+ else if (doc.Orientation & 1)
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Using landscape orientation...");
+
+ xinches = xsize2;
+ yinches = ysize2;
+ xprint = (doc.PageTop - doc.PageBottom) / 72.0;
+ yprint = (doc.PageRight - doc.PageLeft) / 72.0;
+ }
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Using portrait orientation...");
+
+ xinches = xsize;
+ yinches = ysize;
+ xprint = (doc.PageRight - doc.PageLeft) / 72.0;
+ yprint = (doc.PageTop - doc.PageBottom) / 72.0;
+ }
+ }
+
+ /*
+ * Compute the number of pages to print and the size of the image on each
+ * page...
+ */
+
+ xpages = ceil(xinches / xprint);
+ ypages = ceil(yinches / yprint);
+
+ xprint = xinches / xpages;
+ yprint = yinches / ypages;
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: xpages = %dx%.2fin, ypages = %dx%.2fin",
+ xpages, xprint, ypages, yprint);
+
+ /*
+ * Update the page size for custom sizes...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
+ strcasecmp(choice->choice, "Custom") == 0)
+ {
+ float width, /* New width in points */
+ length; /* New length in points */
+ char s[255]; /* New custom page size... */
+
+
+ /*
+ * Use the correct width and length for the current orientation...
+ */
+
+ if (doc.Orientation & 1)
+ {
+ width = yprint * 72.0;
+ length = xprint * 72.0;
+ }
+ else
+ {
+ width = xprint * 72.0;
+ length = yprint * 72.0;
+ }
+
+ /*
+ * Add margins to page size...
+ */
+
+ width += ppd->custom_margins[0] + ppd->custom_margins[2];
+ length += ppd->custom_margins[1] + ppd->custom_margins[3];
+
+ /*
+ * Enforce minimums...
+ */
+
+ if (width < ppd->custom_min[0])
+ width = ppd->custom_min[0];
+
+ if (length < ppd->custom_min[1])
+ length = ppd->custom_min[1];
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Updated custom page size to %.2f x %.2f inches...",
+ width / 72.0, length / 72.0);
+
+ /*
+ * Set the new custom size...
+ */
+
+ sprintf(s, "Custom.%.0fx%.0f", width, length);
+ ppdMarkOption(ppd, "PageSize", s);
+
+ /*
+ * Update page variables...
+ */
+
+ doc.PageWidth = width;
+ doc.PageLength = length;
+ doc.PageLeft = ppd->custom_margins[0];
+ doc.PageRight = width - ppd->custom_margins[2];
+ doc.PageBottom = ppd->custom_margins[1];
+ doc.PageTop = length - ppd->custom_margins[3];
+ }
+
+ /*
+ * See if we need to collate, and if so how we need to do it...
+ */
+
+ if (xpages == 1 && ypages == 1)
+ Collate = 0;
+
+ slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL;
+
+ if (Copies > 1 && !slowcollate)
+ {
+ realcopies = Copies;
+ Copies = 1;
+ }
+ else
+ realcopies = 1;
+
+ /*
+ * Write any "exit server" options that have been selected...
+ */
+
+ ppdEmit(ppd, doc.outputfp, PPD_ORDER_EXIT);
+
+ /*
+ * Write any JCL commands that are needed to print PostScript code...
+ */
+
+ if (emit_jcl)
+ ppdEmitJCL(ppd, doc.outputfp, data->job_id, data->job_user,
+ data->job_title);
+
+ /*
+ * Start sending the document with any commands needed...
+ */
+
+ curtime = time(NULL);
+ curtm = localtime(&curtime);
+
+ doc_puts(&doc, "%!PS-Adobe-3.0\n");
+ doc_printf(&doc, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
+ doc.PageLeft, doc.PageBottom, doc.PageRight, doc.PageTop);
+ doc_printf(&doc, "%%%%LanguageLevel: %d\n", doc.LanguageLevel);
+ doc_printf(&doc, "%%%%Pages: %d\n", xpages * ypages * Copies);
+ doc_puts(&doc, "%%DocumentData: Clean7Bit\n");
+ doc_puts(&doc, "%%DocumentNeededResources: font Helvetica-Bold\n");
+ doc_puts(&doc, "%%Creator: imagetops\n");
+ strftime(curdate, sizeof(curdate), "%c", curtm);
+ doc_printf(&doc, "%%%%CreationDate: %s\n", curdate);
+ write_text_comment(&doc, "Title", data->job_title);
+ write_text_comment(&doc, "For", data->job_user);
+ if (doc.Orientation & 1)
+ doc_puts(&doc, "%%Orientation: Landscape\n");
+ else
+ doc_puts(&doc, "%%Orientation: Portrait\n");
+ doc_puts(&doc, "%%EndComments\n");
+ doc_puts(&doc, "%%BeginProlog\n");
+
+ if (ppd != NULL && ppd->patches != NULL)
+ {
+ doc_puts(&doc, ppd->patches);
+ doc_putc(&doc, '\n');
+ }
+
+ ppdEmit(ppd, doc.outputfp, PPD_ORDER_DOCUMENT);
+ ppdEmit(ppd, doc.outputfp, PPD_ORDER_ANY);
+ ppdEmit(ppd, doc.outputfp, PPD_ORDER_PROLOG);
+
+ if (g != 1.0 || b != 1.0)
+ doc_printf(&doc,
+ "{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
+ "ifelse %.3f mul } bind settransfer\n", g, b);
+
+ write_common(&doc);
+ switch (doc.Orientation)
+ {
+ case 0 :
+ write_label_prolog(&doc, cupsGetOption("page-label", num_options,
+ options),
+ doc.PageBottom, doc.PageTop, doc.PageWidth);
+ break;
+
+ case 1 :
+ write_label_prolog(&doc, cupsGetOption("page-label", num_options,
+ options),
+ doc.PageLeft, doc.PageRight, doc.PageLength);
+ break;
+
+ case 2 :
+ write_label_prolog(&doc, cupsGetOption("page-label", num_options,
+ options),
+ doc.PageLength - doc.PageTop,
+ doc.PageLength - doc.PageBottom,
+ doc.PageWidth);
+ break;
+
+ case 3 :
+ write_label_prolog(&doc, cupsGetOption("page-label", num_options,
+ options),
+ doc.PageWidth - doc.PageRight,
+ doc.PageWidth - doc.PageLeft,
+ doc.PageLength);
+ break;
+ }
+
+ if (realcopies > 1)
+ {
+ if (ppd == NULL || ppd->language_level == 1)
+ doc_printf(&doc, "/#copies %d def\n", realcopies);
+ else
+ doc_printf(&doc, "<</NumCopies %d>>setpagedevice\n", realcopies);
+ }
+
+ doc_puts(&doc, "%%EndProlog\n");
+
+ /*
+ * Output the pages...
+ */
+
+ row = malloc(cfImageGetWidth(img) * abs(colorspace) + 3);
+ if (row == NULL)
+ {
+ log(ld, CF_LOGLEVEL_ERROR,
+ "cfFilterImageToPS: Could not allocate memory.");
+ cfImageClose(img);
+ return (2);
+ }
+
+ if (log)
+ {
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: XPosition=%d, YPosition=%d, Orientation=%d",
+ XPosition, YPosition, doc.Orientation);
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: xprint=%.1f, yprint=%.1f", xprint, yprint);
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f",
+ doc.PageLeft, doc.PageRight, doc.PageWidth);
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f",
+ doc.PageBottom, doc.PageTop, doc.PageLength);
+ }
+
+ switch (doc.Orientation)
+ {
+ default :
+ switch (XPosition)
+ {
+ case -1 :
+ left = doc.PageLeft;
+ break;
+ default :
+ left = (doc.PageRight + doc.PageLeft - xprint * 72) / 2;
+ break;
+ case 1 :
+ left = doc.PageRight - xprint * 72;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case -1 :
+ top = doc.PageBottom + yprint * 72;
+ break;
+ default :
+ top = (doc.PageTop + doc.PageBottom + yprint * 72) / 2;
+ break;
+ case 1 :
+ top = doc.PageTop;
+ break;
+ }
+ break;
+
+ case 1 :
+ switch (XPosition)
+ {
+ case -1 :
+ left = doc.PageBottom;
+ break;
+ default :
+ left = (doc.PageTop + doc.PageBottom - xprint * 72) / 2;
+ break;
+ case 1 :
+ left = doc.PageTop - xprint * 72;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case -1 :
+ top = doc.PageLeft + yprint * 72;
+ break;
+ default :
+ top = (doc.PageRight + doc.PageLeft + yprint * 72) / 2;
+ break;
+ case 1 :
+ top = doc.PageRight;
+ break;
+ }
+ break;
+
+ case 2 :
+ switch (XPosition)
+ {
+ case 1 :
+ left = doc.PageLeft;
+ break;
+ default :
+ left = (doc.PageRight + doc.PageLeft - xprint * 72) / 2;
+ break;
+ case -1 :
+ left = doc.PageRight - xprint * 72;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case 1 :
+ top = doc.PageBottom + yprint * 72;
+ break;
+ default :
+ top = (doc.PageTop + doc.PageBottom + yprint * 72) / 2;
+ break;
+ case -1 :
+ top = doc.PageTop;
+ break;
+ }
+ break;
+
+ case 3 :
+ switch (XPosition)
+ {
+ case 1 :
+ left = doc.PageBottom;
+ break;
+ default :
+ left = (doc.PageTop + doc.PageBottom - xprint * 72) / 2;
+ break;
+ case -1 :
+ left = doc.PageTop - xprint * 72;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case 1 :
+ top = doc.PageLeft + yprint * 72;
+ break;
+ default :
+ top = (doc.PageRight + doc.PageLeft + yprint * 72) / 2;
+ break;
+ case -1 :
+ top = doc.PageRight;
+ break;
+ }
+ break;
+ }
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: left=%.2f, top=%.2f", left, top);
+
+ for (page = 1; Copies > 0; Copies --)
+ for (xpage = 0; xpage < xpages; xpage ++)
+ for (ypage = 0; ypage < ypages; ypage ++, page ++)
+ {
+ if (iscanceled && iscanceled(icd))
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Job canceled");
+ goto canceled;
+ }
+
+ if (log && ppd && ppd->num_filters == 0)
+ log(ld, CF_LOGLEVEL_CONTROL,
+ "PAGE: %d %d", page, realcopies);
+
+ if (log) log(ld, CF_LOGLEVEL_INFO,
+ "cfFilterImageToPS: Printing page %d.", page);
+
+ doc_printf(&doc, "%%%%Page: %d %d\n", page, page);
+
+ ppdEmit(ppd, doc.outputfp, PPD_ORDER_PAGE);
+
+ doc_puts(&doc, "gsave\n");
- /*
- * Write any JCL commands that are needed to print PostScript code...
- */
+ if (Flip)
+ doc_printf(&doc, "%.0f 0 translate -1 1 scale\n", doc.PageWidth);
- if (doc.emit_jcl)
- ppdEmitJCL(data->ppd, outputfp, doc.job_id, doc.user, doc.title);
+ switch (doc.Orientation)
+ {
+ case 1 : /* Landscape */
+ doc_printf(&doc, "%.0f 0 translate 90 rotate\n",
+ doc.PageWidth);
+ break;
+ case 2 : /* Reverse Portrait */
+ doc_printf(&doc, "%.0f %.0f translate 180 rotate\n",
+ doc.PageWidth, doc.PageLength);
+ break;
+ case 3 : /* Reverse Landscape */
+ doc_printf(&doc, "0 %.0f translate -90 rotate\n",
+ doc.PageLength);
+ break;
+ }
- /*
- * Start with a DSC header...
- */
+ doc_puts(&doc, "gsave\n");
- fputs("%!PS-Adobe-3.0\n", outputfp);
+ xc0 = cfImageGetWidth(img) * xpage / xpages;
+ xc1 = cfImageGetWidth(img) * (xpage + 1) / xpages - 1;
+ yc0 = cfImageGetHeight(img) * ypage / ypages;
+ yc1 = cfImageGetHeight(img) * (ypage + 1) / ypages - 1;
- /*
- * Skip leading PJL in the document...
- */
+ doc_printf(&doc, "%.1f %.1f translate\n", left, top);
- while (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))
- {
- /*
- * Yup, we have leading PJL fun, so skip it until we hit the line
- * with "ENTER LANGUAGE"...
- */
+ doc_printf(&doc, "%.3f %.3f scale\n\n",
+ xprint * 72.0 / (xc1 - xc0 + 1),
+ yprint * 72.0 / (yc1 - yc0 + 1));
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Skipping PJL header...");
+ if (doc.LanguageLevel == 1)
+ {
+ doc_printf(&doc, "/picture %d string def\n",
+ (xc1 - xc0 + 1) * abs(colorspace));
+ doc_printf(&doc, "%d %d 8[1 0 0 -1 0 1]",
+ (xc1 - xc0 + 1), (yc1 - yc0 + 1));
+
+ if (colorspace == CF_IMAGE_WHITE)
+ doc_puts(&doc, "{currentfile picture readhexstring pop} image\n");
+ else
+ doc_printf(&doc,
+ "{currentfile picture readhexstring pop} false %d "
+ "colorimage\n",
+ abs(colorspace));
+
+ for (y = yc0; y <= yc1; y ++)
+ {
+ cfImageGetRow(img, xc0, y, xc1 - xc0 + 1, row);
+ ps_hex(&doc, row, (xc1 - xc0 + 1) * abs(colorspace),
+ y == yc1);
+ }
+ }
+ else
+ {
+ switch (colorspace)
+ {
+ case CF_IMAGE_WHITE :
+ doc_puts(&doc, "/DeviceGray setcolorspace\n");
+ break;
+ case CF_IMAGE_RGB :
+ doc_puts(&doc, "/DeviceRGB setcolorspace\n");
+ break;
+ case CF_IMAGE_CMYK :
+ doc_puts(&doc, "/DeviceCMYK setcolorspace\n");
+ break;
+ }
- while (strstr(line, "ENTER LANGUAGE") == NULL && strncmp(line, "%!", 2))
- if ((len = (ssize_t)cupsFileGetLine(inputfp, line, sizeof(line))) == 0)
- break;
+ doc_printf(&doc,
+ "<<"
+ "/ImageType 1"
+ "/Width %d"
+ "/Height %d"
+ "/BitsPerComponent 8",
+ xc1 - xc0 + 1, yc1 - yc0 + 1);
- if (!strncmp(line, "%!", 2))
- break;
+ switch (colorspace)
+ {
+ case CF_IMAGE_WHITE :
+ doc_puts(&doc, "/Decode[0 1]");
+ break;
+ case CF_IMAGE_RGB :
+ doc_puts(&doc, "/Decode[0 1 0 1 0 1]");
+ break;
+ case CF_IMAGE_CMYK :
+ doc_puts(&doc, "/Decode[0 1 0 1 0 1 0 1]");
+ break;
+ }
- if ((len = (ssize_t)cupsFileGetLine(inputfp, line, sizeof(line))) == 0)
- break;
- }
+ doc_puts(&doc, "\n/DataSource currentfile/ASCII85Decode filter");
- /*
- * Now see if the document conforms to the Adobe Document Structuring
- * Conventions...
- */
+ if (((xc1 - xc0 + 1) / xprint) < 100.0)
+ doc_puts(&doc, "/Interpolate true");
- if (!strncmp(line, "%!PS-Adobe-", 11))
- {
- /*
- * Yes, filter the document...
- */
+ doc_puts(&doc, "/ImageMatrix[1 0 0 -1 0 1]>>image\n");
- copy_dsc(&doc, data->ppd, line, len, sizeof(line));
- }
- else
- {
- /*
- * No, display an error message and treat the file as if it contains
- * a single page...
- */
+ for (y = yc0, out_offset = 0; y <= yc1; y ++)
+ {
+ cfImageGetRow(img, xc0, y, xc1 - xc0 + 1, row + out_offset);
- copy_non_dsc(&doc, data->ppd, line, len, sizeof(line));
- }
+ out_length = (xc1 - xc0 + 1) * abs(colorspace) + out_offset;
+ out_offset = out_length & 3;
- /*
- * Send %%EOF as needed...
- */
+ ps_ascii85(&doc, row, out_length, y == yc1);
- if (!doc.saw_eof)
- fputs("%%EOF\n", outputfp);
+ if (out_offset > 0)
+ memcpy(row, row + out_length - out_offset, out_offset);
+ }
+ }
- /*
- * End the job with the appropriate JCL command or CTRL-D...
- */
+ doc_puts(&doc, "grestore\n");
+ write_labels(&doc, 0);
+ doc_puts(&doc, "grestore\n");
+ doc_puts(&doc, "showpage\n");
+ }
- if (doc.emit_jcl)
- {
- if (data->ppd && data->ppd->jcl_end)
- ppdEmitJCLEnd(data->ppd, outputfp);
- else
- fputc(0x04, outputfp);
- }
+ canceled:
+ doc_puts(&doc, "%%EOF\n");
+ free(row);
+
/*
- * Close files and remove the temporary file if needed...
+ * End the job with the appropriate JCL command or CTRL-D otherwise.
*/
- if (doc.temp)
- {
- cupsFileClose(doc.temp);
- unlink(doc.tempfile);
- }
-
- if (doc.pages)
+ if (emit_jcl)
{
- for (pageinfo = (pstops_page_t *)cupsArrayFirst(doc.pages);
- pageinfo; pageinfo = (pstops_page_t *)cupsArrayNext(doc.pages))
- {
- if (pageinfo->label)
- free(pageinfo->label);
- if (pageinfo->num_options && pageinfo->options)
- cupsFreeOptions(pageinfo->num_options, pageinfo->options);
- free(pageinfo);
- }
- cupsArrayDelete(doc.pages);
- doc.pages = NULL;
+ if (ppd && ppd->jcl_end)
+ ppdEmitJCLEnd(ppd, doc.outputfp);
+ else
+ doc_putc(&doc, 0x04);
}
- if(doc.inputPageRange)
- {
- retry_wait:
- if (waitpid (pstops_pid, &childStatus, 0) == -1) {
- if (errno == EINTR)
- goto retry_wait;
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Error while waiting for input_page_ranges to finish - %s.",
- strerror(errno));
- }
- /* How did the sub-process terminate */
- if (childStatus) {
- if (WIFEXITED(childStatus)) {
- /* Via exit() anywhere or return() in the main() function */
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: input-page-ranges filter (PID %d) stopped with status %d",
- pstops_pid, WEXITSTATUS(childStatus));
- } else {
- /* Via signal */
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: imput-page-ranges filter (PID %d) crashed on signal %d",
- pstops_pid, WTERMSIG(childStatus));
- }
- status=1;
- } else {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: input-page-ranges-filter (PID %d) exited with no errors.",
- pstops_pid);
- }
- }
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToPS: Printing completed.", page);
- cupsFileClose(inputfp);
- close(inputfd);
+ /*
+ * Close files...
+ */
- fclose(outputfp);
+ cfImageClose(img);
+ fclose(doc.outputfp);
close(outputfd);
- return (status);
+ return (0);
}
nleft -= (size_t)nbytes;
- fwrite(buffer, 1, (size_t)nbytes, doc->outputfp);
+ doc_write(doc, buffer, (size_t)nbytes);
}
}
"PAGE: %d %d", doc->page,
doc->slow_collate ? 1 : doc->copies);
- fprintf(doc->outputfp, "%%%%Page: (filler) %d\n", doc->page);
+ doc_printf(doc, "%%%%Page: (filler) %d\n", doc->page);
}
start_nup(doc, doc->number_up, 0, doc->bounding_box);
* Send the trailer...
*/
- fputs("%%Trailer\n", doc->outputfp);
- fprintf(doc->outputfp, "%%%%Pages: %d\n", cupsArrayCount(doc->pages));
+ doc_puts(doc, "%%Trailer\n");
+ doc_printf(doc, "%%%%Pages: %d\n", cupsArrayCount(doc->pages));
if (doc->number_up > 1 || doc->fit_to_page)
- fprintf(doc->outputfp, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
+ doc_printf(doc, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
doc->PageLeft, doc->PageBottom, doc->PageRight, doc->PageTop);
else
- fprintf(doc->outputfp, "%%%%BoundingBox: %d %d %d %d\n",
+ doc_printf(doc, "%%%%BoundingBox: %d %d %d %d\n",
doc->new_bounding_box[0], doc->new_bounding_box[1],
doc->new_bounding_box[2], doc->new_bounding_box[3]);
- fputs("%%EOF\n", doc->outputfp);
+ doc_puts(doc, "%%EOF\n");
/*
* Start a new document...
ppdEmitJCLEnd(ppd, doc->outputfp);
ppdEmitJCL(ppd, doc->outputfp, doc->job_id, doc->user, doc->title);
- fputs("%!PS-Adobe-3.0\n", doc->outputfp);
+ doc_puts(doc, "%!PS-Adobe-3.0\n");
number = 0;
}
if (doc->number_up > 1)
{
- fprintf(doc->outputfp, "%%%%Page: (%d) %d\n", number, number);
- fprintf(doc->outputfp, "%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
+ doc_printf(doc, "%%%%Page: (%d) %d\n", number, number);
+ doc_printf(doc, "%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
doc->PageLeft, doc->PageBottom, doc->PageRight, doc->PageTop);
}
else
{
- fprintf(doc->outputfp, "%%%%Page: %s %d\n", pageinfo->label, number);
- fprintf(doc->outputfp, "%%%%PageBoundingBox: %d %d %d %d\n",
+ doc_printf(doc, "%%%%Page: %s %d\n", pageinfo->label, number);
+ doc_printf(doc, "%%%%PageBoundingBox: %d %d %d %d\n",
pageinfo->bounding_box[0], pageinfo->bounding_box[1],
pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
}
*/
if (doc->use_ESPshowpage)
- fputs("userdict/showpage/ESPshowpage load put\n", doc->outputfp);
+ doc_puts(doc, "userdict/showpage/ESPshowpage load put\n");
/*
* Write/copy the trailer...
* Then write a standard DSC comment section...
*/
- fprintf(doc->outputfp, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
+ doc_printf(doc, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
doc->PageLeft, doc->PageBottom, doc->PageRight, doc->PageTop);
if (doc->slow_collate && doc->copies > 1)
- fprintf(doc->outputfp, "%%%%Pages: %d\n", doc->copies);
+ doc_printf(doc, "%%%%Pages: %d\n", doc->copies);
else
- fputs("%%Pages: 1\n", doc->outputfp);
+ doc_puts(doc, "%%Pages: 1\n");
write_text_comment(doc, "For", doc->user);
write_text_comment(doc, "Title", doc->title);
* that are required...
*/
- fprintf(doc->outputfp, "%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
+ doc_printf(doc, "%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
doc->collate ? " collate" : "",
doc->Duplex ? " duplex" : "");
* Apple uses RBI comments for various non-PPD options...
*/
- fprintf(doc->outputfp, "%%RBINumCopies: %d\n", doc->copies);
+ doc_printf(doc, "%%RBINumCopies: %d\n", doc->copies);
}
else
{
*/
if (doc->Duplex)
- fputs("%%Requirements: duplex\n", doc->outputfp);
+ doc_puts(doc, "%%Requirements: duplex\n");
/*
* Apple uses RBI comments for various non-PPD options...
*/
- fputs("%RBINumCopies: 1\n", doc->outputfp);
+ doc_puts(doc, "%RBINumCopies: 1\n");
}
- fputs("%%EndComments\n", doc->outputfp);
+ doc_puts(doc, "%%EndComments\n");
/*
* Then the prolog...
*/
- fputs("%%BeginProlog\n", doc->outputfp);
+ doc_puts(doc, "%%BeginProlog\n");
do_prolog(doc, ppd);
- fputs("%%EndProlog\n", doc->outputfp);
+ doc_puts(doc, "%%EndProlog\n");
/*
* Then the setup section...
*/
- fputs("%%BeginSetup\n", doc->outputfp);
+ doc_puts(doc, "%%BeginSetup\n");
do_setup(doc, ppd);
- fputs("%%EndSetup\n", doc->outputfp);
+ doc_puts(doc, "%%EndSetup\n");
/*
* Finally, embed a copy of the file inside a %%Page...
log(ld, CF_LOGLEVEL_CONTROL,
"PAGE: 1 %d", doc->temp ? 1 : doc->copies);
- fputs("%%Page: 1 1\n", doc->outputfp);
- fputs("%%BeginPageSetup\n", doc->outputfp);
+ doc_puts(doc, "%%Page: 1 1\n");
+ doc_puts(doc, "%%BeginPageSetup\n");
ppdEmit(ppd, doc->outputfp, PPD_ORDER_PAGE);
- fputs("%%EndPageSetup\n", doc->outputfp);
- fputs("%%BeginDocument: nondsc\n", doc->outputfp);
+ doc_puts(doc, "%%EndPageSetup\n");
+ doc_puts(doc, "%%BeginDocument: nondsc\n");
- fwrite(line, (size_t)linelen, 1, doc->outputfp);
+ doc_write(doc, line, (size_t)linelen);
if (doc->temp)
cupsFileWrite(doc->temp, line, (size_t)linelen);
while ((bytes = cupsFileRead(doc->inputfp, buffer, sizeof(buffer))) > 0)
{
- fwrite(buffer, 1, (size_t)bytes, doc->outputfp);
+ doc_write(doc, buffer, (size_t)bytes);
if (doc->temp)
cupsFileWrite(doc->temp, buffer, (size_t)bytes);
}
- fputs("%%EndDocument\n", doc->outputfp);
+ doc_puts(doc, "%%EndDocument\n");
if (doc->use_ESPshowpage)
{
write_labels_outputfile_only(doc, doc->Orientation);
- fputs("ESPshowpage\n", doc->outputfp);
+ doc_puts(doc, "ESPshowpage\n");
}
if (doc->temp && (!iscanceled || !iscanceled(icd)))
log(ld, CF_LOGLEVEL_CONTROL,
"PAGE: 1 1");
- fprintf(doc->outputfp, "%%%%Page: %d %d\n", copy + 1, copy + 1);
- fputs("%%BeginPageSetup\n", doc->outputfp);
+ doc_printf(doc, "%%%%Page: %d %d\n", copy + 1, copy + 1);
+ doc_puts(doc, "%%BeginPageSetup\n");
ppdEmit(ppd, doc->outputfp, PPD_ORDER_PAGE);
- fputs("%%EndPageSetup\n", doc->outputfp);
- fputs("%%BeginDocument: nondsc\n", doc->outputfp);
+ doc_puts(doc, "%%EndPageSetup\n");
+ doc_puts(doc, "%%BeginDocument: nondsc\n");
copy_bytes(doc, 0, 0);
- fputs("%%EndDocument\n", doc->outputfp);
+ doc_puts(doc, "%%EndDocument\n");
if (doc->use_ESPshowpage)
{
write_labels_outputfile_only(doc, doc->Orientation);
- fputs("ESPshowpage\n", doc->outputfp);
+ doc_puts(doc, "ESPshowpage\n");
}
}
}
*/
if (doc->use_ESPshowpage)
- fputs("userdict/showpage/ESPshowpage load put\n", doc->outputfp);
+ doc_puts(doc, "userdict/showpage/ESPshowpage load put\n");
}
if (doc->number_up > 1)
{
- fprintf(doc->outputfp, "%%%%Page: (%d) %d\n", doc->page, doc->page);
- fprintf(doc->outputfp, "%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
+ doc_printf(doc, "%%%%Page: (%d) %d\n", doc->page, doc->page);
+ doc_printf(doc, "%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
doc->PageLeft, doc->PageBottom, doc->PageRight, doc->PageTop);
}
else
{
- fprintf(doc->outputfp, "%%%%Page: %s %d\n", pageinfo->label, doc->page);
- fprintf(doc->outputfp, "%%%%PageBoundingBox: %d %d %d %d\n",
+ doc_printf(doc, "%%%%Page: %s %d\n", pageinfo->label, doc->page);
+ doc_printf(doc, "%%%%PageBoundingBox: %d %d %d %d\n",
pageinfo->bounding_box[0], pageinfo->bounding_box[1],
pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
}
(void)ppd;
- fputs("%%Trailer\n", doc->outputfp);
+ doc_puts(doc, "%%Trailer\n");
while (linelen > 0)
{
else if (strncmp(line, "%%Trailer", 9) &&
strncmp(line, "%%Pages:", 8) &&
strncmp(line, "%%BoundingBox:", 14))
- fwrite(line, 1, (size_t)linelen, doc->outputfp);
+ doc_write(doc, line, (size_t)linelen);
linelen = (ssize_t)cupsFileGetLine(doc->inputfp, line, linesize);
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterPSToPS: Wrote %d pages...", number);
- fprintf(doc->outputfp, "%%%%Pages: %d\n", number);
+ doc_printf(doc, "%%%%Pages: %d\n", number);
if (doc->number_up > 1 || doc->fit_to_page)
- fprintf(doc->outputfp, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
+ doc_printf(doc, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
doc->PageLeft, doc->PageBottom, doc->PageRight, doc->PageTop);
else
- fprintf(doc->outputfp, "%%%%BoundingBox: %d %d %d %d\n",
+ doc_printf(doc, "%%%%BoundingBox: %d %d %d %d\n",
doc->new_bounding_box[0], doc->new_bounding_box[1],
doc->new_bounding_box[2], doc->new_bounding_box[3]);
* Make sure we have rectclip and rectstroke procedures of some sort...
*/
- doc_puts(doc,
- "% x y w h ESPrc - Clip to a rectangle.\n"
- "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
- "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
- "neg 0 rlineto closepath clip newpath}bind}ifelse put\n");
-
- doc_puts(doc,
- "% x y w h ESPrf - Fill a rectangle.\n"
- "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
- "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
- "neg 0 rlineto closepath fill grestore}bind}ifelse put\n");
-
- doc_puts(doc,
- "% x y w h ESPrs - Stroke a rectangle.\n"
- "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
- "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
- "neg 0 rlineto closepath stroke grestore}bind}ifelse put\n");
+ write_common(doc);
/*
* Write the page and label prologs...
}
+/*
+ * 'doc_putc()' - Send a single character to the output file and/or the
+ * temp file.
+ *
+ * This function should be used for all page-level output that is affected
+ * by ordering, collation, etc.
+ */
+
+static void
+doc_putc(pstops_doc_t *doc, /* I - Document information */
+ const char c) /* I - Character to send */
+{
+ doc_write(doc, &c, 1);
+}
+
+
/*
* 'doc_puts()' - Send a nul-terminated string to the output file and/or the
* temp file.
}
+/*
+ * 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
+ */
+
+static void
+ps_hex(pstops_doc_t *doc,
+ cf_ib_t *data, /* I - Data to print */
+ int length, /* I - Number of bytes to print */
+ int last_line) /* I - Last line of raster data? */
+{
+ static int col = 0; /* Current column */
+ static char *hex = "0123456789ABCDEF";
+ /* Hex digits */
+
+
+ while (length > 0)
+ {
+ /*
+ * Put the hex chars out to the file; note that we don't use fprintf()
+ * for speed reasons...
+ */
+
+ doc_putc(doc, hex[*data >> 4]);
+ doc_putc(doc, hex[*data & 15]);
+
+ data ++;
+ length --;
+
+ col += 2;
+ if (col > 78)
+ {
+ doc_putc(doc, '\n');
+ col = 0;
+ }
+ }
+
+ if (last_line && col)
+ {
+ doc_putc(doc, '\n');
+ col = 0;
+ }
+}
+
+
+/*
+ * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
+ */
+
+static void
+ps_ascii85(pstops_doc_t *doc,
+ cf_ib_t *data, /* I - Data to print */
+ int length, /* I - Number of bytes to print */
+ int last_line) /* I - Last line of raster data? */
+{
+ unsigned b; /* Binary data word */
+ unsigned char c[5]; /* ASCII85 encoded chars */
+ static int col = 0; /* Current column */
+
+
+ while (length > 3)
+ {
+ b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
+
+ if (b == 0)
+ {
+ doc_putc(doc, 'z');
+ col ++;
+ }
+ else
+ {
+ c[4] = (b % 85) + '!';
+ b /= 85;
+ c[3] = (b % 85) + '!';
+ b /= 85;
+ c[2] = (b % 85) + '!';
+ b /= 85;
+ c[1] = (b % 85) + '!';
+ b /= 85;
+ c[0] = b + '!';
+
+ doc_write(doc, (const char *)c, 5);
+ col += 5;
+ }
+
+ data += 4;
+ length -= 4;
+
+ if (col >= 75)
+ {
+ doc_putc(doc, '\n');
+ col = 0;
+ }
+ }
+
+ if (last_line)
+ {
+ if (length > 0)
+ {
+ memset(data + length, 0, 4 - length);
+ b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
+
+ c[4] = (b % 85) + '!';
+ b /= 85;
+ c[3] = (b % 85) + '!';
+ b /= 85;
+ c[2] = (b % 85) + '!';
+ b /= 85;
+ c[1] = (b % 85) + '!';
+ b /= 85;
+ c[0] = b + '!';
+
+ doc_write(doc, (const char *)c, length + 1);
+ }
+
+ doc_puts(doc, "~>\n");
+ col = 0;
+ }
+}
+
+
/*
* 'set_pstops_options()' - Set pstops options.
*/
/* Set some common values */
cfFilterSetCommonOptions(ppd, num_options, options, 1,
&doc->Orientation, &doc->Duplex,
- &doc->LanguageLevel, &doc->ColorDevice,
+ &doc->LanguageLevel, &doc->Color,
&doc->PageLeft, &doc->PageRight,
&doc->PageTop, &doc->PageBottom,
&doc->PageWidth, &doc->PageLength,
}
+/*
+ * 'write_common()' - Write common procedures...
+ */
+
+void
+write_common(pstops_doc_t *doc)
+{
+ doc_puts(doc,
+ "% x y w h ESPrc - Clip to a rectangle.\n"
+ "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
+ "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+ "neg 0 rlineto closepath clip newpath}bind}ifelse put\n");
+ doc_puts(doc,
+ "% x y w h ESPrf - Fill a rectangle.\n"
+ "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
+ "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+ "neg 0 rlineto closepath fill grestore}bind}ifelse put\n");
+ doc_puts(doc,
+ "% x y w h ESPrs - Stroke a rectangle.\n"
+ "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
+ "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+ "neg 0 rlineto closepath stroke grestore}bind}ifelse put\n");
+}
+
+
/*
* 'write_label_prolog()' - Write the prolog with the classification
* and page label.
length; /* Length of page */
- fputs("gsave\n", doc->outputfp);
+ doc_puts(doc, "gsave\n");
if ((orient ^ doc->Orientation) & 1)
{
switch (orient & 3)
{
case 1 : /* Landscape */
- fprintf(doc->outputfp, "%.1f 0.0 translate 90 rotate\n", length);
+ doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", length);
break;
case 2 : /* Reverse Portrait */
- fprintf(doc->outputfp, "%.1f %.1f translate 180 rotate\n",
+ doc_printf(doc, "%.1f %.1f translate 180 rotate\n",
width, length);
break;
case 3 : /* Reverse Landscape */
- fprintf(doc->outputfp, "0.0 %.1f translate -90 rotate\n", width);
+ doc_printf(doc, "0.0 %.1f translate -90 rotate\n", width);
break;
}
- fputs("ESPwl\n", doc->outputfp);
- fputs("grestore\n", doc->outputfp);
+ doc_puts(doc, "ESPwl\n");
+ doc_puts(doc, "grestore\n");
}
* in the Adobe Document Structuring Conventions specification.
*/
- fprintf(doc->outputfp, "%%%%%s: (", name);
+ doc_printf(doc, "%%%%%s: (", name);
len = 5 + strlen(name);
while (*value)
if (len >= 251) /* Keep line < 254 chars */
break;
- fprintf(doc->outputfp, "\\%03o", *value & 255);
+ doc_printf(doc, "\\%03o", *value & 255);
len += 4;
}
else if (*value == '\\')
if (len >= 253) /* Keep line < 254 chars */
break;
- fputc('\\', doc->outputfp);
- fputc('\\', doc->outputfp);
+ doc_putc(doc, '\\');
+ doc_putc(doc, '\\');
len += 2;
}
else
if (len >= 254) /* Keep line < 254 chars */
break;
- fputc(*value, doc->outputfp);
+ doc_putc(doc, *value);
len ++;
}
value ++;
}
- fputs(")\n", doc->outputfp);
+ doc_puts(doc, ")\n");
}
+++ /dev/null
-/*
- * Image file to PostScript filter function for cups-filters.
- *
- * Copyright 2007-2011 by Apple Inc.
- * Copyright 1993-2007 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * cfFilterImageToPS() - imagetops filter function
- * WriteCommon() - Write common procedures...
- * WriteLabelProlog() - Write the prolog with the classification
- * and page label.
- * WriteLabels() - Write the actual page labels.
- * WriteTextComment() - Write a DSC comment.
- * ps_hex() - Print binary data as a series of hexadecimal numbers.
- * ps_ascii85() - Print binary data as a series of base-85 numbers.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include <cupsfilters/filter.h>
-#include <cupsfilters/image.h>
-#include <cupsfilters/raster.h>
-#include <cupsfilters/image-private.h>
-#include <math.h>
-#include <signal.h>
-#include <string.h>
-#include <errno.h>
-
-
-/*
- * Types...
- */
-
-typedef struct { /**** Document information ****/
- int Orientation, /* 0 = portrait, 1 = landscape, etc. */
- Duplex, /* Duplexed? */
- LanguageLevel, /* Language level of printer */
- Color; /* Print in color? */
- float PageLeft, /* Left margin */
- PageRight, /* Right margin */
- PageBottom, /* Bottom margin */
- PageTop, /* Top margin */
- PageWidth, /* Total page width */
- PageLength; /* Total page length */
- FILE *outputfp;
-} imagetops_doc_t;
-
-
-/*
- * Local functions...
- */
-
-static void WriteCommon(imagetops_doc_t *doc);
-static void WriteLabelProlog(imagetops_doc_t *doc,
- const char *label, float bottom,
- float top, float width);
-static void WriteLabels(imagetops_doc_t *doc, int orient);
-static void WriteTextComment(imagetops_doc_t *doc,
- const char *name, const char *value);
-static void ps_hex(FILE *outputfp, cf_ib_t *, int, int);
-static void ps_ascii85(FILE *outputfp, cf_ib_t *, int, int);
-
-
-/*
- * 'cfFilterImageToPS()' - Filter function to convert many common image file
- * formats into PostScript
- */
-
-int /* O - Error status */
-cfFilterImageToPS(int inputfd, /* I - File descriptor input stream */
- int outputfd, /* I - File descriptor output stream */
- int inputseekable, /* I - Is input stream seekable? (unused) */
- cf_filter_data_t *data, /* I - Job and printer data */
- void *parameters) /* I - Filter-specific parameters (unused) */
-{
- imagetops_doc_t doc; /* Document information */
- cf_image_t *img; /* Image to print */
- float xprint, /* Printable area */
- yprint,
- xinches, /* Total size in inches */
- yinches;
- float xsize, /* Total size in points */
- ysize,
- xsize2,
- ysize2;
- float aspect; /* Aspect ratio */
- int xpages, /* # x pages */
- ypages, /* # y pages */
- xpage, /* Current x page */
- ypage, /* Current y page */
- page; /* Current page number */
- int xc0, yc0, /* Corners of the page in image coords */
- xc1, yc1;
- cf_ib_t *row; /* Current row */
- int y; /* Current Y coordinate in image */
- int colorspace; /* Output colorspace */
- int out_offset, /* Offset into output buffer */
- out_length; /* Length of output buffer */
- ppd_file_t *ppd; /* PPD file */
- ppd_choice_t *choice; /* PPD option choice */
- int num_options; /* Number of print options */
- cups_option_t *options; /* Print options */
- const char *val; /* Option value */
- int slowcollate; /* Collate copies the slow way */
- float g; /* Gamma correction value */
- float b; /* Brightness factor */
- float zoom; /* Zoom facter */
- int xppi, yppi; /* Pixels-per-inch */
- int hue, sat; /* Hue and saturation adjustment */
- int realcopies, /* Real copies being printed */
- emit_jcl; /* Emit JCL? */
- float left, top; /* Left and top of image */
- time_t curtime; /* Current time */
- struct tm *curtm; /* Current date */
- char curdate[255]; /* Current date string */
- int fillprint = 0; /* print-scaling = fill */
- int cropfit = 0; /* -o crop-to-fit = true */
- cups_page_header2_t h; /* CUPS Raster page header, to */
- /* accommodate results of command */
- /* line parsing for PPD-less queue */
- int Flip, /* Flip/mirror pages */
- XPosition, /* Horizontal position on page */
- YPosition, /* Vertical position on page */
- Collate, /* Collate copies? */
- Copies; /* Number of copies */
- char tempfile[1024]; /* Name of file to print */
- FILE *inputfp; /* Input file */
- int fd; /* File descriptor for temp file */
- char buf[BUFSIZ];
- int bytes;
- cf_logfunc_t log = data->logfunc;
- void *ld = data->logdata;
- cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
- void *icd = data->iscanceleddata;
-
-
- /*
- * Make sure status messages are not buffered...
- */
-
- setbuf(stderr, NULL);
-
- /*
- * Ignore broken pipe signals...
- */
-
- signal(SIGPIPE, SIG_IGN);
-
- /*
- * Initialize data structure
- */
-
- Flip = 0;
- XPosition = 0;
- YPosition = 0;
- Collate = 0;
- Copies = 1;
-
- /*
- * Open the input data stream specified by the inputfd ...
- */
-
- if ((inputfp = fdopen(inputfd, "r")) == NULL)
- {
- if (!iscanceled || !iscanceled(icd))
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Unable to open input data stream.");
- }
-
- return (1);
- }
-
- /*
- * Copy input into temporary file if needed ...
- */
-
- if (!inputseekable) {
- if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Unable to copy input: %s",
- strerror(errno));
- return (1);
- }
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Copying input to temp file \"%s\"",
- tempfile);
-
- while ((bytes = fread(buf, 1, sizeof(buf), inputfp)) > 0)
- bytes = write(fd, buf, bytes);
-
- fclose(inputfp);
- close(fd);
-
- /*
- * Open the temporary file to read it instead of the original input ...
- */
-
- if ((inputfp = fopen(tempfile, "r")) == NULL)
- {
- if (!iscanceled || !iscanceled(icd))
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Unable to open temporary file.");
- }
-
- unlink(tempfile);
- return (1);
- }
- }
-
- /*
- * Open the output data stream specified by the outputfd...
- */
-
- if ((doc.outputfp = fdopen(outputfd, "w")) == NULL)
- {
- if (!iscanceled || !iscanceled(icd))
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Unable to open output data stream.");
- }
-
- fclose(inputfp);
-
- if (!inputseekable)
- unlink(tempfile);
- return (1);
- }
-
- /*
- * Process command-line options and write the prolog...
- */
-
- zoom = 1.0;
- xppi = 0;
- yppi = 0;
- hue = 0;
- sat = 100;
- g = 1.0;
- b = 1.0;
-
- Copies = data->copies;
-
- /*
- * Option list...
- */
-
- options = data->options;
- num_options = data->num_options;
-
- /*
- * Process job options...
- */
-
- ppd = data->ppd;
- cfFilterSetCommonOptions(ppd, num_options, options, 0,
- &doc.Orientation, &doc.Duplex,
- &doc.LanguageLevel, &doc.Color,
- &doc.PageLeft, &doc.PageRight,
- &doc.PageTop, &doc.PageBottom,
- &doc.PageWidth, &doc.PageLength,
- log, ld);
-
- /* The cfFilterSetCommonOptions() does not set doc.Color
- according to option settings (user's demand for color/gray),
- so we parse the options and set the mode here */
- cfRasterParseIPPOptions(&h, data, 0, 1);
- if (doc.Color)
- doc.Color = h.cupsNumColors <= 1 ? 0 : 1;
- if (!ppd) {
- /* Without PPD use also the other findings of cfRasterParseIPPOptions() */
- doc.Orientation = h.Orientation;
- doc.Duplex = h.Duplex;
- doc.LanguageLevel = 2;
- doc.PageWidth = h.cupsPageSize[0] != 0.0 ? h.cupsPageSize[0] :
- (float)h.PageSize[0];
- doc.PageLength = h.cupsPageSize[1] != 0.0 ? h.cupsPageSize[1] :
- (float)h.PageSize[1];
- doc.PageLeft = h.cupsImagingBBox[0] != 0.0 ? h.cupsImagingBBox[0] :
- (float)h.ImagingBoundingBox[0];
- doc.PageBottom = h.cupsImagingBBox[1] != 0.0 ? h.cupsImagingBBox[1] :
- (float)h.ImagingBoundingBox[1];
- doc.PageRight = h.cupsImagingBBox[2] != 0.0 ? h.cupsImagingBBox[2] :
- (float)h.ImagingBoundingBox[2];
- doc.PageTop = h.cupsImagingBBox[3] != 0.0 ? h.cupsImagingBBox[3] :
- (float)h.ImagingBoundingBox[3];
- Flip = h.MirrorPrint ? 1 : 0;
- Collate = h.Collate ? 1 : 0;
- Copies = h.NumCopies;
- }
-
- if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
- {
- /*
- * This IPP attribute is unnecessarily complicated...
- *
- * single-document, separate-documents-collated-copies, and
- * single-document-new-sheet all require collated copies.
- *
- * separate-documents-uncollated-copies allows for uncollated copies.
- */
-
- Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
- }
-
- if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
- strcasecmp(val, "True") == 0)
- Collate = 1;
-
- if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
- {
- /*
- * Get gamma value from 1 to 10000...
- */
-
- g = atoi(val) * 0.001f;
-
- if (g < 0.001f)
- g = 0.001f;
- else if (g > 10.0f)
- g = 10.0f;
- }
-
- if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
- {
- /*
- * Get brightness value from 10 to 1000.
- */
-
- b = atoi(val) * 0.01f;
-
- if (b < 0.1f)
- b = 0.1f;
- else if (b > 10.0f)
- b = 10.0f;
- }
-
- if ((val = cupsGetOption("ppi", num_options, options)) != NULL)
- {
- sscanf(val, "%d", &xppi);
- yppi = xppi;
- zoom = 0.0;
- }
-
- if ((val = cupsGetOption("position", num_options, options)) != NULL)
- {
- if (strcasecmp(val, "center") == 0)
- {
- XPosition = 0;
- YPosition = 0;
- }
- else if (strcasecmp(val, "top") == 0)
- {
- XPosition = 0;
- YPosition = 1;
- }
- else if (strcasecmp(val, "left") == 0)
- {
- XPosition = -1;
- YPosition = 0;
- }
- else if (strcasecmp(val, "right") == 0)
- {
- XPosition = 1;
- YPosition = 0;
- }
- else if (strcasecmp(val, "top-left") == 0)
- {
- XPosition = -1;
- YPosition = 1;
- }
- else if (strcasecmp(val, "top-right") == 0)
- {
- XPosition = 1;
- YPosition = 1;
- }
- else if (strcasecmp(val, "bottom") == 0)
- {
- XPosition = 0;
- YPosition = -1;
- }
- else if (strcasecmp(val, "bottom-left") == 0)
- {
- XPosition = -1;
- YPosition = -1;
- }
- else if (strcasecmp(val, "bottom-right") == 0)
- {
- XPosition = 1;
- YPosition = -1;
- }
- }
-
- if ((val = cupsGetOption("saturation", num_options, options)) != NULL)
- sat = atoi(val);
-
- if ((val = cupsGetOption("hue", num_options, options)) != NULL)
- hue = atoi(val);
-
- if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
- {
- val = choice->choice;
- choice->marked = 0;
- }
- else
- val = cupsGetOption("mirror", num_options, options);
-
- if (val && (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
- !strcasecmp(val, "yes")))
- Flip = 1;
-
- if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
- (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
- !strcasecmp(val, "no") || !strcmp(val, "0")))
- emit_jcl = 0;
- else
- emit_jcl = 1;
-
- /*
- * Open the input image to print...
- */
-
- colorspace = doc.Color ? CF_IMAGE_RGB_CMYK : CF_IMAGE_WHITE;
-
- img = cfImageOpenFP(inputfp, colorspace, CF_IMAGE_WHITE, sat, hue, NULL);
- if (img != NULL) {
-
- int margin_defined = 0;
- int fidelity = 0;
- int document_large = 0;
-
- if (ppd && (ppd->custom_margins[0] || ppd->custom_margins[1] ||
- ppd->custom_margins[2] || ppd->custom_margins[3]))
- /* In case of custom margins */
- margin_defined = 1;
- if (doc.PageLength != doc.PageTop - doc.PageBottom ||
- doc.PageWidth != doc.PageRight - doc.PageLeft)
- margin_defined = 1;
-
- if((val = cupsGetOption("ipp-attribute-fidelity", num_options, options))
- != NULL)
- {
- if(!strcasecmp(val, "true") || !strcasecmp(val, "yes") ||
- !strcasecmp(val, "on")) {
- fidelity = 1;
- }
- }
-
- float w = (float)cfImageGetWidth(img);
- float h = (float)cfImageGetHeight(img);
- float pw = doc.PageRight - doc.PageLeft;
- float ph = doc.PageTop - doc.PageBottom;
- int tempOrientation = doc.Orientation;
- if ((val = cupsGetOption("orientation-requested", num_options, options)) !=
- NULL)
- tempOrientation = atoi(val);
- else if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
- {
- if(!strcasecmp(val, "true") || !strcasecmp(val, "yes"))
- tempOrientation = 4;
- }
- if (tempOrientation == 0) {
- if (((pw > ph) && (w < h)) || ((pw < ph) && (w > h)))
- tempOrientation = 4;
- }
- if (tempOrientation == 4 || tempOrientation == 5)
- {
- int tmp = pw;
- pw = ph;
- ph = tmp;
- }
- if (w * 72.0 / img->xppi > pw || h * 72.0 / img->yppi > ph)
- document_large = 1;
-
- if ((val = cupsGetOption("print-scaling", num_options, options)) != NULL)
- {
- if (!strcasecmp(val, "auto"))
- {
- if (fidelity || document_large) {
- if (margin_defined)
- zoom = 1.0; // fit method
- else
- fillprint = 1; // fill method
- }
- else
- cropfit = 1; // none method
- }
- else if (!strcasecmp(val, "auto-fit"))
- {
- if (fidelity || document_large)
- zoom = 1.0; // fit method
- else
- cropfit = 1; // none method
- }
- else if (!strcasecmp(val, "fill"))
- fillprint = 1; // fill method
- else if (!strcasecmp(val, "fit"))
- zoom = 1.0; // fitplot = 1 or fit method
- else
- cropfit = 1; // none or crop-to-fit
- }
- else
- { // print-scaling is not defined, look for alternate options.
- if ((val = cupsGetOption("scaling", num_options, options)) != NULL)
- zoom = atoi(val) * 0.01;
- else if (((val =
- cupsGetOption("fit-to-page", num_options, options)) != NULL) ||
- ((val = cupsGetOption("fitplot", num_options, options)) != NULL))
- {
- if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
- !strcasecmp(val, "true"))
- zoom = 1.0;
- else
- zoom = 0.0;
- }
- else if ((val = cupsGetOption("natural-scaling", num_options, options)) !=
- NULL)
- zoom = 0.0;
-
- if ((val = cupsGetOption("fill", num_options,options)) != NULL)
- {
- if (!strcasecmp(val, "true") || !strcasecmp(val, "yes"))
- fillprint = 1;
- }
-
- if ((val = cupsGetOption("crop-to-fit", num_options,options)) != NULL)
- {
- if (!strcasecmp(val, "true") || !strcasecmp(val, "yes"))
- cropfit=1;
- }
- }
- if (fillprint || cropfit)
- {
- /* For cropfit do the math without the unprintable margins to get correct
- centering */
- if (cropfit)
- {
- pw = doc.PageWidth;
- ph = doc.PageLength;
- doc.PageBottom = 0.0;
- doc.PageTop = doc.PageLength;
- doc.PageLeft = 0.0;
- doc.PageRight = doc.PageWidth;
- }
- tempOrientation = doc.Orientation;
- int flag = 3;
- if ((val = cupsGetOption("orientation-requested", num_options,
- options)) != NULL)
- tempOrientation = atoi(val);
- else if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
- {
- if (!strcasecmp(val,"true") || !strcasecmp(val,"yes"))
- tempOrientation = 4;
- }
- if (tempOrientation > 0)
- {
- if (tempOrientation == 4 || tempOrientation == 5)
- {
- float temp = pw;
- pw = ph;
- ph = temp;
- flag = 4;
- }
- }
- if (tempOrientation==0)
- {
- if (((pw > ph) && (w < h)) || ((pw < ph) && (w > h)))
- {
- int temp = pw;
- pw = ph;
- ph = temp;
- flag = 4;
- }
- }
- if (fillprint) {
- float final_w, final_h;
- if (w * ph / pw <= h) {
- final_w = w;
- final_h = w * ph / pw;
- }
- else
- {
- final_w = h * pw / ph;
- final_h = h;
- }
- float posw = (w - final_w) / 2, posh = (h - final_h) / 2;
- posw = (1 + XPosition) * posw;
- posh = (1 - YPosition) * posh;
- cf_image_t *img2 = cfImageCrop(img, posw, posh, final_w, final_h);
- cfImageClose(img);
- img = img2;
- }
- else
- {
- float final_w = w, final_h = h;
- if (w > pw * img->xppi / 72.0)
- final_w = pw * img->xppi / 72.0;
- if (h > ph * img->yppi / 72.0)
- final_h = ph * img->yppi / 72.0;
- float posw = (w - final_w) / 2, posh = (h - final_h) / 2;
- posw = (1 + XPosition) * posw;
- posh = (1 - YPosition) * posh;
- cf_image_t *img2 = cfImageCrop(img, posw, posh, final_w, final_h);
- cfImageClose(img);
- img = img2;
- if (flag == 4)
- {
- doc.PageBottom += (doc.PageLength - final_w * 72.0 / img->xppi) / 2;
- doc.PageTop = doc.PageBottom + final_w * 72.0 / img->xppi;
- doc.PageLeft += (doc.PageWidth - final_h * 72.0 / img->yppi) / 2;
- doc.PageRight = doc.PageLeft + final_h * 72.0 / img->yppi;
- }
- else
- {
- doc.PageBottom += (doc.PageLength - final_h * 72.0 / img->yppi) / 2;
- doc.PageTop = doc.PageBottom + final_h * 72.0 / img->yppi;
- doc.PageLeft += (doc.PageWidth - final_w * 72.0 / img->xppi) / 2;
- doc.PageRight = doc.PageLeft + final_w * 72.0 / img->xppi;
- }
- if (doc.PageBottom < 0) doc.PageBottom = 0;
- if (doc.PageLeft < 0) doc.PageLeft = 0;
- }
- }
- }
-
- if (!inputseekable)
- unlink(tempfile);
-
- if (img == NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: The print file could not be opened - %s",
- strerror(errno));
- return (1);
- }
-
- colorspace = cfImageGetColorSpace(img);
-
- /*
- * Scale as necessary...
- */
-
- if (zoom == 0.0 && xppi == 0)
- {
- xppi = cfImageGetXPPI(img);
- yppi = cfImageGetYPPI(img);
- }
-
- if (yppi == 0)
- yppi = xppi;
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Before scaling: xppi=%d, yppi=%d, zoom=%.2f",
- xppi, yppi, zoom);
-
- if (xppi > 0)
- {
- /*
- * Scale the image as neccesary to match the desired pixels-per-inch.
- */
-
- if (doc.Orientation & 1)
- {
- xprint = (doc.PageTop - doc.PageBottom) / 72.0;
- yprint = (doc.PageRight - doc.PageLeft) / 72.0;
- }
- else
- {
- xprint = (doc.PageRight - doc.PageLeft) / 72.0;
- yprint = (doc.PageTop - doc.PageBottom) / 72.0;
- }
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
- xprint, yprint);
-
- xinches = (float)cfImageGetWidth(img) / (float)xppi;
- yinches = (float)cfImageGetHeight(img) / (float)yppi;
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Image size is %.1f x %.1f inches...",
- xinches, yinches);
-
- if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
- {
- xinches = xinches * atoi(val) / 100;
- yinches = yinches * atoi(val) / 100;
- }
-
- if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
- cupsGetOption("landscape", num_options, options) == NULL)
- {
- /*
- * Rotate the image if it will fit landscape but not portrait...
- */
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Auto orientation...");
-
- if ((xinches > xprint || yinches > yprint) &&
- xinches <= yprint && yinches <= xprint)
- {
- /*
- * Rotate the image as needed...
- */
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using landscape orientation...");
-
- doc.Orientation = (doc.Orientation + 1) & 3;
- xsize = yprint;
- yprint = xprint;
- xprint = xsize;
- }
- }
- }
- else
- {
- /*
- * Scale percentage of page size...
- */
-
- xprint = (doc.PageRight - doc.PageLeft) / 72.0;
- yprint = (doc.PageTop - doc.PageBottom) / 72.0;
- aspect = (float)cfImageGetYPPI(img) / (float)cfImageGetXPPI(img);
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
- xprint, yprint);
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: cfImageGetXPPI(img) = %d, "
- "cfImageGetYPPI(img) = %d, aspect = %f",
- cfImageGetXPPI(img), cfImageGetYPPI(img), aspect);
-
- xsize = xprint * zoom;
- ysize = xsize * cfImageGetHeight(img) / cfImageGetWidth(img) / aspect;
-
- if (ysize > (yprint * zoom))
- {
- ysize = yprint * zoom;
- xsize = ysize * cfImageGetWidth(img) * aspect /
- cfImageGetHeight(img);
- }
-
- xsize2 = yprint * zoom;
- ysize2 = xsize2 * cfImageGetHeight(img) / cfImageGetWidth(img) /
- aspect;
-
- if (ysize2 > (xprint * zoom))
- {
- ysize2 = xprint * zoom;
- xsize2 = ysize2 * cfImageGetWidth(img) * aspect /
- cfImageGetHeight(img);
- }
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Portrait size is %.2f x %.2f inches",
- xsize, ysize);
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Landscape size is %.2f x %.2f inches",
- xsize2, ysize2);
-
- if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
- cupsGetOption("landscape", num_options, options) == NULL)
- {
- /*
- * Choose the rotation with the largest area, but prefer
- * portrait if they are equal...
- */
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Auto orientation...");
-
- if ((xsize * ysize) < (xsize2 * xsize2))
- {
- /*
- * Do landscape orientation...
- */
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using landscape orientation...");
-
- doc.Orientation = 1;
- xinches = xsize2;
- yinches = ysize2;
- xprint = (doc.PageTop - doc.PageBottom) / 72.0;
- yprint = (doc.PageRight - doc.PageLeft) / 72.0;
- }
- else
- {
- /*
- * Do portrait orientation...
- */
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using portrait orientation...");
-
- doc.Orientation = 0;
- xinches = xsize;
- yinches = ysize;
- }
- }
- else if (doc.Orientation & 1)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using landscape orientation...");
-
- xinches = xsize2;
- yinches = ysize2;
- xprint = (doc.PageTop - doc.PageBottom) / 72.0;
- yprint = (doc.PageRight - doc.PageLeft) / 72.0;
- }
- else
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using portrait orientation...");
-
- xinches = xsize;
- yinches = ysize;
- xprint = (doc.PageRight - doc.PageLeft) / 72.0;
- yprint = (doc.PageTop - doc.PageBottom) / 72.0;
- }
- }
-
- /*
- * Compute the number of pages to print and the size of the image on each
- * page...
- */
-
- xpages = ceil(xinches / xprint);
- ypages = ceil(yinches / yprint);
-
- xprint = xinches / xpages;
- yprint = yinches / ypages;
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: xpages = %dx%.2fin, ypages = %dx%.2fin",
- xpages, xprint, ypages, yprint);
-
- /*
- * Update the page size for custom sizes...
- */
-
- if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
- strcasecmp(choice->choice, "Custom") == 0)
- {
- float width, /* New width in points */
- length; /* New length in points */
- char s[255]; /* New custom page size... */
-
-
- /*
- * Use the correct width and length for the current orientation...
- */
-
- if (doc.Orientation & 1)
- {
- width = yprint * 72.0;
- length = xprint * 72.0;
- }
- else
- {
- width = xprint * 72.0;
- length = yprint * 72.0;
- }
-
- /*
- * Add margins to page size...
- */
-
- width += ppd->custom_margins[0] + ppd->custom_margins[2];
- length += ppd->custom_margins[1] + ppd->custom_margins[3];
-
- /*
- * Enforce minimums...
- */
-
- if (width < ppd->custom_min[0])
- width = ppd->custom_min[0];
-
- if (length < ppd->custom_min[1])
- length = ppd->custom_min[1];
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Updated custom page size to %.2f x %.2f inches...",
- width / 72.0, length / 72.0);
-
- /*
- * Set the new custom size...
- */
-
- sprintf(s, "Custom.%.0fx%.0f", width, length);
- ppdMarkOption(ppd, "PageSize", s);
-
- /*
- * Update page variables...
- */
-
- doc.PageWidth = width;
- doc.PageLength = length;
- doc.PageLeft = ppd->custom_margins[0];
- doc.PageRight = width - ppd->custom_margins[2];
- doc.PageBottom = ppd->custom_margins[1];
- doc.PageTop = length - ppd->custom_margins[3];
- }
-
- /*
- * See if we need to collate, and if so how we need to do it...
- */
-
- if (xpages == 1 && ypages == 1)
- Collate = 0;
-
- slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL;
-
- if (Copies > 1 && !slowcollate)
- {
- realcopies = Copies;
- Copies = 1;
- }
- else
- realcopies = 1;
-
- /*
- * Write any "exit server" options that have been selected...
- */
-
- ppdEmit(ppd, doc.outputfp, PPD_ORDER_EXIT);
-
- /*
- * Write any JCL commands that are needed to print PostScript code...
- */
-
- if (emit_jcl)
- ppdEmitJCL(ppd, doc.outputfp, data->job_id, data->job_user,
- data->job_title);
-
- /*
- * Start sending the document with any commands needed...
- */
-
- curtime = time(NULL);
- curtm = localtime(&curtime);
-
- fputs("%!PS-Adobe-3.0\n", doc.outputfp);
- fprintf(doc.outputfp, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
- doc.PageLeft, doc.PageBottom, doc.PageRight, doc.PageTop);
- fprintf(doc.outputfp, "%%%%LanguageLevel: %d\n", doc.LanguageLevel);
- fprintf(doc.outputfp, "%%%%Pages: %d\n", xpages * ypages * Copies);
- fputs("%%DocumentData: Clean7Bit\n", doc.outputfp);
- fputs("%%DocumentNeededResources: font Helvetica-Bold\n", doc.outputfp);
- fputs("%%Creator: imagetops\n", doc.outputfp);
- strftime(curdate, sizeof(curdate), "%c", curtm);
- fprintf(doc.outputfp, "%%%%CreationDate: %s\n", curdate);
- WriteTextComment(&doc, "Title", data->job_title);
- WriteTextComment(&doc, "For", data->job_user);
- if (doc.Orientation & 1)
- fputs("%%Orientation: Landscape\n", doc.outputfp);
- else
- fputs("%%Orientation: Portrait\n", doc.outputfp);
- fputs("%%EndComments\n", doc.outputfp);
- fputs("%%BeginProlog\n", doc.outputfp);
-
- if (ppd != NULL && ppd->patches != NULL)
- {
- fputs(ppd->patches, doc.outputfp);
- fputc('\n', doc.outputfp);
- }
-
- ppdEmit(ppd, doc.outputfp, PPD_ORDER_DOCUMENT);
- ppdEmit(ppd, doc.outputfp, PPD_ORDER_ANY);
- ppdEmit(ppd, doc.outputfp, PPD_ORDER_PROLOG);
-
- if (g != 1.0 || b != 1.0)
- fprintf(doc.outputfp,
- "{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
- "ifelse %.3f mul } bind settransfer\n", g, b);
-
- WriteCommon(&doc);
- switch (doc.Orientation)
- {
- case 0 :
- WriteLabelProlog(&doc, cupsGetOption("page-label", num_options,
- options),
- doc.PageBottom, doc.PageTop, doc.PageWidth);
- break;
-
- case 1 :
- WriteLabelProlog(&doc, cupsGetOption("page-label", num_options,
- options),
- doc.PageLeft, doc.PageRight, doc.PageLength);
- break;
-
- case 2 :
- WriteLabelProlog(&doc, cupsGetOption("page-label", num_options,
- options),
- doc.PageLength - doc.PageTop,
- doc.PageLength - doc.PageBottom,
- doc.PageWidth);
- break;
-
- case 3 :
- WriteLabelProlog(&doc, cupsGetOption("page-label", num_options,
- options),
- doc.PageWidth - doc.PageRight,
- doc.PageWidth - doc.PageLeft,
- doc.PageLength);
- break;
- }
-
- if (realcopies > 1)
- {
- if (ppd == NULL || ppd->language_level == 1)
- fprintf(doc.outputfp, "/#copies %d def\n", realcopies);
- else
- fprintf(doc.outputfp, "<</NumCopies %d>>setpagedevice\n", realcopies);
- }
-
- fputs("%%EndProlog\n", doc.outputfp);
-
- /*
- * Output the pages...
- */
-
- row = malloc(cfImageGetWidth(img) * abs(colorspace) + 3);
- if (row == NULL)
- {
- log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Could not allocate memory.");
- cfImageClose(img);
- return (2);
- }
-
- if (log)
- {
- log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: XPosition=%d, YPosition=%d, Orientation=%d",
- XPosition, YPosition, doc.Orientation);
- log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: xprint=%.1f, yprint=%.1f", xprint, yprint);
- log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f",
- doc.PageLeft, doc.PageRight, doc.PageWidth);
- log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f",
- doc.PageBottom, doc.PageTop, doc.PageLength);
- }
-
- switch (doc.Orientation)
- {
- default :
- switch (XPosition)
- {
- case -1 :
- left = doc.PageLeft;
- break;
- default :
- left = (doc.PageRight + doc.PageLeft - xprint * 72) / 2;
- break;
- case 1 :
- left = doc.PageRight - xprint * 72;
- break;
- }
-
- switch (YPosition)
- {
- case -1 :
- top = doc.PageBottom + yprint * 72;
- break;
- default :
- top = (doc.PageTop + doc.PageBottom + yprint * 72) / 2;
- break;
- case 1 :
- top = doc.PageTop;
- break;
- }
- break;
-
- case 1 :
- switch (XPosition)
- {
- case -1 :
- left = doc.PageBottom;
- break;
- default :
- left = (doc.PageTop + doc.PageBottom - xprint * 72) / 2;
- break;
- case 1 :
- left = doc.PageTop - xprint * 72;
- break;
- }
-
- switch (YPosition)
- {
- case -1 :
- top = doc.PageLeft + yprint * 72;
- break;
- default :
- top = (doc.PageRight + doc.PageLeft + yprint * 72) / 2;
- break;
- case 1 :
- top = doc.PageRight;
- break;
- }
- break;
-
- case 2 :
- switch (XPosition)
- {
- case 1 :
- left = doc.PageLeft;
- break;
- default :
- left = (doc.PageRight + doc.PageLeft - xprint * 72) / 2;
- break;
- case -1 :
- left = doc.PageRight - xprint * 72;
- break;
- }
-
- switch (YPosition)
- {
- case 1 :
- top = doc.PageBottom + yprint * 72;
- break;
- default :
- top = (doc.PageTop + doc.PageBottom + yprint * 72) / 2;
- break;
- case -1 :
- top = doc.PageTop;
- break;
- }
- break;
-
- case 3 :
- switch (XPosition)
- {
- case 1 :
- left = doc.PageBottom;
- break;
- default :
- left = (doc.PageTop + doc.PageBottom - xprint * 72) / 2;
- break;
- case -1 :
- left = doc.PageTop - xprint * 72;
- break;
- }
-
- switch (YPosition)
- {
- case 1 :
- top = doc.PageLeft + yprint * 72;
- break;
- default :
- top = (doc.PageRight + doc.PageLeft + yprint * 72) / 2;
- break;
- case -1 :
- top = doc.PageRight;
- break;
- }
- break;
- }
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: left=%.2f, top=%.2f", left, top);
-
- for (page = 1; Copies > 0; Copies --)
- for (xpage = 0; xpage < xpages; xpage ++)
- for (ypage = 0; ypage < ypages; ypage ++, page ++)
- {
- if (iscanceled && iscanceled(icd))
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Job canceled");
- goto canceled;
- }
-
- if (log && ppd && ppd->num_filters == 0)
- log(ld, CF_LOGLEVEL_CONTROL,
- "PAGE: %d %d", page, realcopies);
-
- if (log) log(ld, CF_LOGLEVEL_INFO,
- "cfFilterImageToPS: Printing page %d.", page);
-
- fprintf(doc.outputfp, "%%%%Page: %d %d\n", page, page);
-
- ppdEmit(ppd, doc.outputfp, PPD_ORDER_PAGE);
-
- fputs("gsave\n", doc.outputfp);
-
- if (Flip)
- fprintf(doc.outputfp, "%.0f 0 translate -1 1 scale\n", doc.PageWidth);
-
- switch (doc.Orientation)
- {
- case 1 : /* Landscape */
- fprintf(doc.outputfp, "%.0f 0 translate 90 rotate\n",
- doc.PageWidth);
- break;
- case 2 : /* Reverse Portrait */
- fprintf(doc.outputfp, "%.0f %.0f translate 180 rotate\n",
- doc.PageWidth, doc.PageLength);
- break;
- case 3 : /* Reverse Landscape */
- fprintf(doc.outputfp, "0 %.0f translate -90 rotate\n",
- doc.PageLength);
- break;
- }
-
- fputs("gsave\n", doc.outputfp);
-
- xc0 = cfImageGetWidth(img) * xpage / xpages;
- xc1 = cfImageGetWidth(img) * (xpage + 1) / xpages - 1;
- yc0 = cfImageGetHeight(img) * ypage / ypages;
- yc1 = cfImageGetHeight(img) * (ypage + 1) / ypages - 1;
-
- fprintf(doc.outputfp, "%.1f %.1f translate\n", left, top);
-
- fprintf(doc.outputfp, "%.3f %.3f scale\n\n",
- xprint * 72.0 / (xc1 - xc0 + 1),
- yprint * 72.0 / (yc1 - yc0 + 1));
-
- if (doc.LanguageLevel == 1)
- {
- fprintf(doc.outputfp, "/picture %d string def\n",
- (xc1 - xc0 + 1) * abs(colorspace));
- fprintf(doc.outputfp, "%d %d 8[1 0 0 -1 0 1]",
- (xc1 - xc0 + 1), (yc1 - yc0 + 1));
-
- if (colorspace == CF_IMAGE_WHITE)
- fputs("{currentfile picture readhexstring pop} image\n",
- doc.outputfp);
- else
- fprintf(doc.outputfp,
- "{currentfile picture readhexstring pop} false %d "
- "colorimage\n",
- abs(colorspace));
-
- for (y = yc0; y <= yc1; y ++)
- {
- cfImageGetRow(img, xc0, y, xc1 - xc0 + 1, row);
- ps_hex(doc.outputfp, row, (xc1 - xc0 + 1) * abs(colorspace),
- y == yc1);
- }
- }
- else
- {
- switch (colorspace)
- {
- case CF_IMAGE_WHITE :
- fputs("/DeviceGray setcolorspace\n", doc.outputfp);
- break;
- case CF_IMAGE_RGB :
- fputs("/DeviceRGB setcolorspace\n", doc.outputfp);
- break;
- case CF_IMAGE_CMYK :
- fputs("/DeviceCMYK setcolorspace\n", doc.outputfp);
- break;
- }
-
- fprintf(doc.outputfp,
- "<<"
- "/ImageType 1"
- "/Width %d"
- "/Height %d"
- "/BitsPerComponent 8",
- xc1 - xc0 + 1, yc1 - yc0 + 1);
-
- switch (colorspace)
- {
- case CF_IMAGE_WHITE :
- fputs("/Decode[0 1]", doc.outputfp);
- break;
- case CF_IMAGE_RGB :
- fputs("/Decode[0 1 0 1 0 1]", doc.outputfp);
- break;
- case CF_IMAGE_CMYK :
- fputs("/Decode[0 1 0 1 0 1 0 1]", doc.outputfp);
- break;
- }
-
- fputs("\n/DataSource currentfile/ASCII85Decode filter", doc.outputfp);
-
- if (((xc1 - xc0 + 1) / xprint) < 100.0)
- fputs("/Interpolate true", doc.outputfp);
-
- fputs("/ImageMatrix[1 0 0 -1 0 1]>>image\n", doc.outputfp);
-
- for (y = yc0, out_offset = 0; y <= yc1; y ++)
- {
- cfImageGetRow(img, xc0, y, xc1 - xc0 + 1, row + out_offset);
-
- out_length = (xc1 - xc0 + 1) * abs(colorspace) + out_offset;
- out_offset = out_length & 3;
-
- ps_ascii85(doc.outputfp, row, out_length, y == yc1);
-
- if (out_offset > 0)
- memcpy(row, row + out_length - out_offset, out_offset);
- }
- }
-
- fputs("grestore\n", doc.outputfp);
- WriteLabels(&doc, 0);
- fputs("grestore\n", doc.outputfp);
- fputs("showpage\n", doc.outputfp);
- }
-
- canceled:
- fputs("%%EOF\n", doc.outputfp);
-
- free(row);
-
- /*
- * End the job with the appropriate JCL command or CTRL-D otherwise.
- */
-
- if (emit_jcl)
- {
- if (ppd && ppd->jcl_end)
- ppdEmitJCLEnd(ppd, doc.outputfp);
- else
- fputc(0x04, doc.outputfp);
- }
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Printing completed.", page);
-
- /*
- * Close files...
- */
-
- cfImageClose(img);
- fclose(doc.outputfp);
- close(outputfd);
-
- return (0);
-}
-
-
-/*
- * 'WriteCommon()' - Write common procedures...
- */
-
-void
-WriteCommon(imagetops_doc_t *doc)
-{
- fputs("% x y w h ESPrc - Clip to a rectangle.\n"
- "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
- "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
- "neg 0 rlineto closepath clip newpath}bind}ifelse put\n",
- doc->outputfp);
- fputs("% x y w h ESPrf - Fill a rectangle.\n"
- "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
- "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
- "neg 0 rlineto closepath fill grestore}bind}ifelse put\n",
- doc->outputfp);
- fputs("% x y w h ESPrs - Stroke a rectangle.\n"
- "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
- "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
- "neg 0 rlineto closepath stroke grestore}bind}ifelse put\n",
- doc->outputfp);
-}
-
-
-/*
- * 'WriteLabelProlog()' - Write the prolog with the classification
- * and page label.
- */
-
-void
-WriteLabelProlog(imagetops_doc_t *doc,
- const char *label, /* I - Page label */
- float bottom, /* I - Bottom position in points */
- float top, /* I - Top position in points */
- float width) /* I - Width in points */
-{
- const char *classification; /* CLASSIFICATION environment variable*/
- const char *ptr; /* Temporary string pointer */
-
-
- /*
- * First get the current classification...
- */
-
- if ((classification = getenv("CLASSIFICATION")) == NULL)
- classification = "";
- if (strcmp(classification, "none") == 0)
- classification = "";
-
- /*
- * If there is nothing to show, bind an empty 'write labels' procedure
- * and return...
- */
-
- if (!classification[0] && (label == NULL || !label[0]))
- {
- fputs("userdict/ESPwl{}bind put\n", doc->outputfp);
- return;
- }
-
- /*
- * Set the classification + page label string...
- */
-
- fprintf(doc->outputfp, "userdict");
- if (strcmp(classification, "confidential") == 0)
- fprintf(doc->outputfp, "/ESPpl(CONFIDENTIAL");
- else if (strcmp(classification, "classified") == 0)
- fprintf(doc->outputfp, "/ESPpl(CLASSIFIED");
- else if (strcmp(classification, "secret") == 0)
- fprintf(doc->outputfp, "/ESPpl(SECRET");
- else if (strcmp(classification, "topsecret") == 0)
- fprintf(doc->outputfp, "/ESPpl(TOP SECRET");
- else if (strcmp(classification, "unclassified") == 0)
- fprintf(doc->outputfp, "/ESPpl(UNCLASSIFIED");
- else
- {
- fprintf(doc->outputfp, "/ESPpl(");
-
- for (ptr = classification; *ptr; ptr ++)
- if (*ptr < 32 || *ptr > 126)
- fprintf(doc->outputfp, "\\%03o", *ptr);
- else if (*ptr == '_')
- fputc(' ', doc->outputfp);
- else
- {
- if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
- fputc('\\', doc->outputfp);
-
- fputc(*ptr, doc->outputfp);
- }
- }
-
- if (label)
- {
- if (classification[0])
- fprintf(doc->outputfp, " - ");
-
- /*
- * Quote the label string as needed...
- */
-
- for (ptr = label; *ptr; ptr ++)
- if (*ptr < 32 || *ptr > 126)
- fprintf(doc->outputfp, "\\%03o", *ptr);
- else
- {
- if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
- fputc('\\', doc->outputfp);
-
- fputc(*ptr, doc->outputfp);
- }
- }
-
- fputs(")put\n", doc->outputfp);
-
- /*
- * Then get a 14 point Helvetica-Bold font...
- */
-
- fputs("userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put\n",
- doc->outputfp);
-
- /*
- * Finally, the procedure to write the labels on the page...
- */
-
- fputs("userdict/ESPwl{\n", doc->outputfp);
- fputs(" ESPpf setfont\n", doc->outputfp);
- fprintf(doc->outputfp,
- " ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
- width * 0.5f);
- fputs(" 1 setgray\n", doc->outputfp);
- fprintf(doc->outputfp, " dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0);
- fprintf(doc->outputfp, " dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0);
- fputs(" 0 setgray\n", doc->outputfp);
- fprintf(doc->outputfp, " dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0);
- fprintf(doc->outputfp, " dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0);
- fprintf(doc->outputfp, " dup %.0f moveto ESPpl show\n", bottom + 2.0);
- fprintf(doc->outputfp, " %.0f moveto ESPpl show\n", top - 14.0);
- fputs("pop\n", doc->outputfp);
- fputs("}bind put\n", doc->outputfp);
-}
-
-
-/*
- * 'WriteLabels()' - Write the actual page labels.
- */
-
-void
-WriteLabels(imagetops_doc_t *doc,
- int orient) /* I - Orientation of the page */
-{
- float width, /* Width of page */
- length; /* Length of page */
-
-
- fputs("gsave\n", doc->outputfp);
-
- if ((orient ^ doc->Orientation) & 1)
- {
- width = doc->PageLength;
- length = doc->PageWidth;
- }
- else
- {
- width = doc->PageWidth;
- length = doc->PageLength;
- }
-
- switch (orient & 3)
- {
- case 1 : /* Landscape */
- fprintf(doc->outputfp, "%.1f 0.0 translate 90 rotate\n", length);
- break;
- case 2 : /* Reverse Portrait */
- fprintf(doc->outputfp, "%.1f %.1f translate 180 rotate\n", width,
- length);
- break;
- case 3 : /* Reverse Landscape */
- fprintf(doc->outputfp, "0.0 %.1f translate -90 rotate\n", width);
- break;
- }
-
- fputs("ESPwl\n", doc->outputfp);
- fputs("grestore\n", doc->outputfp);
-}
-
-
-/*
- * 'WriteTextComment()' - Write a DSC text comment.
- */
-
-void
-WriteTextComment(imagetops_doc_t *doc,
- const char *name, /* I - Comment name ("Title", etc.) */
- const char *value) /* I - Comment value */
-{
- int len; /* Current line length */
-
-
- /*
- * DSC comments are of the form:
- *
- * %%name: value
- *
- * The name and value must be limited to 7-bit ASCII for most printers,
- * so we escape all non-ASCII and ASCII control characters as described
- * in the Adobe Document Structuring Conventions specification.
- */
-
- fprintf(doc->outputfp, "%%%%%s: (", name);
- len = 5 + strlen(name);
-
- while (*value)
- {
- if (*value < ' ' || *value >= 127)
- {
- /*
- * Escape this character value...
- */
-
- if (len >= 251) /* Keep line < 254 chars */
- break;
-
- fprintf(doc->outputfp, "\\%03o", *value & 255);
- len += 4;
- }
- else if (*value == '\\')
- {
- /*
- * Escape the backslash...
- */
-
- if (len >= 253) /* Keep line < 254 chars */
- break;
-
- fputc('\\', doc->outputfp);
- fputc('\\', doc->outputfp);
- len += 2;
- }
- else
- {
- /*
- * Put this character literally...
- */
-
- if (len >= 254) /* Keep line < 254 chars */
- break;
-
- fputc(*value, doc->outputfp);
- len ++;
- }
-
- value ++;
- }
-
- fputs(")\n", doc->outputfp);
-}
-
-
-/*
- * 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
- */
-
-static void
-ps_hex(FILE *outputfp,
- cf_ib_t *data, /* I - Data to print */
- int length, /* I - Number of bytes to print */
- int last_line) /* I - Last line of raster data? */
-{
- static int col = 0; /* Current column */
- static char *hex = "0123456789ABCDEF";
- /* Hex digits */
-
-
- while (length > 0)
- {
- /*
- * Put the hex chars out to the file; note that we don't use fprintf()
- * for speed reasons...
- */
-
- fputc(hex[*data >> 4], outputfp);
- fputc(hex[*data & 15], outputfp);
-
- data ++;
- length --;
-
- col += 2;
- if (col > 78)
- {
- fputc('\n', outputfp);
- col = 0;
- }
- }
-
- if (last_line && col)
- {
- fputc('\n', outputfp);
- col = 0;
- }
-}
-
-
-/*
- * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
- */
-
-static void
-ps_ascii85(FILE *outputfp,
- cf_ib_t *data, /* I - Data to print */
- int length, /* I - Number of bytes to print */
- int last_line) /* I - Last line of raster data? */
-{
- unsigned b; /* Binary data word */
- unsigned char c[5]; /* ASCII85 encoded chars */
- static int col = 0; /* Current column */
-
-
- while (length > 3)
- {
- b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
-
- if (b == 0)
- {
- fputc('z', outputfp);
- col ++;
- }
- else
- {
- c[4] = (b % 85) + '!';
- b /= 85;
- c[3] = (b % 85) + '!';
- b /= 85;
- c[2] = (b % 85) + '!';
- b /= 85;
- c[1] = (b % 85) + '!';
- b /= 85;
- c[0] = b + '!';
-
- fwrite(c, 5, 1, outputfp);
- col += 5;
- }
-
- data += 4;
- length -= 4;
-
- if (col >= 75)
- {
- fputc('\n', outputfp);
- col = 0;
- }
- }
-
- if (last_line)
- {
- if (length > 0)
- {
- memset(data + length, 0, 4 - length);
- b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
-
- c[4] = (b % 85) + '!';
- b /= 85;
- c[3] = (b % 85) + '!';
- b /= 85;
- c[2] = (b % 85) + '!';
- b /= 85;
- c[1] = (b % 85) + '!';
- b /= 85;
- c[0] = b + '!';
-
- fwrite(c, length + 1, 1, outputfp);
- }
-
- fputs("~>\n", outputfp);
- col = 0;
- }
-}