+++ /dev/null
-/*
- * Generic Adobe PostScript printer command for ippeveprinter/CUPS.
- *
- * Copyright © 2019 by Apple Inc.
- *
- * Licensed under Apache License v2.0. See the file "LICENSE" for more
- * information.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "ippevecommon.h"
-#if !CUPS_LITE
-# include <cups/ppd-private.h>
-#endif /* !CUPS_LITE */
-#include <limits.h>
-
-#ifdef __APPLE__
-# define PDFTOPS CUPS_SERVERBIN "/filter/cgpdftops"
-#else
-# define PDFTOPS CUPS_SERVERBIN "/filter/pdftops"
-#endif /* __APPLE__ */
-
-
-/*
- * Local globals...
- */
-
-#if !CUPS_LITE
-static ppd_file_t *ppd = NULL; /* PPD file data */
-static _ppd_cache_t *ppd_cache = NULL;
- /* IPP to PPD cache data */
-#endif /* !CUPS_LITE */
-
-
-/*
- * Local functions...
- */
-
-static void ascii85(const unsigned char *data, int length, int eod);
-static void dsc_header(int num_pages);
-static void dsc_page(int page);
-static void dsc_trailer(int num_pages);
-static int get_options(cups_option_t **options);
-static int jpeg_to_ps(const char *filename, int copies);
-static int pdf_to_ps(const char *filename, int copies, int num_options, cups_option_t *options);
-static int ps_to_ps(const char *filename, int copies);
-static int raster_to_ps(const char *filename);
-
-
-/*
- * 'main()' - Main entry for PostScript printer command.
- */
-
-int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments */
- char *argv[]) /* I - Command-line arguments */
-{
- const char *content_type, /* Content type to print */
- *ipp_copies; /* IPP_COPIES value */
- int copies; /* Number of copies */
- int num_options; /* Number of options */
- cups_option_t *options; /* Options */
-
-
- /*
- * Get print options...
- */
-
- num_options = get_options(&options);
- if ((ipp_copies = getenv("IPP_COPIES")) != NULL)
- copies = atoi(ipp_copies);
- else
- copies = 1;
-
- /*
- * Print it...
- */
-
- if (argc > 2)
- {
- fputs("ERROR: Too many arguments supplied, aborting.\n", stderr);
- return (1);
- }
- else if ((content_type = getenv("CONTENT_TYPE")) == NULL)
- {
- fputs("ERROR: CONTENT_TYPE environment variable not set, aborting.\n", stderr);
- return (1);
- }
- else if (!strcasecmp(content_type, "application/pdf"))
- {
- return (pdf_to_ps(argv[1], copies, num_options, options));
- }
- else if (!strcasecmp(content_type, "application/postscript"))
- {
- return (ps_to_ps(argv[1], copies));
- }
- else if (!strcasecmp(content_type, "image/jpeg"))
- {
- return (jpeg_to_ps(argv[1], copies));
- }
- else if (!strcasecmp(content_type, "image/pwg-raster") || !strcasecmp(content_type, "image/urf"))
- {
- return (raster_to_ps(argv[1]));
- }
- else
- {
- fprintf(stderr, "ERROR: CONTENT_TYPE %s not supported.\n", content_type);
- return (1);
- }
-}
-
-
-/*
- * 'ascii85()' - Write binary data using a Base85 encoding...
- */
-
-static void
-ascii85(const unsigned char *data, /* I - Data to write */
- int length, /* I - Number of bytes to write */
- int eod) /* I - 1 if this is the end, 0 otherwise */
-{
- unsigned b = 0; /* Current 32-bit word */
- unsigned char c[5]; /* Base-85 encoded characters */
- static int col = 0; /* Column */
- static unsigned char leftdata[4]; /* Leftover data at the end */
- static int leftcount = 0; /* Size of leftover data */
-
-
- length += leftcount;
-
- while (length > 3)
- {
- switch (leftcount)
- {
- case 0 :
- b = (unsigned)((((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]);
- break;
- case 1 :
- b = (unsigned)((((((leftdata[0] << 8) | data[0]) << 8) | data[1]) << 8) | data[2]);
- break;
- case 2 :
- b = (unsigned)((((((leftdata[0] << 8) | leftdata[1]) << 8) | data[0]) << 8) | data[1]);
- break;
- case 3 :
- b = (unsigned)((((((leftdata[0] << 8) | leftdata[1]) << 8) | leftdata[2]) << 8) | data[0]);
- break;
- }
-
- if (col >= 76)
- {
- col = 0;
- putchar('\n');
- }
-
- if (b == 0)
- {
- putchar('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] = (unsigned char)(b + '!');
-
- fwrite(c, 1, 5, stdout);
- col += 5;
- }
-
- data += 4 - leftcount;
- length -= 4 - leftcount;
- leftcount = 0;
- }
-
- if (length > 0)
- {
- // Copy any remainder into the leftdata array...
- if ((length - leftcount) > 0)
- memcpy(leftdata + leftcount, data, (size_t)(length - leftcount));
-
- memset(leftdata + length, 0, (size_t)(4 - length));
-
- leftcount = length;
- }
-
- if (eod)
- {
- // Do the end-of-data dance...
- if (col >= 76)
- {
- col = 0;
- putchar('\n');
- }
-
- if (leftcount > 0)
- {
- // Write the remaining bytes as needed...
- b = (unsigned)((((((leftdata[0] << 8) | leftdata[1]) << 8) | leftdata[2]) << 8) | leftdata[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] = (unsigned char)(b + '!');
-
- fwrite(c, (size_t)(leftcount + 1), 1, stdout);
-
- leftcount = 0;
- }
-
- puts("~>");
- col = 0;
- }
-}
-
-
-/*
- * 'dsc_header()' - Write out a standard Document Structuring Conventions
- * PostScript header.
- */
-
-static void
-dsc_header(int num_pages) /* I - Number of pages or 0 if not known */
-{
- const char *job_name = getenv("IPP_JOB_NAME");
- /* job-name value */
-
-
-#if !CUPS_LITE
- const char *job_id = getenv("IPP_JOB_ID");
- /* job-id value */
-
- ppdEmitJCL(ppd, stdout, job_id ? atoi(job_id) : 0, cupsUser(), job_name ? job_name : "Unknown");
-#endif /* !CUPS_LITE */
-
- puts("%!PS-Adobe-3.0");
- puts("%%LanguageLevel: 2");
- printf("%%%%Creator: ippeveps/%d.%d.%d\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR, CUPS_VERSION_PATCH);
- if (job_name)
- {
- fputs("%%Title: ", stdout);
- while (*job_name)
- {
- if (*job_name >= 0x20 && *job_name < 0x7f)
- putchar(*job_name);
- else
- putchar('?');
-
- job_name ++;
- }
- putchar('\n');
- }
- if (num_pages > 0)
- printf("%%%%Pages: %d\n", num_pages);
- else
- puts("%%Pages: (atend)");
- puts("%%EndComments");
-
-#if !CUPS_LITE
- if (ppd)
- {
- puts("%%BeginProlog");
- if (ppd->patches)
- {
- puts("%%BeginFeature: *JobPatchFile 1");
- puts(ppd->patches);
- puts("%%EndFeature");
- }
- ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
- puts("%%EndProlog");
-
- puts("%%BeginSetup");
- ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
- ppdEmit(ppd, stdout, PPD_ORDER_ANY);
- puts("%%EndSetup");
- }
-#endif /* !CUPS_LITE */
-}
-
-
-/*
- * 'dsc_page()' - Mark the start of a page.
- */
-
-static void
-dsc_page(int page) /* I - Page numebr (1-based) */
-{
- printf("%%%%Page: (%d) %d\n", page, page);
-
- fprintf(stderr, "ATTR: job-impressions-completed=%d\n", page);
-
-#if !CUPS_LITE
- if (ppd)
- {
- puts("%%BeginPageSetup");
- ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
- puts("%%EndPageSetup");
- }
-#endif /* !CUPS_LITE */
-}
-
-
-/*
- * 'dsc_trailer()' - Mark the end of the document.
- */
-
-static void
-dsc_trailer(int num_pages) /* I - Number of pages */
-{
- if (num_pages > 0)
- {
- puts("%%Trailer");
- printf("%%%%Pages: %d\n", num_pages);
- puts("%%EOF");
- }
-
-#if !CUPS_LITE
- if (ppd && ppd->jcl_end)
- ppdEmitJCLEnd(ppd, stdout);
- else
-#endif /* !CUPS_LITE */
- putchar(0x04);
-}
-
-
-/*
- * 'get_options()' - Get the PPD options corresponding to the IPP Job Template
- * attributes.
- */
-
-static int /* O - Number of options */
-get_options(cups_option_t **options) /* O - Options */
-{
- int num_options = 0; /* Number of options */
- const char *value; /* Option value */
- pwg_media_t *media = NULL; /* Media mapping */
- int num_media_col = 0; /* Number of media-col values */
- cups_option_t *media_col = NULL; /* media-col values */
-#if !CUPS_LITE
- const char *choice; /* PPD choice */
-#endif /* !CUPS_LITE */
-
-
- /*
- * No options to start...
- */
-
- *options = NULL;
-
- /*
- * Media...
- */
-
- if ((value = getenv("IPP_MEDIA")) == NULL)
- if ((value = getenv("IPP_MEDIA_COL")) == NULL)
- if ((value = getenv("IPP_MEDIA_DEFAULT")) == NULL)
- value = getenv("IPP_MEDIA_COL_DEFAULT");
-
- if (value)
- {
- if (*value == '{')
- {
- /*
- * media-col value...
- */
-
- num_media_col = cupsParseOptions(value, 0, &media_col);
- }
- else
- {
- /*
- * media value - map to media-col.media-size-name...
- */
-
- num_media_col = cupsAddOption("media-size-name", value, 0, &media_col);
- }
- }
-
- if ((value = cupsGetOption("media-size-name", num_media_col, media_col)) != NULL)
- {
- media = pwgMediaForPWG(value);
- }
- else if ((value = cupsGetOption("media-size", num_media_col, media_col)) != NULL)
- {
- int num_media_size; /* Number of media-size values */
- cups_option_t *media_size; /* media-size values */
- const char *x_dimension, /* x-dimension value */
- *y_dimension; /* y-dimension value */
-
- num_media_size = cupsParseOptions(value, 0, &media_size);
-
- if ((x_dimension = cupsGetOption("x-dimension", num_media_size, media_size)) != NULL && (y_dimension = cupsGetOption("y-dimension", num_media_size, media_size)) != NULL)
- media = pwgMediaForSize(atoi(x_dimension), atoi(y_dimension));
-
- cupsFreeOptions(num_media_size, media_size);
- }
-
- if (media)
- num_options = cupsAddOption("PageSize", media->ppd, num_options, options);
-
-#if !CUPS_LITE
- /*
- * Load PPD file and the corresponding IPP <-> PPD cache data...
- */
-
- if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL)
- {
- ppd_cache = _ppdCacheCreateWithPPD(ppd);
-
- /* TODO: Fix me - values are names, not numbers... Also need to support finishings-col */
- if ((value = getenv("IPP_FINISHINGS")) == NULL)
- value = getenv("IPP_FINISHINGS_DEFAULT");
-
- if (value)
- {
- char *ptr; /* Pointer into value */
- int fin; /* Current value */
-
- for (fin = strtol(value, &ptr, 10); fin > 0; fin = strtol(ptr + 1, &ptr, 10))
- {
- num_options = _ppdCacheGetFinishingOptions(ppd_cache, NULL, (ipp_finishings_t)fin, num_options, options);
-
- if (*ptr != ',')
- break;
- }
- }
-
- if ((value = cupsGetOption("media-source", num_media_col, media_col)) != NULL)
- {
- if ((choice = _ppdCacheGetInputSlot(ppd_cache, NULL, value)) != NULL)
- num_options = cupsAddOption("InputSlot", choice, num_options, options);
- }
-
- if ((value = cupsGetOption("media-type", num_media_col, media_col)) != NULL)
- {
- if ((choice = _ppdCacheGetMediaType(ppd_cache, NULL, value)) != NULL)
- num_options = cupsAddOption("MediaType", choice, num_options, options);
- }
-
- if ((value = getenv("IPP_OUTPUT_BIN")) == NULL)
- value = getenv("IPP_OUTPUT_BIN_DEFAULT");
-
- if (value)
- {
- if ((choice = _ppdCacheGetOutputBin(ppd_cache, value)) != NULL)
- num_options = cupsAddOption("OutputBin", choice, num_options, options);
- }
-
- if ((value = getenv("IPP_SIDES")) == NULL)
- value = getenv("IPP_SIDES_DEFAULT");
-
- if (value && ppd_cache->sides_option)
- {
- if (!strcmp(value, "one-sided") && ppd_cache->sides_1sided)
- num_options = cupsAddOption(ppd_cache->sides_option, ppd_cache->sides_1sided, num_options, options);
- else if (!strcmp(value, "two-sided-long-edge") && ppd_cache->sides_2sided_long)
- num_options = cupsAddOption(ppd_cache->sides_option, ppd_cache->sides_2sided_long, num_options, options);
- else if (!strcmp(value, "two-sided-short-edge") && ppd_cache->sides_2sided_short)
- num_options = cupsAddOption(ppd_cache->sides_option, ppd_cache->sides_2sided_short, num_options, options);
- }
-
- if ((value = getenv("IPP_PRINT_QUALITY")) == NULL)
- value = getenv("IPP_PRINT_QUALITY_DEFAULT");
-
- if (value)
- {
- int i; /* Looping var */
- int pq; /* Print quality (0-2) */
- int pcm = 1; /* Print color model (0 = mono, 1 = color) */
- int num_presets; /* Number of presets */
- cups_option_t *presets; /* Presets */
-
- if (!strcmp(value, "draft"))
- pq = 0;
- else if (!strcmp(value, "high"))
- pq = 2;
- else
- pq = 1;
-
- if ((value = getenv("IPP_PRINT_COLOR_MODE")) == NULL)
- value = getenv("IPP_PRINT_COLOR_MODE_DEFAULT");
-
- if (value && !strcmp(value, "monochrome"))
- pcm = 0;
-
- num_presets = ppd_cache->num_presets[pcm][pq];
- presets = ppd_cache->presets[pcm][pq];
-
- for (i = 0; i < num_presets; i ++)
- num_options = cupsAddOption(presets[i].name, presets[i].value, num_options, options);
- }
-
- /*
- * Mark the PPD with the options...
- */
-
- ppdMarkDefaults(ppd);
- cupsMarkOptions(ppd, num_options, *options);
- }
-#endif /* !CUPS_LITE */
-
- cupsFreeOptions(num_media_col, media_col);
-
- return (num_options);
-}
-
-
-/*
- * 'jpeg_to_ps()' - Convert a JPEG file to PostScript.
- */
-
-static int /* O - Exit status */
-jpeg_to_ps(const char *filename, /* I - Filename */
- int copies) /* I - Number of copies */
-{
- int fd; /* JPEG file descriptor */
- int copy; /* Current copy */
- int width = 0, /* Width */
- height = 0, /* Height */
- depth = 0, /* Number of colors */
- length; /* Length of marker */
- unsigned char buffer[65536], /* Copy buffer */
- *bufptr, /* Pointer info buffer */
- *bufend; /* End of buffer */
- ssize_t bytes; /* Bytes in buffer */
- const char *decode; /* Decode array */
- float page_left, /* Left margin */
- page_top, /* Top margin */
- page_width, /* Page width in points */
- page_height, /* Page heigth in points */
- x_factor, /* X image scaling factor */
- y_factor, /* Y image scaling factor */
- page_scaling; /* Image scaling factor */
-#if !CUPS_LITE
- ppd_size_t *page_size; /* Current page size */
-#endif /* !CUPS_LITE */
-
-
- /*
- * Open the input file...
- */
-
- if (filename)
- {
- if ((fd = open(filename, O_RDONLY)) < 0)
- {
- fprintf(stderr, "ERROR: Unable to open \"%s\": %s\n", filename, strerror(errno));
- return (1);
- }
- }
- else
- {
- fd = 0;
- copies = 1;
- }
-
- /*
- * Read the JPEG dimensions...
- */
-
- bytes = read(fd, buffer, sizeof(buffer));
-
- if (bytes < 3 || memcmp(buffer, "\377\330\377", 3))
- {
- fputs("ERROR: Not a JPEG image.\n", stderr);
-
- if (fd > 0)
- close(fd);
-
- return (1);
- }
-
- for (bufptr = buffer + 2, bufend = buffer + bytes; bufptr < bufend;)
- {
- /*
- * Scan the file for a SOFn marker, then we can get the dimensions...
- */
-
- if (*bufptr == 0xff)
- {
- bufptr ++;
-
- if (bufptr >= bufend)
- {
- /*
- * If we are at the end of the current buffer, re-fill and continue...
- */
-
- if ((bytes = read(fd, buffer, sizeof(buffer))) <= 0)
- break;
-
- bufptr = buffer;
- bufend = buffer + bytes;
- }
-
- if (*bufptr == 0xff)
- continue;
-
- if ((bufptr + 16) >= bufend)
- {
- /*
- * Read more of the marker...
- */
-
- bytes = bufend - bufptr;
-
- memmove(buffer, bufptr, (size_t)bytes);
- bufptr = buffer;
- bufend = buffer + bytes;
-
- if ((bytes = read(fd, bufend, sizeof(buffer) - (size_t)bytes)) <= 0)
- break;
-
- bufend += bytes;
- }
-
- length = (size_t)((bufptr[1] << 8) | bufptr[2]);
-
- if ((*bufptr >= 0xc0 && *bufptr <= 0xc3) || (*bufptr >= 0xc5 && *bufptr <= 0xc7) || (*bufptr >= 0xc9 && *bufptr <= 0xcb) || (*bufptr >= 0xcd && *bufptr <= 0xcf))
- {
- /*
- * SOFn marker, look for dimensions...
- */
-
- width = (bufptr[6] << 8) | bufptr[7];
- height = (bufptr[4] << 8) | bufptr[5];
- depth = bufptr[8];
- break;
- }
-
- /*
- * Skip past this marker...
- */
-
- bufptr ++;
- bytes = bufend - bufptr;
-
- while (length >= bytes)
- {
- length -= bytes;
-
- if ((bytes = read(fd, buffer, sizeof(buffer))) <= 0)
- break;
-
- bufptr = buffer;
- bufend = buffer + bytes;
- }
-
- if (length > bytes)
- break;
-
- bufptr += length;
- }
- }
-
- fprintf(stderr, "DEBUG: JPEG dimensions are %dx%dx%d\n", width, height, depth);
-
- if (width <= 0 || height <= 0 || depth <= 0)
- {
- fputs("ERROR: No valid image data in JPEG file.\n", stderr);
-
- if (fd > 0)
- close(fd);
-
- return (1);
- }
-
- fputs("ATTR: job-impressions=1\n", stderr);
-
- /*
- * Figure out the dimensions/scaling of the final image...
- */
-
-#if CUPS_LITE
- page_left = 18.0f;
- page_top = 756.0f;
- page_width = 576.0f;
- page_height = 720.0f;
-
-#else
- if ((page_size = ppdPageSize(ppd, NULL)) != NULL)
- {
- page_left = page_size->left;
- page_top = page_size->top;
- page_width = page_size->right - page_left;
- page_height = page_top - page_size->bottom;
- }
- else
- {
- page_left = 18.0f;
- page_top = 756.0f;
- page_width = 576.0f;
- page_height = 720.0f;
- }
-#endif /* CUPS_LITE */
-
- fprintf(stderr, "DEBUG: page_left=%.2f, page_top=%.2f, page_width=%.2f, page_height=%.2f\n", page_left, page_top, page_width, page_height);
-
- /* TODO: Support orientation/rotation, different print-scaling modes */
- x_factor = page_width / width;
- y_factor = page_height / height;
-
- if (x_factor > y_factor && (height * x_factor) <= page_height)
- page_scaling = x_factor;
- else
- page_scaling = y_factor;
-
- fprintf(stderr, "DEBUG: Scaled dimensions are %.2fx%.2f\n", width * page_scaling, height * page_scaling);
-
- /*
- * Write pages...
- */
-
- dsc_header(copies);
-
- for (copy = 1; copy <= copies; copy ++)
- {
- dsc_page(copy);
-
- if (depth == 1)
- {
- puts("/DeviceGray setcolorspace");
- decode = "0 1";
- }
- else if (depth == 3)
- {
- puts("/DeviceRGB setcolorspace");
- decode = "0 1 0 1 0 1";
- }
- else
- {
- puts("/DeviceCMYK setcolorspace");
- decode = "0 1 0 1 0 1 0 1";
- }
-
- printf("gsave %.3f %.3f translate %.3f %.3f scale\n", page_left + 0.5f * (page_width - width * page_scaling), page_top - 0.5f * (page_height - height * page_scaling), page_scaling, page_scaling);
- printf("<</ImageType 1/Width %d/Height %d/BitsPerComponent 8/ImageMatrix[1 0 0 -1 0 1]/Decode[%s]/DataSource currentfile/ASCII85Decode filter/DCTDecode filter/Interpolate true>>image\n", width, height, decode);
-
- if (fd > 0)
- lseek(fd, 0, SEEK_SET);
-
- while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
- ascii85(buffer, (int)bytes, 0);
-
- ascii85(buffer, 0, 1);
-
- puts("grestore showpage");
- }
-
- dsc_trailer(0);
-
- return (0);
-}
-
-
-/*
- * 'pdf_to_ps()' - Convert a PDF file to PostScript.
- */
-
-static int /* O - Exit status */
-pdf_to_ps(const char *filename, /* I - Filename */
- int copies, /* I - Number of copies */
- int num_options, /* I - Number of options */
- cups_option_t *options) /* I - options */
-{
- int status; /* Exit status */
- char tempfile[1024]; /* Temporary file */
- int tempfd; /* Temporary file descriptor */
- int pid; /* Process ID */
- const char *pdf_argv[8]; /* Command-line arguments */
- char pdf_options[1024]; /* Options */
- const char *value; /* Option value */
- const char *job_id, /* job-id value */
- *job_name; /* job-name value */
-
-
- /*
- * Create a temporary file for the PostScript version...
- */
-
- if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
- {
- fprintf(stderr, "ERROR: Unable to create temporary file: %s\n", strerror(errno));
- return (1);
- }
-
- /*
- * Run cgpdftops or pdftops in the filter directory...
- */
-
- if ((value = cupsGetOption("PageSize", num_options, options)) != NULL)
- snprintf(pdf_options, sizeof(pdf_options), "PageSize=%s", value);
- else
- pdf_options[0] = '\0';
-
- if ((job_id = getenv("IPP_JOB_ID")) == NULL)
- job_id = "42";
- if ((job_name = getenv("IPP_JOB_NAME")) == NULL)
- job_name = "untitled";
-
- pdf_argv[0] = "printer";
- pdf_argv[1] = job_id;
- pdf_argv[2] = cupsUser();
- pdf_argv[3] = job_name;
- pdf_argv[4] = "1";
- pdf_argv[5] = pdf_options;
- pdf_argv[6] = filename;
- pdf_argv[7] = NULL;
-
- if ((pid = fork()) == 0)
- {
- /*
- * Child comes here...
- */
-
- close(1);
- dup2(tempfd, 1);
- close(tempfd);
-
- execv(PDFTOPS, (char * const *)pdf_argv);
- exit(errno);
- }
- else if (pid < 0)
- {
- /*
- * Unable to fork process...
- */
-
- perror("ERROR: Unable to start PDF filter");
-
- close(tempfd);
- unlink(tempfile);
-
- return (1);
- }
- else
- {
- /*
- * Wait for the filter to complete...
- */
-
- close(tempfd);
-
-# ifdef HAVE_WAITPID
- while (waitpid(pid, &status, 0) < 0);
-# else
- while (wait(&status) < 0);
-# endif /* HAVE_WAITPID */
-
- if (status)
- {
- if (WIFEXITED(status))
- fprintf(stderr, "ERROR: " PDFTOPS " exited with status %d.\n", WEXITSTATUS(status));
- else
- fprintf(stderr, "ERROR: " PDFTOPS " terminated with signal %d.\n", WTERMSIG(status));
-
- unlink(tempfile);
- return (1);
- }
- }
-
- /*
- * Copy the PostScript output from the command...
- */
-
- status = ps_to_ps(tempfile, copies);
-
- unlink(tempfile);
-
- return (status);
-}
-
-
-/*
- * 'ps_to_ps()' - Copy PostScript to the standard output.
- */
-
-static int /* O - Exit status */
-ps_to_ps(const char *filename, /* I - Filename */
- int copies) /* I - Number of copies */
-{
- FILE *fp; /* File to read from */
- int copy, /* Current copy */
- page, /* Current page number */
- num_pages = 0, /* Total number of pages */
- first_page, /* First page */
- last_page; /* Last page */
- const char *page_ranges; /* page-ranges option */
- long first_pos = -1; /* Offset for first page */
- char line[1024]; /* Line from file */
-
-
- /*
- * Open the print file...
- */
-
- if (filename)
- {
- if ((fp = fopen(filename, "rb")) == NULL)
- {
- fprintf(stderr, "ERROR: Unable to open \"%s\": %s\n", filename, strerror(errno));
- return (1);
- }
- }
- else
- {
- copies = 1;
- fp = stdin;
- }
-
- /*
- * Check page ranges...
- */
-
- if ((page_ranges = getenv("IPP_PAGE_RANGES")) != NULL)
- {
- if (sscanf(page_ranges, "%d-%d", &first_page, &last_page) != 2)
- {
- first_page = 1;
- last_page = INT_MAX;
- }
- }
- else
- {
- first_page = 1;
- last_page = INT_MAX;
- }
-
- /*
- * Write the PostScript header for the document...
- */
-
- dsc_header(0);
-
- first_pos = 0;
-
- while (fgets(line, sizeof(line), fp))
- {
- if (!strncmp(line, "%%Page:", 7))
- break;
-
- first_pos = ftell(fp);
-
- if (line[0] != '%')
- fputs(line, stdout);
- }
-
- if (!strncmp(line, "%%Page:", 7))
- {
- for (copy = 0; copy < copies; copy ++)
- {
- int copy_page = 0; /* Do we copy the page data? */
-
- if (fp != stdin)
- fseek(fp, first_pos, SEEK_SET);
-
- page = 0;
- while (fgets(line, sizeof(line), fp))
- {
- if (!strncmp(line, "%%Page:", 7))
- {
- page ++;
- copy_page = page >= first_page && page <= last_page;
-
- if (copy_page)
- {
- num_pages ++;
- dsc_page(num_pages);
- }
- }
- else if (copy_page)
- fputs(line, stdout);
- }
- }
- }
-
- dsc_trailer(num_pages);
-
- fprintf(stderr, "ATTR: job-impressions=%d\n", num_pages / copies);
-
- if (fp != stdin)
- fclose(fp);
-
- return (0);
-}
-
-
-/*
- * 'raster_to_ps()' - Convert PWG Raster/Apple Raster to PostScript.
- *
- * The current implementation locally-decodes the raster data and then writes
- * whole, non-blank lines as 1-line high images with base-85 encoding, resulting
- * in between 10 and 20 times larger output. A alternate implementation (if it
- * is deemed necessary) would be to implement a PostScript decode procedure that
- * handles the modified packbits decompression so that we just have the base-85
- * encoding overhead (25%). Furthermore, Level 3 PostScript printers also
- * support Flate compression.
- *
- * That said, the most efficient path with the highest quality is for Clients
- * to supply PDF files and us to use the existing PDF to PostScript conversion
- * filters.
- */
-
-static int /* O - Exit status */
-raster_to_ps(const char *filename) /* I - Filename */
-{
- int fd; /* Input file */
- cups_raster_t *ras; /* Raster stream */
- cups_page_header2_t header; /* Page header */
- int page = 0; /* Current page */
- unsigned y; /* Current line */
- unsigned char *line; /* Line buffer */
- unsigned char white; /* White color */
- const char *decode; /* Image decode array */
-
-
- /*
- * Open the input file...
- */
-
- if (filename)
- {
- if ((fd = open(filename, O_RDONLY)) < 0)
- {
- fprintf(stderr, "ERROR: Unable to open \"%s\": %s\n", filename, strerror(errno));
- return (1);
- }
- }
- else
- {
- fd = 0;
- }
-
- /*
- * Open the raster stream and send pages...
- */
-
- if ((ras = cupsRasterOpen(fd, CUPS_RASTER_READ)) == NULL)
- {
- fputs("ERROR: Unable to read raster data, aborting.\n", stderr);
- return (1);
- }
-
- dsc_header(0);
-
- while (cupsRasterReadHeader2(ras, &header))
- {
- page ++;
-
- fprintf(stderr, "DEBUG: Page %d: %ux%ux%u\n", page, header.cupsWidth, header.cupsHeight, header.cupsBitsPerPixel);
-
- if (header.cupsColorSpace != CUPS_CSPACE_W && header.cupsColorSpace != CUPS_CSPACE_SW && header.cupsColorSpace != CUPS_CSPACE_K && header.cupsColorSpace != CUPS_CSPACE_RGB && header.cupsColorSpace != CUPS_CSPACE_SRGB)
- {
- fputs("ERROR: Unsupported color space, aborting.\n", stderr);
- break;
- }
- else if (header.cupsBitsPerColor != 1 && header.cupsBitsPerColor != 8)
- {
- fputs("ERROR: Unsupported bit depth, aborting.\n", stderr);
- break;
- }
-
- line = malloc(header.cupsBytesPerLine);
-
- dsc_page(page);
-
- puts("gsave");
- printf("%.6f %.6f scale\n", 72.0f / header.HWResolution[0], 72.0f / header.HWResolution[1]);
-
- switch (header.cupsColorSpace)
- {
- case CUPS_CSPACE_W :
- case CUPS_CSPACE_SW :
- decode = "0 1";
- puts("/DeviceGray setcolorspace");
- white = 255;
- break;
-
- case CUPS_CSPACE_K :
- decode = "0 1";
- puts("/DeviceGray setcolorspace");
- white = 0;
- break;
-
- default :
- decode = "0 1 0 1 0 1";
- puts("/DeviceRGB setcolorspace");
- white = 255;
- break;
- }
-
- printf("gsave /L{grestore gsave 0 exch translate <</ImageType 1/Width %u/Height 1/BitsPerComponent %u/ImageMatrix[1 0 0 -1 0 1]/DataSource currentfile/ASCII85Decode filter/Decode[%s]>>image}bind def\n", header.cupsWidth, header.cupsBitsPerColor, decode);
-
- for (y = header.cupsHeight; y > 0; y --)
- {
- if (cupsRasterReadPixels(ras, line, header.cupsBytesPerLine))
- {
- if (line[0] != white || memcmp(line, line + 1, header.cupsBytesPerLine - 1))
- {
- printf("%d L\n", y - 1);
- ascii85(line, (int)header.cupsBytesPerLine, 1);
- }
- }
- else
- break;
- }
-
- fprintf(stderr, "DEBUG: y=%d at end...\n", y);
-
- puts("grestore grestore");
- puts("showpage");
-
- free(line);
- }
-
- cupsRasterClose(ras);
-
- dsc_trailer(page);
-
- fprintf(stderr, "ATTR: job-impressions=%d\n", page);
-
- return (0);
-}
-
-