2
* "$Id: pdftops.c 9793 2011-05-20 03:49:49Z mike $"
4
* PDF to PostScript filter front-end for CUPS.
6
* Copyright 2007-2011 by Apple Inc.
7
* Copyright 1997-2006 by Easy Software Products.
9
* These coded instructions, statements, and computer programs are the
10
* property of Apple Inc. and are protected by Federal copyright
11
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
12
* which should have been included with this file. If this file is
13
* file is missing or damaged, see the license at "http://www.cups.org/".
17
* main() - Main entry for filter...
18
* cancel_job() - Flag the job as canceled.
22
* Include necessary headers...
25
#include <cups/cups.h>
27
#include <cups/string-private.h>
28
#include <cups/language-private.h>
38
static void cancel_job(int sig);
45
static int job_canceled = 0;
49
* 'main()' - Main entry for filter...
52
int /* O - Exit status */
53
main(int argc, /* I - Number of command-line args */
54
char *argv[]) /* I - Command-line arguments */
56
int fd; /* Copy file descriptor */
57
char *filename, /* PDF file to convert */
58
tempfile[1024]; /* Temporary file */
59
char buffer[8192]; /* Copy buffer */
60
int bytes; /* Bytes copied */
61
int num_options; /* Number of options */
62
cups_option_t *options; /* Options */
63
const char *val; /* Option value */
64
int orientation, /* Output orientation */
65
fit; /* Fit output to default page size? */
66
ppd_file_t *ppd; /* PPD file */
67
ppd_size_t *size; /* Current page size */
68
int pdf_pid, /* Process ID for pdftops */
69
pdf_argc, /* Number of args for pdftops */
70
pstops_pid, /* Process ID of pstops filter */
71
pstops_pipe[2], /* Pipe to pstops filter */
72
wait_children, /* Number of child processes left */
73
wait_pid, /* Process ID from wait() */
74
wait_status, /* Status from child */
75
exit_status = 0; /* Exit status */
76
char *pdf_argv[100], /* Arguments for pdftops/gs */
77
pdf_width[255], /* Paper width */
78
pdf_height[255], /* Paper height */
79
pstops_path[1024], /* Path to pstops program */
80
*pstops_argv[7], /* Arguments for pstops filter */
81
*pstops_options, /* Options for pstops filter */
82
*pstops_start, /* Start of pstops filter option */
83
*pstops_end; /* End of pstops filter option */
84
const char *cups_serverbin; /* CUPS_SERVERBIN environment variable */
85
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
86
struct sigaction action; /* Actions for POSIX signals */
87
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
91
* Make sure status messages are not buffered...
97
* Ignore broken pipe signals...
100
signal(SIGPIPE, SIG_IGN);
103
* Make sure we have the right number of arguments for CUPS!
106
if (argc < 6 || argc > 7)
108
_cupsLangPrintf(stderr,
109
_("Usage: %s job user title copies options [filename]"),
115
* Register a signal handler to cleanly cancel a job.
118
#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
119
sigset(SIGTERM, cancel_job);
120
#elif defined(HAVE_SIGACTION)
121
memset(&action, 0, sizeof(action));
123
sigemptyset(&action.sa_mask);
124
action.sa_handler = cancel_job;
125
sigaction(SIGTERM, &action, NULL);
127
signal(SIGTERM, cancel_job);
128
#endif /* HAVE_SIGSET */
131
* Copy stdin if needed...
137
* Copy stdin to a temp file...
140
if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
142
perror("DEBUG: Unable to copy PDF file");
146
fprintf(stderr, "DEBUG: pdftops - copying to temp print file \"%s\"\n",
149
while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
150
write(fd, buffer, bytes);
159
* Use the filename on the command-line...
167
* Load the PPD file and mark options...
170
ppd = ppdOpenFile(getenv("PPD"));
171
num_options = cupsParseOptions(argv[5], 0, &options);
173
ppdMarkDefaults(ppd);
174
cupsMarkOptions(ppd, num_options, options);
177
* Build the pstops command-line...
180
if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
181
cups_serverbin = CUPS_SERVERBIN;
183
snprintf(pstops_path, sizeof(pstops_path), "%s/filter/pstops",
186
pstops_options = strdup(argv[5]);
188
if ((pstops_start = strstr(pstops_options, "fitplot")) != NULL &&
189
(!pstops_start[7] || isspace(pstops_start[7] & 255)))
192
* Strip [no]fitplot option...
195
pstops_end = pstops_start + 7;
197
if ((pstops_start - pstops_options) >= 2 &&
198
!strncmp(pstops_start - 2, "no", 2))
201
while (*pstops_end && isspace(*pstops_end & 255))
204
_cups_strcpy(pstops_start, pstops_end);
207
if ((pstops_start = strstr(pstops_options, "fit-to-page")) != NULL &&
208
(!pstops_start[11] || isspace(pstops_start[11] & 255)))
211
* Strip [no]fit-to-page option...
214
pstops_end = pstops_start + 11;
216
if ((pstops_start - pstops_options) >= 2 &&
217
!strncmp(pstops_start - 2, "no", 2))
220
while (*pstops_end && isspace(*pstops_end & 255))
223
_cups_strcpy(pstops_start, pstops_end);
226
if ((pstops_start = strstr(pstops_options, "landscape")) != NULL &&
227
(!pstops_start[9] || isspace(pstops_start[9] & 255)))
230
* Strip [no]landscape option...
233
pstops_end = pstops_start + 9;
235
if ((pstops_start - pstops_options) >= 2 &&
236
!strncmp(pstops_start - 2, "no", 2))
239
while (*pstops_end && isspace(*pstops_end & 255))
242
_cups_strcpy(pstops_start, pstops_end);
245
if ((pstops_start = strstr(pstops_options, "orientation-requested=")) != NULL)
248
* Strip [no]fitplot option...
251
pstops_end = pstops_start + 22;
252
while (*pstops_end && !isspace(*pstops_end & 255))
255
_cups_strcpy(pstops_start, pstops_end);
258
pstops_argv[0] = argv[0]; /* Printer */
259
pstops_argv[1] = argv[1]; /* Job */
260
pstops_argv[2] = argv[2]; /* User */
261
pstops_argv[3] = argv[3]; /* Title */
262
pstops_argv[4] = argv[4]; /* Copies */
263
pstops_argv[5] = pstops_options; /* Options */
264
pstops_argv[6] = NULL;
267
* Build the command-line for the pdftops or gs filter...
271
pdf_argv[0] = (char *)"pdftops";
274
pdf_argv[0] = (char *)"gs";
275
pdf_argv[1] = (char *)"-q";
276
pdf_argv[2] = (char *)"-dNOPAUSE";
277
pdf_argv[3] = (char *)"-dBATCH";
278
pdf_argv[4] = (char *)"-dSAFER";
279
# ifdef HAVE_GHOSTSCRIPT_PS2WRITE
280
pdf_argv[5] = (char *)"-sDEVICE=ps2write";
282
pdf_argv[5] = (char *)"-sDEVICE=pswrite";
283
# endif /* HAVE_GHOSTSCRIPT_PS2WRITE */
284
pdf_argv[6] = (char *)"-sOUTPUTFILE=%stdout";
286
#endif /* HAVE_PDFTOPS */
291
* Set language level and TrueType font handling...
294
if (ppd->language_level == 1)
297
pdf_argv[pdf_argc++] = (char *)"-level1";
298
pdf_argv[pdf_argc++] = (char *)"-noembtt";
300
pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=1";
301
#endif /* HAVE_PDFTOPS */
303
else if (ppd->language_level == 2)
306
pdf_argv[pdf_argc++] = (char *)"-level2";
307
if (!ppd->ttrasterizer)
308
pdf_argv[pdf_argc++] = (char *)"-noembtt";
310
pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=2";
311
#endif /* HAVE_PDFTOPS */
315
pdf_argv[pdf_argc++] = (char *)"-level3";
317
pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=3";
318
#endif /* HAVE_PDFTOPS */
320
if ((val = cupsGetOption("fitplot", num_options, options)) == NULL)
321
val = cupsGetOption("fit-to-page", num_options, options);
323
if (val && _cups_strcasecmp(val, "no") && _cups_strcasecmp(val, "off") &&
324
_cups_strcasecmp(val, "false"))
330
* Set output page size...
333
size = ppdPageSize(ppd, NULL);
337
* Got the size, now get the orientation...
342
if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
344
if (_cups_strcasecmp(val, "no") != 0 && _cups_strcasecmp(val, "off") != 0 &&
345
_cups_strcasecmp(val, "false") != 0)
348
else if ((val = cupsGetOption("orientation-requested", num_options,
352
* Map IPP orientation values to 0 to 3:
356
* 5 = -90 degrees = 3
357
* 6 = 180 degrees = 2
360
orientation = atoi(val) - 3;
361
if (orientation >= 2)
368
snprintf(pdf_width, sizeof(pdf_width), "%.0f", size->length);
369
snprintf(pdf_height, sizeof(pdf_height), "%.0f", size->width);
373
snprintf(pdf_width, sizeof(pdf_width), "%.0f", size->width);
374
snprintf(pdf_height, sizeof(pdf_height), "%.0f", size->length);
377
pdf_argv[pdf_argc++] = (char *)"-paperw";
378
pdf_argv[pdf_argc++] = pdf_width;
379
pdf_argv[pdf_argc++] = (char *)"-paperh";
380
pdf_argv[pdf_argc++] = pdf_height;
381
pdf_argv[pdf_argc++] = (char *)"-expand";
386
snprintf(pdf_width, sizeof(pdf_width), "-dDEVICEWIDTHPOINTS=%.0f",
388
snprintf(pdf_height, sizeof(pdf_height), "-dDEVICEHEIGHTPOINTS=%.0f",
393
snprintf(pdf_width, sizeof(pdf_width), "-dDEVICEWIDTHPOINTS=%.0f",
395
snprintf(pdf_height, sizeof(pdf_height), "-dDEVICEHEIGHTPOINTS=%.0f",
399
pdf_argv[pdf_argc++] = pdf_width;
400
pdf_argv[pdf_argc++] = pdf_height;
401
#endif /* HAVE_PDFTOPS */
403
#if defined(HAVE_PDFTOPS) && defined(HAVE_PDFTOPS_WITH_ORIGPAGESIZES)
407
* Use the page sizes of the original PDF document, this way documents
408
* which contain pages of different sizes can be printed correctly
411
pdf_argv[pdf_argc++] = (char *)"-origpagesizes";
413
#endif /* HAVE_PDFTOPS && HAVE_PDFTOPS_WITH_ORIGPAGESIZES */
417
pdf_argv[pdf_argc++] = filename;
418
pdf_argv[pdf_argc++] = (char *)"-";
420
pdf_argv[pdf_argc++] = (char *)"-c";
421
pdf_argv[pdf_argc++] = (char *)"save pop";
422
pdf_argv[pdf_argc++] = (char *)"-f";
423
pdf_argv[pdf_argc++] = filename;
424
#endif /* HAVE_PDFTOPS */
426
pdf_argv[pdf_argc] = NULL;
429
* Execute "pdftops/gs | pstops"...
432
if (pipe(pstops_pipe))
434
perror("DEBUG: Unable to create pipe");
440
if ((pdf_pid = fork()) == 0)
443
* Child comes here...
446
dup2(pstops_pipe[1], 1);
447
close(pstops_pipe[0]);
448
close(pstops_pipe[1]);
451
execv(CUPS_PDFTOPS, pdf_argv);
452
perror("DEBUG: Unable to execute pdftops program");
454
execv(CUPS_GHOSTSCRIPT, pdf_argv);
455
perror("DEBUG: Unable to execute gs program");
456
#endif /* HAVE_PDFTOPS */
460
else if (pdf_pid < 0)
467
perror("DEBUG: Unable to execute pdftops program");
469
perror("DEBUG: Unable to execute gs program");
470
#endif /* HAVE_PDFTOPS */
476
fprintf(stderr, "DEBUG: Started filter %s (PID %d)\n", pdf_argv[0], pdf_pid);
478
if ((pstops_pid = fork()) == 0)
481
* Child comes here...
484
dup2(pstops_pipe[0], 0);
485
close(pstops_pipe[0]);
486
close(pstops_pipe[1]);
488
execv(pstops_path, pstops_argv);
489
perror("DEBUG: Unable to execute pstops program");
493
else if (pstops_pid < 0)
499
perror("DEBUG: Unable to execute pstops program");
505
fprintf(stderr, "DEBUG: Started filter pstops (PID %d)\n", pstops_pid);
507
close(pstops_pipe[0]);
508
close(pstops_pipe[1]);
511
* Wait for the child processes to exit...
516
while (wait_children > 0)
519
* Wait until we get a valid process ID or the job is canceled...
522
while ((wait_pid = wait(&wait_status)) < 0 && errno == EINTR)
526
kill(pdf_pid, SIGTERM);
527
kill(pstops_pid, SIGTERM);
539
* Report child status...
544
if (WIFEXITED(wait_status))
546
exit_status = WEXITSTATUS(wait_status);
548
fprintf(stderr, "DEBUG: PID %d (%s) stopped with status %d!\n",
551
wait_pid == pdf_pid ? "pdftops" : "pstops",
553
wait_pid == pdf_pid ? "gs" : "pstops",
554
#endif /* HAVE_PDFTOPS */
557
else if (WTERMSIG(wait_status) == SIGTERM)
560
"DEBUG: PID %d (%s) was terminated normally with signal %d!\n",
563
wait_pid == pdf_pid ? "pdftops" : "pstops",
565
wait_pid == pdf_pid ? "gs" : "pstops",
566
#endif /* HAVE_PDFTOPS */
571
exit_status = WTERMSIG(wait_status);
573
fprintf(stderr, "DEBUG: PID %d (%s) crashed on signal %d!\n", wait_pid,
575
wait_pid == pdf_pid ? "pdftops" : "pstops",
577
wait_pid == pdf_pid ? "gs" : "pstops",
578
#endif /* HAVE_PDFTOPS */
584
fprintf(stderr, "DEBUG: PID %d (%s) exited with no errors.\n", wait_pid,
586
wait_pid == pdf_pid ? "pdftops" : "pstops");
588
wait_pid == pdf_pid ? "gs" : "pstops");
589
#endif /* HAVE_PDFTOPS */
594
* Cleanup and exit...
602
return (exit_status);
607
* 'cancel_job()' - Flag the job as canceled.
611
cancel_job(int sig) /* I - Signal number (unused) */
620
* End of "$Id: pdftops.c 9793 2011-05-20 03:49:49Z mike $".