3
* Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
4
* Copyright (C) 2008 Lars Uebernickel <larsuebernickel@gmx.de>
6
* This file is part of foomatic-rip.
8
* Foomatic-rip is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* Foomatic-rip is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the
20
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
* Boston, MA 02111-1307, USA.
24
#include "foomaticrip.h"
36
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
39
static int wait_for_renderer();
42
static int pdf_count_pages(const char *filename)
44
char gscommand[CMDLINE_MAX];
49
snprintf(gscommand, CMDLINE_MAX, "%s -dNODISPLAY -q -c "
50
"'/pdffile (%s) (r) file def pdfdict begin pdffile pdfopen begin "
51
"(PageCount: ) print pdfpagecount == flush currentdict pdfclose "
55
FILE *pd = popen(gscommand, "r");
57
rip_die(EXIT_STARVED, "Failed to execute ghostscript to determine number of input pages!\n");
59
bytes = fread(output, 1, 31, pd);
62
if (bytes <= 0 || sscanf(output, "PageCount: %d", &pagecount) < 1)
71
static int start_renderer(const char *cmd)
76
_log("Starting renderer with command: %s\n", cmd);
77
kid3 = start_process("kid3", exec_kid3, (void *)cmd, NULL, NULL);
79
rip_die(EXIT_STARVED, "Could not start renderer\n");
84
static int wait_for_renderer()
88
waitpid(kid3, &status, 0);
90
if (!WIFEXITED(status)) {
91
_log("Kid3 did not finish normally.\n");
92
exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
95
_log("Kid3 exit status: %d\n", WEXITSTATUS(status));
96
if (WEXITSTATUS(status) != 0)
97
exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
104
* Extract pages 'first' through 'last' from the pdf and write them into a
107
static int pdf_extract_pages(char filename[PATH_MAX],
108
const char *pdffilename,
112
char gscommand[CMDLINE_MAX];
113
char filename_arg[PATH_MAX], first_arg[50], last_arg[50];
116
_log("Extracting pages %d through %d\n", first, last);
118
snprintf(filename, PATH_MAX, "%s/foomatic-XXXXXX", temp_dir());
119
if ((fd = mkstemp(filename)) == -1)
120
rip_die(EXIT_STARVED, "Unable to create temporary file!\n");
123
snprintf(filename_arg, PATH_MAX, "-sOutputFile=%s", filename);
124
snprintf(first_arg, 50, "-dFirstPage=%d", first);
126
snprintf(last_arg, 50, "-dLastPage=%d", last);
130
snprintf(gscommand, CMDLINE_MAX, "%s -q -dNOPAUSE -dBATCH -dPARANOIDSAFER -dNOINTERPOLATE"
131
"-sDEVICE=pdfwrite %s %s %s %s",
132
gspath, filename_arg, first_arg, last_arg, pdffilename);
134
FILE *pd = popen(gscommand, "r");
136
rip_die(EXIT_STARVED, "Could not run ghostscript to extract the pages!\n");
142
static int render_pages_with_generic_command(dstr_t *cmd,
143
const char *filename,
147
char tmpfile[PATH_MAX];
150
/* TODO it might be a good idea to give pdf command lines the possibility
151
* to get the file on the command line rather than piped through stdin
152
* (maybe introduce a &filename; ??) */
154
if (lastpage < 0) /* i.e. print the whole document */
155
dstrcatf(cmd, " < %s", filename);
158
if (!pdf_extract_pages(tmpfile, filename, firstpage, lastpage))
159
rip_die(EXIT_STARVED, "Could not run ghostscript to extract the pages!\n");
160
dstrcatf(cmd, " < %s", tmpfile);
163
result = start_renderer(cmd->data);
171
static int render_pages_with_ghostscript(dstr_t *cmd,
174
const char *filename,
180
/* No need to create a temporary file, just give ghostscript the file and
181
* first/last page on the command line */
183
/* Some command lines want to read from stdin */
184
for (p = &cmd->data[end_gs_cmd -1]; isspace(*p); p--)
189
dstrinsertf(cmd, end_gs_cmd, " %s ", filename);
192
dstrinsertf(cmd, start_gs_cmd +2,
193
" -dFirstPage=%d -dLastPage=%d ",
194
firstpage, lastpage);
196
dstrinsertf(cmd, start_gs_cmd +2,
197
" -dFirstPage=%d ", firstpage);
199
return start_renderer(cmd->data);
202
static int render_pages(const char *filename, int firstpage, int lastpage)
204
dstr_t *cmd = create_dstr();
208
build_commandline(optionset("currentpage"), cmd, 1);
210
extract_command(&start, &end, cmd->data, "gs");
212
/* command is not Ghostscript */
213
result = render_pages_with_generic_command(cmd,
218
/* Ghostscript command, tell it which pages we want to render */
219
result = render_pages_with_ghostscript(cmd,
230
static int print_pdf_file(const char *filename)
235
page_count = pdf_count_pages(filename);
238
rip_die(EXIT_JOBERR, "Unable to determine number of pages, page count: %d\n", page_count);
239
_log("File contains %d pages\n", page_count);
241
optionset_copy_values(optionset("header"), optionset("currentpage"));
242
optionset_copy_values(optionset("currentpage"), optionset("previouspage"));
244
for (i = 1; i <= page_count; i++)
246
set_options_for_page(optionset("currentpage"), i);
247
if (!optionset_equal(optionset("currentpage"), optionset("previouspage"), 1))
249
render_pages(filename, firstpage, i);
252
optionset_copy_values(optionset("currentpage"), optionset("previouspage"));
255
render_pages(filename, 1, -1); /* Render the whole document */
257
render_pages(filename, firstpage, page_count);
264
int print_pdf(FILE *s,
265
const char *alreadyread,
267
const char *filename,
270
char tmpfilename[PATH_MAX] = "";
273
/* If reading from stdin, write everything into a temporary file */
274
/* TODO don't do this if there aren't any pagerange-limited options */
280
snprintf(tmpfilename, PATH_MAX, "%s/foomatic-XXXXXX", temp_dir());
281
fd = mkstemp(tmpfilename);
283
_log("Could not create temporary file: %s\n", strerror(errno));
284
return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
287
tmpfile = fdopen(fd, "r+");
288
copy_file(tmpfile, stdin, alreadyread, len);
291
filename = tmpfilename;
294
result = print_pdf_file(filename);
296
if (!isempty(tmpfilename))