1 /*---------------------------------------------------------------------------*
2 | PDFlib - A library for generating PDF on the fly |
3 +---------------------------------------------------------------------------+
4 | Copyright (c) 2000-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
5 +---------------------------------------------------------------------------+
6 | |
7 | This software is subject to the PDFlib license. It is NOT in the |
8 | public domain. Extended versions and commercial licenses are |
9 | available, please check http://www.pdflib.com. |
10 | |
11 *---------------------------------------------------------------------------*/
12
13 /* $Id: pdfimpose.c,v 1.22.2.2 2008/05/27 09:10:37 kurt Exp $
14 *
15 * Impose multiple PDF documents on a single sheet,
16 * or concatenate multiple PDFs (if no -g option is supplied),
17 * or create PDF/A from one or more PDF/A input documents.
18 *
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #if defined(__CYGWIN32__)
26 #include <getopt.h>
27 #elif defined(WIN32)
28 int getopt(int argc, char * const argv[], const char *optstring);
29 extern char *optarg;
30 extern int optind;
31 #elif !defined(WIN32) && !defined(MAC)
32 #include <unistd.h>
33 #endif
34
35 #include "pdflib.h"
36
37 static void
usage(void)38 usage(void)
39 {
40 fprintf(stderr,
41
42 "\npdfimpose: impose multiple PDF documents on a single sheet.\n"
43 "(c) PDFlib GmbH 2001-2006 www.pdflib.com\n"
44 "\n"
45 "usage: pdfimpose [options] pdffiles(s)\n"
46 "\n"
47 "Available options:\n"
48 "-a level PDF/A compatibility level: \"PDF/A-1b:2005\" or \"none\""
49 " default: none\n"
50 "-b print boxes around imposed pages\n"
51 "-g wxh number of columns and rows per sheet (default: 1x1)\n"
52 "-I <filename> name of a PDF/A file from which to copy the output intent\n"
53 " default: first PDF/A input file\n"
54 "-l landscape mode\n"
55 "-n start each document on a new page\n"
56 "-o <filename> PDF output file name\n"
57 "-p <pagesize> page format (a0-a6, letter, legal, etc.)\n"
58 "-q quiet mode: do not emit info messages\n"
59 "-v <version> PDF output version: 1.3, 1.4, 1.5, 1.6, 1.7\n");
60
61 exit(1);
62 }
63
64 int
main(int argc,char * argv[])65 main(int argc, char *argv[])
66 {
67 char *pdffilename = NULL;
68 char *pdfversion = NULL;
69 PDF *p;
70 int opt;
71 int doc, page;
72 int pageno, docpages;
73 char *filename, *intent=NULL;
74 int quiet = 0, landscape = 0, boxes = 0, newpage = 0;
75 int cols = 1, rows = 1;
76 int c = 0, r = 0;
77 double sheetwidth = 595.0, sheetheight = 842.0;
78 double width, height, scale = 1.0f;
79 double rowheight = 0.0f, colwidth = 0.0f;
80 char *pagesize = NULL;
81 char *pdfalevel = NULL;
82 char optlist[1024];
83
84 while ((opt = getopt(argc, argv, "a:bg:I:lnp:o:qv:")) != -1)
85 switch (opt) {
86 case 'a':
87 if (strcmp(optarg, "none"))
88 pdfalevel = optarg;
89 break;
90
91 case 'b':
92 boxes = 1;
93 break;
94
95 case 'g':
96 if (sscanf(optarg, "%dx%d", &rows, &cols) != 2) {
97 fprintf(stderr, "Error: Couldn't parse -g option.\n");
98 usage();
99 }
100 if (rows <= 0 || cols <= 0) {
101 fprintf(stderr, "Bad row or column number.\n");
102 usage();
103 }
104 break;
105
106 case 'I':
107 intent = optarg;
108 break;
109
110 case 'l':
111 landscape = 1;
112 break;
113
114 case 'n':
115 newpage = 1;
116 break;
117
118 case 'p':
119 pagesize = optarg;
120 break;
121
122 case 'o':
123 pdffilename = optarg;
124 break;
125
126 case 'v':
127 pdfversion = optarg;
128 break;
129
130 case 'q':
131 quiet = 1;
132 break;
133
134 case '?':
135 default:
136 usage();
137 }
138
139 if (optind == argc)
140 {
141 fprintf(stderr, "Error: no PDF files given.\n");
142 usage();
143 }
144
145 if (pdffilename == NULL)
146 {
147 fprintf(stderr, "Error: no PDF output file given.\n");
148 usage();
149 }
150
151 p = PDF_new();
152
153 PDF_TRY(p)
154 {
155
156 optlist[0] = 0;
157
158 if (pdfversion)
159 sprintf(optlist, "compatibility=%s ", pdfversion);
160
161 if (pdfalevel)
162 sprintf(optlist+strlen(optlist), "pdfa=%s ", pdfalevel);
163
164 if (PDF_begin_document(p, pdffilename, 0, optlist) == -1)
165 {
166 fprintf(stderr, "Error: %s.\n", PDF_get_errmsg(p));
167 exit(1);
168 }
169
170 if (pdfalevel)
171 {
172 int res;
173
174 /* Use intent from the first PDF if none specified */
175 if (!intent)
176 intent = argv[optind];
177
178 if (!quiet)
179 fprintf(stderr, "Using output intent from file '%s'.\n",
180 intent);
181
182 if ((doc = PDF_open_pdi_document(p, intent, 0, "infomode")) == -1)
183 {
184 if (!quiet)
185 fprintf(stderr, "Error: %s.\n", PDF_get_errmsg(p));
186 exit(99);
187 }
188
189 res = (int) PDF_pcos_get_number(p, doc, "type:/Root/OutputIntents");
190
191 if (res == pcos_ot_array)
192 {
193 res = PDF_process_pdi(p, doc, 0, "action=copyoutputintent");
194 if (res == -1)
195 {
196 if (!quiet)
197 fprintf(stderr, "Error: %s.\n", PDF_get_errmsg(p));
198 exit(99);
199 }
200 PDF_close_pdi_document(p, doc);
201 }
202 else
203 {
204 fprintf(stderr,
205 "No output intent found.\n");
206 }
207 }
208
209 PDF_set_info(p, "Creator", "pdfimpose by PDFlib GmbH");
210
211 PDF_set_parameter(p, "openaction", "fitpage");
212
213 /* multi-page imposition: calculate scaling factor and cell dimensions*/
214 if (rows != 1 || cols != 1)
215 {
216 if (landscape)
217 {
218 height = sheetheight;
219 sheetheight = sheetwidth;
220 sheetwidth = height;
221 }
222
223 if (rows > cols)
224 scale = 1.0f / rows;
225 else
226 scale = 1.0f / cols;
227
228 rowheight = sheetheight * scale;
229 colwidth = sheetwidth * scale;
230 }
231
232 /* process all PDF documents */
233 while (optind++ < argc)
234 {
235 filename = argv[optind-1];
236
237 if (!quiet)
238 fprintf(stderr, "Imposing '%s'...\n", filename);
239
240 if ((doc = PDF_open_pdi_document(p, filename, 0, "")) == -1)
241 {
242 if (!quiet)
243 fprintf(stderr, "Error: %s.\n", PDF_get_errmsg(p));
244 continue;
245 }
246
247 /* query number of pages in the document */
248 docpages = (int) PDF_pcos_get_number(p, doc, "/Root/Pages/Count");
249
250 /* single cell only: concatenate */
251 if (rows == 1 && cols == 1)
252 {
253 /* open all pages and add to the output file */
254 for (pageno = 1; pageno <= docpages ; pageno++)
255 {
256
257 page = PDF_open_pdi_page(p, doc, pageno, "");
258
259 if (page == -1)
260 {
261 if (!quiet)
262 fprintf(stderr, "Couldn't open page %d (%s)\n",
263 pageno, PDF_get_errmsg(p));
264 break;
265 }
266
267 sheetwidth = PDF_pcos_get_number(p, doc,
268 "pages[%d]/width", pageno-1);
269 sheetheight = PDF_pcos_get_number(p, doc,
270 "pages[%d]/height", pageno-1);
271
272 optlist[0] = 0;
273
274 if (pagesize)
275 {
276 sprintf(optlist, landscape ?
277 "width=%s.height height=%s.width " :
278 "width=%s.width height=%s.height ",
279 pagesize, pagesize);
280 }
281
282 PDF_begin_page_ext(p, sheetwidth, sheetheight, optlist);
283
284 /* define bookmark with filename */
285 if (pageno == 1)
286 PDF_create_bookmark(p, argv[optind-1], 0, "");
287
288 PDF_fit_pdi_page(p, page, 0.0f, 0.0f, "");
289 PDF_close_pdi_page(p, page);
290 PDF_end_page_ext(p, "");
291 }
292
293 }
294 else
295 { /* impose multiple pages */
296
297 if (newpage)
298 r = c = 0;
299
300 /* open all pages and add to the output file */
301 for (pageno = 1; pageno <= docpages ; pageno++) {
302
303 page = PDF_open_pdi_page(p, doc, pageno, "");
304
305 if (page == -1)
306 {
307 if (!quiet)
308 fprintf(stderr, "Couldn't open page %d (%s)\n",
309 pageno, PDF_get_errmsg(p));
310 break;
311 }
312
313 /* start a new page */
314 if (r == 0 && c == 0)
315 PDF_begin_page_ext(p, sheetwidth, sheetheight, "");
316
317 /* define bookmark with filename */
318 if (pageno == 1)
319 PDF_create_bookmark(p, argv[optind-1], 0, "");
320
321 width = PDF_pcos_get_number(p, doc,
322 "pages[%d]/width", pageno-1);
323 height = PDF_pcos_get_number(p, doc,
324 "pages[%d]/height", pageno-1);
325
326 /*
327 * The save/restore pair is required to get the clipping
328 * right, and helps PostScript printing manage its memory
329 * efficiently.
330 */
331 PDF_save(p);
332 PDF_rect(p, c * colwidth, sheetheight - (r + 1) * rowheight,
333 colwidth, rowheight);
334 PDF_clip(p);
335
336 if (pdfalevel)
337 PDF_setcolor(p,"stroke", "lab", 0.0f, 0.0f, 0.0f, 0.0f);
338 else
339 PDF_setcolor(p,"stroke","gray", 0.0f, 0.0f, 0.0f, 0.0f);
340
341 sprintf(optlist,
342 "boxsize {%f %f} position 0 fitmethod meet",
343 colwidth, rowheight);
344
345 PDF_fit_pdi_page(p, page,
346 c * colwidth, sheetheight - (r + 1) * rowheight,
347 optlist);
348
349 PDF_close_pdi_page(p, page);
350
351 /* only half of the linewidth will be drawn due to clip() */
352 if (boxes) {
353 PDF_setlinewidth(p, 1.0f * scale);
354 PDF_rect(p, c * colwidth,
355 sheetheight - (r + 1) * rowheight,
356 colwidth, rowheight);
357 PDF_stroke(p);
358 }
359
360 PDF_restore(p);
361
362 c++;
363 if (c == cols)
364 {
365 c = 0;
366 r++;
367 }
368 if (r == rows)
369 {
370 r = 0;
371 PDF_end_page_ext(p, "");
372 }
373 }
374 }
375
376 PDF_close_pdi_document(p, doc);
377 }
378
379 /* finish last page if multi-page imposition */
380 if ((rows != 1 || cols != 1) && (r != 0 || c != 0))
381 PDF_end_page_ext(p, "");
382
383 PDF_end_document(p, "");
384 }
385
386 PDF_CATCH(p)
387 {
388 printf("\npdfimpose: error while creating PDF output (%s(): %s)\n",
389 PDF_get_apiname(p), PDF_get_errmsg(p));
390 PDF_delete(p);
391 exit(99);
392 }
393
394 PDF_delete(p);
395 exit(0);
396 }
397