4 * PDF to PostScript filter front-end for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
8 * Copyright 2011-2012 by Till Kamppeter
10 * These coded instructions, statements, and computer programs are the
11 * property of Apple Inc. and are protected by Federal copyright
12 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
13 * which should have been included with this file. If this file is
14 * file is missing or damaged, see the license at "http://www.cups.org/".
18 * main() - Main entry for filter...
19 * cancel_job() - Flag the job as canceled.
23 * Include necessary headers...
26 #include <cups/cups.h>
28 #include <cups/file.h>
36 #include <cupsfilters/image-private.h>
38 #define MAX_CHECK_COMMENT_LINES 20
44 typedef unsigned renderer_t;
45 enum renderer_e {GS = 0, PDFTOPS = 1, ACROREAD = 2};
51 static void cancel_job(int sig);
58 static int job_canceled = 0;
59 int pdftopdfapplied = 0;
60 char deviceCopies[32] = "1";
61 int deviceCollate = 0;
65 * When calling the "pstops" filter we exclude the following options from its
66 * command line as we have applied these options already to the PDF input,
67 * either on the "pdftops"/Ghostscript call in this filter or by use of the
68 * "pdftopdf" filter before this filter.
71 const char *pstops_exclude_general[] = {
75 "orientation-requested",
79 const char *pstops_exclude_page_management[] = {
85 "ipp-attribute-fidelity",
88 "multiple-document-handling",
109 * Check whether we were called after the "pdftopdf" filter and extract
110 * parameters passed over by "pdftopdf" in the header comments of the PDF
114 static void parsePDFTOPDFComment(char *filename)
120 if ((fp = fopen(filename,"rb")) == 0) {
121 fprintf(stderr, "ERROR: pdftops - cannot open print file \"%s\"\n",
126 /* skip until PDF start header */
127 while (fgets(buf,sizeof(buf),fp) != 0) {
128 if (strncmp(buf,"%PDF",4) == 0) {
132 for (i = 0;i < MAX_CHECK_COMMENT_LINES;i++) {
133 if (fgets(buf,sizeof(buf),fp) == 0) break;
134 if (strncmp(buf,"%%PDFTOPDFNumCopies",19) == 0) {
137 p = strchr(buf+19,':') + 1;
138 while (*p == ' ' || *p == '\t') p++;
139 strncpy(deviceCopies, p, sizeof(deviceCopies));
140 deviceCopies[sizeof(deviceCopies) - 1] = '\0';
141 p = deviceCopies + strlen(deviceCopies) - 1;
142 while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p--;
145 } else if (strncmp(buf,"%%PDFTOPDFCollate",17) == 0) {
148 p = strchr(buf+17,':') + 1;
149 while (*p == ' ' || *p == '\t') p++;
150 if (strncasecmp(p,"true",4) == 0) {
156 } else if (strcmp(buf,"% This file was generated by pdftopdf") == 0) {
166 * Remove all options in option_list from the string option_str, including
167 * option values after an "=" sign and preceded "no" before boolean options
170 void remove_options(char *options_str, const char **option_list)
172 const char **option; /* Option to be removed now */
173 char *option_start, /* Start of option in string */
174 *option_end; /* End of option in string */
176 for (option = option_list; *option; option ++)
178 option_start = options_str;
180 while ((option_start = strcasestr(option_start, *option)) != NULL)
182 if (!option_start[strlen(*option)] ||
183 isspace(option_start[strlen(*option)] & 255) ||
184 option_start[strlen(*option)] == '=')
190 option_end = option_start + strlen(*option);
192 /* Remove preceding "no" of boolean option */
193 if ((option_start - options_str) >= 2 &&
194 !strncasecmp(option_start - 2, "no", 2))
197 /* Is match of the searched option name really at the beginning of
198 the name of the option in the command line? */
199 if ((option_start > options_str) &&
200 (!isspace(*(option_start - 1) & 255)))
202 /* Prevent the same option to be found again. */
208 /* Remove "=" and value */
209 while (*option_end && !isspace(*option_end & 255))
212 /* Remove spaces up to next option */
213 while (*option_end && isspace(*option_end & 255))
216 memmove(option_start, option_end, strlen(option_end) + 1);
218 /* Prevent the same option to be found again. */
227 * 'main()' - Main entry for filter...
230 int /* O - Exit status */
231 main(int argc, /* I - Number of command-line args */
232 char *argv[]) /* I - Command-line arguments */
234 renderer_t renderer = CUPS_PDFTOPS_RENDERER; /* Renderer: gs or pdftops or acroread */
235 int fd = 0; /* Copy file descriptor */
236 char *filename, /* PDF file to convert */
237 tempfile[1024]; /* Temporary file */
238 char buffer[8192]; /* Copy buffer */
239 int bytes; /* Bytes copied */
240 int num_options; /* Number of options */
241 cups_option_t *options; /* Options */
242 const char *val; /* Option value */
243 int orientation, /* Output orientation */
244 fit; /* Fit output to default page size? */
245 ppd_file_t *ppd; /* PPD file */
246 ppd_size_t *size; /* Current page size */
247 char resolution[128] = "300";/* Output resolution */
248 int xres = 0, yres = 0, /* resolution values */
249 maxres = CUPS_PDFTOPS_MAX_RESOLUTION,
250 /* Maximum image rendering resolution */
251 numvalues; /* Number of values actually read */
252 ppd_choice_t *choice;
254 cups_page_header2_t header;
255 cups_file_t *fp; /* Post-processing input file */
256 int pdf_pid, /* Process ID for pdftops */
257 pdf_argc, /* Number of args for pdftops */
258 pstops_pid, /* Process ID of pstops filter */
259 pstops_pipe[2], /* Pipe to pstops filter */
260 need_post_proc = 0, /* Post-processing needed? */
261 post_proc_pid = 0, /* Process ID of post-processing */
262 post_proc_pipe[2], /* Pipe to post-processing */
263 wait_children, /* Number of child processes left */
264 wait_pid, /* Process ID from wait() */
265 wait_status, /* Status from child */
266 exit_status = 0; /* Exit status */
267 char *pdf_argv[100], /* Arguments for pdftops/gs */
268 pdf_width[255], /* Paper width */
269 pdf_height[255], /* Paper height */
270 pdf_widthxheight[255], /* Paper width x height */
271 pstops_path[1024], /* Path to pstops program */
272 *pstops_argv[7], /* Arguments for pstops filter */
273 *pstops_options, /* Options for pstops filter */
274 *pstops_end; /* End of pstops filter option */
275 const char *cups_serverbin; /* CUPS_SERVERBIN environment variable */
276 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
277 struct sigaction action; /* Actions for POSIX signals */
278 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
282 * Make sure status messages are not buffered...
285 setbuf(stderr, NULL);
288 * Ignore broken pipe signals...
291 signal(SIGPIPE, SIG_IGN);
294 * Make sure we have the right number of arguments for CUPS!
297 if (argc < 6 || argc > 7)
299 fprintf(stderr, "Usage: %s job user title copies options [file]\n",
305 * Register a signal handler to cleanly cancel a job.
308 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
309 sigset(SIGTERM, cancel_job);
310 #elif defined(HAVE_SIGACTION)
311 memset(&action, 0, sizeof(action));
313 sigemptyset(&action.sa_mask);
314 action.sa_handler = cancel_job;
315 sigaction(SIGTERM, &action, NULL);
317 signal(SIGTERM, cancel_job);
318 #endif /* HAVE_SIGSET */
321 * Copy stdin if needed...
327 * Copy stdin to a temp file...
330 if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
332 perror("DEBUG: Unable to copy PDF file");
336 fprintf(stderr, "DEBUG: pdftops - copying to temp print file \"%s\"\n",
339 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
340 bytes = write(fd, buffer, bytes);
349 * Use the filename on the command-line...
357 * Read out copy counts and collate setting passed over by pdftopdf
360 parsePDFTOPDFComment(filename);
363 * Load the PPD file and mark options...
366 ppd = ppdOpenFile(getenv("PPD"));
367 num_options = cupsParseOptions(argv[5], 0, &options);
369 ppdMarkDefaults(ppd);
370 cupsMarkOptions(ppd, num_options, options);
373 * Select the PDF renderer: Ghostscript (gs) or Poppler (pdftops)
376 if ((val = cupsGetOption("pdftops-renderer", num_options, options)) != NULL)
378 if (strcasecmp(val, "gs") == 0)
380 else if (strcasecmp(val, "pdftops") == 0)
382 else if (strcasecmp(val, "acroread") == 0)
386 "WARNING: Invalid value for \"pdftops-renderer\": \"%s\"\n", val);
390 * Build the pstops command-line...
393 if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
394 cups_serverbin = CUPS_SERVERBIN;
396 snprintf(pstops_path, sizeof(pstops_path), "%s/filter/pstops",
399 pstops_options = strdup(argv[5]);
402 * Strip options which "pstops" does not need to apply any more
404 remove_options(pstops_options, pstops_exclude_general);
406 remove_options(pstops_options, pstops_exclude_page_management);
408 if (pdftopdfapplied && deviceCollate)
411 * Add collate option to the pstops call if pdftopdf has found out that the
412 * printer does hardware collate.
415 pstops_options = realloc(pstops_options, strlen(pstops_options) + 9);
416 if (!pstops_options) {
417 fprintf(stderr, "ERROR: Can't allocate pstops_options\n");
420 pstops_end = pstops_options + strlen(pstops_options);
421 strcpy(pstops_end, " Collate");
424 pstops_argv[0] = argv[0]; /* Printer */
425 pstops_argv[1] = argv[1]; /* Job */
426 pstops_argv[2] = argv[2]; /* User */
427 pstops_argv[3] = argv[3]; /* Title */
429 pstops_argv[4] = deviceCopies; /* Copies */
431 pstops_argv[4] = argv[4]; /* Copies */
432 pstops_argv[5] = pstops_options; /* Options */
433 pstops_argv[6] = NULL;
436 * Build the command-line for the pdftops or gs filter...
439 if (renderer == PDFTOPS)
441 pdf_argv[0] = (char *)"pdftops";
444 else if (renderer == GS)
446 pdf_argv[0] = (char *)"gs";
447 pdf_argv[1] = (char *)"-q";
448 pdf_argv[2] = (char *)"-dNOPAUSE";
449 pdf_argv[3] = (char *)"-dBATCH";
450 pdf_argv[4] = (char *)"-dSAFER";
451 # ifdef HAVE_GHOSTSCRIPT_PS2WRITE
452 pdf_argv[5] = (char *)"-sDEVICE=ps2write";
454 pdf_argv[5] = (char *)"-sDEVICE=pswrite";
455 # endif /* HAVE_GHOSTSCRIPT_PS2WRITE */
456 pdf_argv[6] = (char *)"-sOUTPUTFILE=%stdout";
461 pdf_argv[0] = (char *)"acroread";
462 pdf_argv[1] = (char *)"-toPostScript";
469 * Set language level and TrueType font handling...
472 if (ppd->language_level == 1)
474 if (renderer == PDFTOPS)
476 pdf_argv[pdf_argc++] = (char *)"-level1";
477 pdf_argv[pdf_argc++] = (char *)"-noembtt";
479 else if (renderer == GS)
480 pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=1";
482 fprintf(stderr, "WARNING: Level 1 PostScript not supported by acroread.");
484 else if (ppd->language_level == 2)
486 if (renderer == PDFTOPS)
488 pdf_argv[pdf_argc++] = (char *)"-level2";
489 if (!ppd->ttrasterizer)
490 pdf_argv[pdf_argc++] = (char *)"-noembtt";
492 else if (renderer == GS)
493 pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=2";
495 pdf_argv[pdf_argc++] = (char *)"-level2";
499 if (renderer == PDFTOPS)
500 /* Do not emit PS Level 3 with Poppler, some HP PostScript printers
501 do not like it. See https://bugs.launchpad.net/bugs/277404. */
502 pdf_argv[pdf_argc++] = (char *)"-level2";
503 else if (renderer == GS)
504 pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=3";
506 pdf_argv[pdf_argc++] = (char *)"-level3";
509 if ((val = cupsGetOption("fitplot", num_options, options)) == NULL)
510 val = cupsGetOption("fit-to-page", num_options, options);
512 if (val && strcasecmp(val, "no") && strcasecmp(val, "off") &&
513 strcasecmp(val, "false"))
519 * Set output page size...
522 size = ppdPageSize(ppd, NULL);
526 * Got the size, now get the orientation...
531 if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
533 if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 &&
534 strcasecmp(val, "false") != 0)
537 else if ((val = cupsGetOption("orientation-requested", num_options,
541 * Map IPP orientation values to 0 to 3:
545 * 5 = -90 degrees = 3
546 * 6 = 180 degrees = 2
549 orientation = atoi(val) - 3;
550 if (orientation >= 2)
554 if (renderer == PDFTOPS)
558 snprintf(pdf_width, sizeof(pdf_width), "%.0f", size->length);
559 snprintf(pdf_height, sizeof(pdf_height), "%.0f", size->width);
563 snprintf(pdf_width, sizeof(pdf_width), "%.0f", size->width);
564 snprintf(pdf_height, sizeof(pdf_height), "%.0f", size->length);
567 pdf_argv[pdf_argc++] = (char *)"-paperw";
568 pdf_argv[pdf_argc++] = pdf_width;
569 pdf_argv[pdf_argc++] = (char *)"-paperh";
570 pdf_argv[pdf_argc++] = pdf_height;
571 pdf_argv[pdf_argc++] = (char *)"-expand";
574 else if (renderer == GS)
578 snprintf(pdf_width, sizeof(pdf_width), "-dDEVICEWIDTHPOINTS=%.0f",
580 snprintf(pdf_height, sizeof(pdf_height), "-dDEVICEHEIGHTPOINTS=%.0f",
585 snprintf(pdf_width, sizeof(pdf_width), "-dDEVICEWIDTHPOINTS=%.0f",
587 snprintf(pdf_height, sizeof(pdf_height), "-dDEVICEHEIGHTPOINTS=%.0f",
591 pdf_argv[pdf_argc++] = pdf_width;
592 pdf_argv[pdf_argc++] = pdf_height;
597 snprintf(pdf_widthxheight, sizeof(pdf_widthxheight), "%.0fx%.0f",
598 size->length, size->width);
600 snprintf(pdf_widthxheight, sizeof(pdf_widthxheight), "%.0fx%.0f",
601 size->width, size->length);
603 pdf_argv[pdf_argc++] = (char *)"-size";
604 pdf_argv[pdf_argc++] = pdf_widthxheight;
607 #ifdef HAVE_POPPLER_PDFTOPS_WITH_ORIGPAGESIZES
608 else if (renderer == PDFTOPS)
611 * Use the page sizes of the original PDF document, this way documents
612 * which contain pages of different sizes can be printed correctly
615 pdf_argv[pdf_argc++] = (char *)"-origpagesizes";
617 #endif /* HAVE_POPPLER_PDFTOPS_WITH_ORIGPAGESIZES */
618 else if (renderer == ACROREAD)
621 * Use the page sizes of the original PDF document, this way documents
622 * which contain pages of different sizes can be printed correctly
625 pdf_argv[pdf_argc++] = (char *)"-choosePaperByPDFPageSize";
629 * Set output resolution ...
632 /* Ignore error exits of cupsRasterInterpretPPD(), if it found a resolution
633 setting before erroring it is OK for us */
634 cupsRasterInterpretPPD(&header, ppd, num_options, options, NULL);
635 /* 100 dpi is default, this means that if we have 100 dpi here this
636 method failed to find the printing resolution */
637 if (header.HWResolution[0] > 100 && header.HWResolution[1] > 100)
639 xres = header.HWResolution[0];
640 yres = header.HWResolution[1];
642 else if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL)
643 strncpy(resolution, choice->choice, sizeof(resolution));
644 else if ((attr = ppdFindAttr(ppd,"DefaultResolution",NULL)) != NULL)
645 strncpy(resolution, attr->value, sizeof(resolution));
648 resolution[sizeof(resolution)-1] = '\0';
649 if ((xres > 0) || (yres > 0) ||
650 ((numvalues = sscanf(resolution, "%dx%d", &xres, &yres)) > 0))
652 if ((yres > 0) && (xres > yres)) xres = yres;
658 * Get the ceiling for the image rendering resolution
661 if ((val = cupsGetOption("pdftops-max-image-resolution", num_options, options)) != NULL)
663 if ((numvalues = sscanf(val, "%d", &yres)) > 0)
667 "WARNING: Invalid value for \"pdftops-max-image-resolution\": \"%s\"\n", val);
671 * Reduce the image rendering resolution to not exceed a given maximum
672 * to make processing of jobs by the PDF->PS converter and the printer faster
674 * maxres = 0 means no limit
678 while (xres > maxres)
681 if (renderer == PDFTOPS)
683 #ifdef HAVE_POPPLER_PDFTOPS_WITH_RESOLUTION
685 * Set resolution to avoid slow processing by the printer when the
686 * resolution of embedded images does not match the printer's resolution
688 pdf_argv[pdf_argc++] = (char *)"-r";
689 snprintf(resolution, sizeof(resolution), "%d", xres);
690 pdf_argv[pdf_argc++] = resolution;
691 fprintf(stderr, "DEBUG: Using image rendering resolution %d dpi\n", xres);
692 #endif /* HAVE_POPPLER_PDFTOPS_WITH_RESOLUTION */
693 pdf_argv[pdf_argc++] = filename;
694 pdf_argv[pdf_argc++] = (char *)"-";
696 else if (renderer == GS)
699 * Set resolution to avoid slow processing by the printer when the
700 * resolution of embedded images does not match the printer's resolution
702 snprintf(resolution, 127, "-r%d", xres);
703 pdf_argv[pdf_argc++] = resolution;
704 fprintf(stderr, "DEBUG: Using image rendering resolution %d dpi\n", xres);
706 * PostScript debug mode: If you send a job with "lpr -o psdebug" Ghostscript
707 * will not compress the pages, so that the PostScript code can get
708 * analysed. This is especially important if a PostScript printer errors or
709 * misbehaves on Ghostscript's output.
710 * On Kyocera printers we always suppress page compression, to avoid slow
711 * processing of raster images.
713 val = cupsGetOption("psdebug", num_options, options);
714 if ((val && strcasecmp(val, "no") && strcasecmp(val, "off") &&
715 strcasecmp(val, "false")) ||
716 (ppd && ppd->manufacturer &&
717 !strncasecmp(ppd->manufacturer, "Kyocera", 7)))
719 fprintf(stderr, "DEBUG: Deactivated compression of pages in Ghostscript's PostScript output (\"psdebug\" debug mode or Kyocera printer)\n");
720 pdf_argv[pdf_argc++] = (char *)"-dCompressPages=false";
723 * The PostScript interpreters on many printers have bugs which make
724 * the interpreter crash, error out, or otherwise misbehave on too
725 * heavily compressed input files, especially if code with compressed
726 * elements is compressed again. Therefore we reduce compression here.
728 pdf_argv[pdf_argc++] = (char *)"-dCompressFonts=false";
729 pdf_argv[pdf_argc++] = (char *)"-dNoT3CCITT";
730 if (ppd && ppd->manufacturer &&
731 !strncasecmp(ppd->manufacturer, "Brother", 7))
733 fprintf(stderr, "DEBUG: Deactivation of Ghostscript's image compression for Brother printers to workarounmd PS interpreter bug\n");
734 pdf_argv[pdf_argc++] = (char *)"-dEncodeMonoImages=false";
735 pdf_argv[pdf_argc++] = (char *)"-dEncodeColorImages=false";
737 pdf_argv[pdf_argc++] = (char *)"-c";
738 pdf_argv[pdf_argc++] = (char *)"save pop";
739 pdf_argv[pdf_argc++] = (char *)"-f";
740 pdf_argv[pdf_argc++] = filename;
742 /* acroread has to read from stdin */
744 pdf_argv[pdf_argc] = NULL;
747 * Do we need post-processing of the PostScript output to work around bugs
748 * of the printer's PostScript interpreter?
751 if (renderer == PDFTOPS)
753 else if (renderer == GS)
755 (ppd && ppd->manufacturer &&
756 (!strncasecmp(ppd->manufacturer, "Kyocera", 7) ||
757 !strncasecmp(ppd->manufacturer, "Brother", 7)) ? 1 : 0);
762 * Execute "pdftops/gs | pstops [ | post-processing ]"...
765 if (pipe(pstops_pipe))
767 perror("DEBUG: Unable to create pipe for pstops");
775 if (pipe(post_proc_pipe))
777 perror("DEBUG: Unable to create pipe for post-processing");
784 if ((pdf_pid = fork()) == 0)
787 * Child comes here...
792 dup2(post_proc_pipe[1], 1);
793 close(post_proc_pipe[0]);
794 close(post_proc_pipe[1]);
797 dup2(pstops_pipe[1], 1);
798 close(pstops_pipe[0]);
799 close(pstops_pipe[1]);
801 if (renderer == PDFTOPS)
803 execv(CUPS_POPPLER_PDFTOPS, pdf_argv);
804 perror("DEBUG: Unable to execute pdftops program");
806 else if (renderer == GS)
808 execv(CUPS_GHOSTSCRIPT, pdf_argv);
809 perror("DEBUG: Unable to execute gs program");
814 * use filename as stdin for acroread to force output to stdout
817 if ((fd = open(filename, O_RDONLY)))
823 execv(CUPS_ACROREAD, pdf_argv);
824 perror("DEBUG: Unable to execute acroread program");
829 else if (pdf_pid < 0)
835 if (renderer == PDFTOPS)
836 perror("DEBUG: Unable to execute pdftops program");
837 else if (renderer == GS)
838 perror("DEBUG: Unable to execute gs program");
840 perror("DEBUG: Unable to execute acroread program");
846 fprintf(stderr, "DEBUG: Started filter %s (PID %d)\n", pdf_argv[0], pdf_pid);
850 if ((post_proc_pid = fork()) == 0)
853 * Child comes here...
856 dup2(post_proc_pipe[0], 0);
857 close(post_proc_pipe[0]);
858 close(post_proc_pipe[1]);
859 dup2(pstops_pipe[1], 1);
860 close(pstops_pipe[0]);
861 close(pstops_pipe[1]);
863 fp = cupsFileStdin();
865 if (renderer == ACROREAD)
868 * Set %Title and %For from filter arguments since acroread inserts
869 * garbage for these when using -toPostScript
872 while ((bytes = cupsFileGetLine(fp, buffer, sizeof(buffer))) > 0 &&
873 strncmp(buffer, "%%BeginProlog", 13))
875 if (strncmp(buffer, "%%Title", 7) == 0)
876 printf("%%%%Title: %s\n", argv[3]);
877 else if (strncmp(buffer, "%%For", 5) == 0)
878 printf("%%%%For: %s\n", argv[2]);
880 printf("%s", buffer);
884 * Copy the rest of the file
886 while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
887 fwrite(buffer, 1, bytes, stdout);
893 * Copy everything until after initial comments (Prolog section)
895 while ((bytes = cupsFileGetLine(fp, buffer, sizeof(buffer))) > 0 &&
896 strncmp(buffer, "%%BeginProlog", 13) &&
897 strncmp(buffer, "%%EndProlog", 11) &&
898 strncmp(buffer, "%%BeginSetup", 12) &&
899 strncmp(buffer, "%%Page:", 7))
900 printf("%s", buffer);
905 * Insert PostScript interpreter bug fix code in the beginning of
906 * the Prolog section (before the first active PostScript code)
908 if (strncmp(buffer, "%%BeginProlog", 13))
910 /* No Prolog section, create one */
911 fprintf(stderr, "DEBUG: Adding Prolog section for workaround PostScript code\n");
912 puts("%%BeginProlog");
915 printf("%s", buffer);
917 if (renderer == GS && ppd && ppd->manufacturer)
921 * Kyocera printers have a bug in their PostScript interpreter
922 * making them crashing on PostScript input data generated by
923 * Ghostscript's "ps2write" output device.
925 * The problem can be simply worked around by preceding the PostScript
926 * code with some extra bits.
928 * See https://bugs.launchpad.net/bugs/951627
930 * In addition, at least some of Kyocera's PostScript printers are
931 * very slow on rendering images which request interpolation. So we
932 * also add some code to eliminate interpolation requests.
934 * See https://bugs.launchpad.net/bugs/1026974
937 if (!strncasecmp(ppd->manufacturer, "Kyocera", 7))
939 fprintf(stderr, "DEBUG: Inserted workaround PostScript code for Kyocera printers\n");
940 puts("% ===== Workaround insertion by pdftops CUPS filter =====");
941 puts("% Kyocera's PostScript interpreter crashes on early name binding,");
942 puts("% so eliminate all \"bind\"s by redifining \"bind\" to no-op");
943 puts("/bind {} bind def");
944 puts("% Some Kyocera printers have an unacceptably slow implementation");
945 puts("% of image interpolation.");
948 puts(" dup /Interpolate known");
950 puts(" dup /Interpolate undef");
952 puts(" systemdict /image get exec");
958 * Brother printers have a bug in their PostScript interpreter
959 * making them printing one blank page if PostScript input data
960 * generated by Ghostscript's "ps2write" output device is used.
962 * The problem can be simply worked around by preceding the PostScript
963 * code with some extra bits.
965 * See https://bugs.launchpad.net/bugs/950713
968 else if (!strncasecmp(ppd->manufacturer, "Brother", 7))
970 fprintf(stderr, "DEBUG: Inserted workaround PostScript code for Brother printers\n");
971 puts("% ===== Workaround insertion by pdftops CUPS filter =====");
972 puts("% Brother's PostScript interpreter spits out the current page");
973 puts("% and aborts the job on the \"currenthalftone\" operator, so redefine");
974 puts("% it to null");
975 puts("/currenthalftone {//null} bind def");
976 puts("/orig.sethalftone systemdict /sethalftone get def");
977 puts("/sethalftone {dup //null eq not {//orig.sethalftone}{pop} ifelse} bind def");
982 if (strncmp(buffer, "%%BeginProlog", 13))
984 /* Close newly created Prolog section */
985 if (strncmp(buffer, "%%EndProlog", 11))
987 printf("%s", buffer);
991 * Copy the rest of the file
993 while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
994 fwrite(buffer, 1, bytes, stdout);
1000 else if (post_proc_pid < 0)
1006 perror("DEBUG: Unable to execute post-processing process");
1012 fprintf(stderr, "DEBUG: Started post-processing (PID %d)\n", post_proc_pid);
1015 if ((pstops_pid = fork()) == 0)
1018 * Child comes here...
1023 close(post_proc_pipe[0]);
1024 close(post_proc_pipe[1]);
1026 dup2(pstops_pipe[0], 0);
1027 close(pstops_pipe[0]);
1028 close(pstops_pipe[1]);
1030 execv(pstops_path, pstops_argv);
1031 perror("DEBUG: Unable to execute pstops program");
1035 else if (pstops_pid < 0)
1041 perror("DEBUG: Unable to execute pstops program");
1047 fprintf(stderr, "DEBUG: Started filter pstops (PID %d)\n", pstops_pid);
1049 close(pstops_pipe[0]);
1050 close(pstops_pipe[1]);
1053 close(post_proc_pipe[0]);
1054 close(post_proc_pipe[1]);
1058 * Wait for the child processes to exit...
1061 wait_children = 2 + need_post_proc;
1063 while (wait_children > 0)
1066 * Wait until we get a valid process ID or the job is canceled...
1069 while ((wait_pid = wait(&wait_status)) < 0 && errno == EINTR)
1073 kill(pdf_pid, SIGTERM);
1075 kill(post_proc_pid, SIGTERM);
1076 kill(pstops_pid, SIGTERM);
1088 * Report child status...
1093 if (WIFEXITED(wait_status))
1095 exit_status = WEXITSTATUS(wait_status);
1097 fprintf(stderr, "DEBUG: PID %d (%s) stopped with status %d!\n",
1099 wait_pid == pdf_pid ? (renderer == PDFTOPS ? "pdftops" :
1100 (renderer == GS ? "gs" : "acroread")) :
1101 (wait_pid == pstops_pid ? "pstops" : "Post-processing"),
1104 else if (WTERMSIG(wait_status) == SIGTERM)
1107 "DEBUG: PID %d (%s) was terminated normally with signal %d!\n",
1109 wait_pid == pdf_pid ? (renderer == PDFTOPS ? "pdftops" :
1110 (renderer == GS ? "gs" : "acroread")) :
1111 (wait_pid == pstops_pid ? "pstops" : "Post-processing"),
1116 exit_status = WTERMSIG(wait_status);
1118 fprintf(stderr, "DEBUG: PID %d (%s) crashed on signal %d!\n", wait_pid,
1119 wait_pid == pdf_pid ? (renderer == PDFTOPS ? "pdftops" :
1120 (renderer == GS ? "gs" : "acroread")) :
1121 (wait_pid == pstops_pid ? "pstops" : "Post-processing"),
1127 fprintf(stderr, "DEBUG: PID %d (%s) exited with no errors.\n", wait_pid,
1128 wait_pid == pdf_pid ? (renderer == PDFTOPS ? "pdftops" :
1129 (renderer == GS ? "gs" : "acroread")) :
1130 (wait_pid == pstops_pid ? "pstops" : "Post-processing"));
1135 * Cleanup and exit...
1143 return (exit_status);
1148 * 'cancel_job()' - Flag the job as canceled.
1152 cancel_job(int sig) /* I - Signal number (unused) */