1/*---------------------------------------------------------------------------* 2 | PDFlib - A library for generating PDF on the fly | 3 +---------------------------------------------------------------------------+ 4 | Copyright (c) 1997-2004 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 14574 2005-10-29 16:27:43Z bonefish $ 14 * 15 * Impose multiple PDF documents on a single sheet, 16 * or concatenate multiple PDFs (if no -g option is supplied) 17 * (requires the PDF import library PDI) 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) 28int getopt(int argc, char * const argv[], const char *optstring); 29extern char *optarg; 30extern int optind; 31#elif !defined(WIN32) && !defined(MAC) 32#include <unistd.h> 33#endif 34 35#include "pdflib.h" 36 37/* Array of known page sizes including name, width, and height */ 38 39typedef struct { const char *name; float width; float height; } PageSize_s; 40 41PageSize_s PageSizes[] = { 42 {"a0", 2380.0f, 3368.0f}, 43 {"a1", 1684.0f, 2380.0f}, 44 {"a2", 1190.0f, 1684.0f}, 45 {"a3", 842.0f, 1190.0f}, 46 {"a4", 595.0f, 842.0f}, 47 {"a5", 421.0f, 595.0f}, 48 {"a6", 297.0f, 421.0f}, 49 {"b5", 501.0f, 709.0f}, 50 {"letter", 612.0f, 792.0f}, 51 {"legal", 612.0f, 1008.0f}, 52 {"ledger", 1224.0f, 792.0f}, 53 {"p11x17", 792.0f, 1224.0f} 54}; 55 56#define PAGESIZELISTLEN (sizeof(PageSizes)/sizeof(PageSizes[0])) 57 58static void 59usage(void) 60{ 61 fprintf(stderr, 62 "\npdfimpose: impose multiple PDF documents on a single sheet.\n"); 63 fprintf(stderr, "(C) PDFlib GmbH and Thomas Merz 2001-2004\n"); 64 fprintf(stderr, "usage: pdfimpose [options] pdffiles(s)\n\n"); 65 fprintf(stderr, "Available options:\n"); 66 fprintf(stderr, "-b print boxes around imposed pages\n"); 67 fprintf(stderr, 68 "-g wxh number of columns and rows per sheet (default: 1x1)\n"); 69 fprintf(stderr, "-l landscape mode\n"); 70 fprintf(stderr, "-n start each document on a new page\n"); 71 fprintf(stderr, "-o <file> output file\n"); 72 fprintf(stderr, "-p <pagesize> page format (a0-a6, letter, legal, etc.)\n"); 73 fprintf(stderr, "-q quiet mode: do not emit info messages\n"); 74 fprintf(stderr, "-v <version> PDF output version: 1.3, 1.4, or 1.5\n"); 75 76 exit(1); 77} 78 79int 80main(int argc, char *argv[]) 81{ 82 char *pdffilename = NULL; 83 char *pdfversion = NULL; 84 PDF *p; 85 int opt; 86 int doc, page; 87 int pageno, docpages; 88 char *filename; 89 int quiet = 0, landscape = 0, boxes = 0, newpage = 0; 90 int cols = 1, rows = 1; 91 int c = 0, r = 0; 92 float sheetwidth = 595.0f, sheetheight = 842.0f; 93 float width, height, scale = 1.0f; 94 float rowheight = 0.0f, colwidth = 0.0f; 95 96 while ((opt = getopt(argc, argv, "bg:lnp:o:qv:")) != -1) 97 switch (opt) { 98 case 'b': 99 boxes = 1; 100 break; 101 102 case 'g': 103 if (sscanf(optarg, "%dx%d", &rows, &cols) != 2) { 104 fprintf(stderr, "Error: Couldn't parse -g option.\n"); 105 usage(); 106 } 107 if (rows <= 0 || cols <= 0) { 108 fprintf(stderr, "Bad row or column number.\n"); 109 usage(); 110 } 111 break; 112 113 case 'l': 114 landscape = 1; 115 break; 116 117 case 'n': 118 newpage = 1; 119 break; 120 121 case 'p': 122 for(c = 0; c < PAGESIZELISTLEN; c++) 123 if (!strcmp((const char *) optarg, PageSizes[c].name)) { 124 sheetheight = PageSizes[c].height; 125 sheetwidth = PageSizes[c].width; 126 break; 127 } 128 if (c == PAGESIZELISTLEN) { /* page size name not found */ 129 fprintf(stderr, "Error: Unknown page size '%s'.\n", optarg); 130 usage(); 131 } 132 break; 133 134 case 'o': 135 pdffilename = optarg; 136 break; 137 138 case 'v': 139 pdfversion = optarg; 140 if (strcmp(pdfversion, "1.3") && strcmp(pdfversion, "1.4") && 141 strcmp(pdfversion, "1.5")) { 142 fprintf(stderr, "Error: bad PDF version number '%s'.\n", 143 optarg); 144 usage(); 145 } 146 147 break; 148 149 case 'q': 150 quiet = 1; 151 break; 152 153 case '?': 154 default: 155 usage(); 156 } 157 158 if (optind == argc) { 159 fprintf(stderr, "Error: no PDF files given.\n"); 160 usage(); 161 } 162 163 if (pdffilename == NULL) { 164 fprintf(stderr, "Error: no PDF output file given.\n"); 165 usage(); 166 } 167 168 p = PDF_new(); 169 170 if (pdfversion) 171 PDF_set_parameter(p, "compatibility", pdfversion); 172 173 if (PDF_open_file(p, pdffilename) == -1) { 174 fprintf(stderr, "Error: %s.\n", PDF_get_errmsg(p)); 175 exit(1); 176 } 177 178 PDF_set_info(p, "Creator", "pdfimpose by PDFlib GmbH"); 179 180 PDF_set_parameter(p, "openaction", "fitpage"); 181 182 if (!quiet) 183 PDF_set_parameter(p, "pdiwarning", "true"); /* report PDI problems */ 184 185 /* multi-page imposition: calculate scaling factor and cell dimensions */ 186 if (rows != 1 || cols != 1) { 187 if (landscape) { 188 height = sheetheight; 189 sheetheight = sheetwidth; 190 sheetwidth = height; 191 } 192 193 if (rows > cols) 194 scale = 1.0f / rows; 195 else 196 scale = 1.0f / cols; 197 198 rowheight = sheetheight * scale; 199 colwidth = sheetwidth * scale; 200 } 201 202 /* process all PDF documents */ 203 while (optind++ < argc) { 204 filename = argv[optind-1]; 205 206 if (!quiet) 207 fprintf(stderr, "Imposing '%s'...\n", filename); 208 209 if ((doc = PDF_open_pdi(p, filename, "", 0)) == -1) { 210 if (quiet) 211 fprintf(stderr, "Error: %s.\n", PDF_get_errmsg(p)); 212 continue; 213 } 214 215 /* query number of pages in the document */ 216 docpages = (int) PDF_get_pdi_value(p, "/Root/Pages/Count", doc, -1, 0); 217 218 /* single cell only: concatenate, using original page dimensions */ 219 if (rows == 1 && cols == 1) { 220 /* open all pages and add to the output file */ 221 for (pageno = 1; pageno <= docpages ; pageno++) { 222 223 page = PDF_open_pdi_page(p, doc, pageno, ""); 224 225 if (page == -1) { 226 /* we'll get an exception in verbose mode anyway */ 227 if (quiet) 228 fprintf(stderr, 229 "Couldn't open page %d of PDF file '%s' (%s)\n", 230 pageno, filename, PDF_get_errmsg(p)); 231 break; 232 } 233 234 sheetwidth = PDF_get_pdi_value(p, "width", doc, page, 0); 235 sheetheight = PDF_get_pdi_value(p, "height", doc, page, 0); 236 237 PDF_begin_page(p, sheetwidth, sheetheight); 238 239 /* define bookmark with filename */ 240 if (pageno == 1) 241 PDF_add_bookmark(p, argv[optind-1], 0, 0); 242 243 PDF_place_pdi_page(p, page, 0.0f, 0.0f, 1.0f, 1.0f); 244 PDF_close_pdi_page(p, page); 245 PDF_end_page(p); 246 } 247 248 } else { /* impose multiple pages */ 249 250 if (newpage) 251 r = c = 0; 252 253 /* open all pages and add to the output file */ 254 for (pageno = 1; pageno <= docpages ; pageno++) { 255 256 page = PDF_open_pdi_page(p, doc, pageno, ""); 257 258 if (page == -1) { 259 /* we'll get an exception in verbose mode anyway */ 260 if (quiet) 261 fprintf(stderr, 262 "Couldn't open page %d of PDF file '%s' (%s)\n", 263 pageno, filename, PDF_get_errmsg(p)); 264 break; 265 } 266 267 /* start a new page */ 268 if (r == 0 && c == 0) 269 PDF_begin_page(p, sheetwidth, sheetheight); 270 271 /* define bookmark with filename */ 272 if (pageno == 1) 273 PDF_add_bookmark(p, argv[optind-1], 0, 0); 274 275 width = PDF_get_pdi_value(p, "width", doc, page, 0); 276 height = PDF_get_pdi_value(p, "height", doc, page, 0); 277 278 /* 279 * The save/restore pair is required to get the clipping right, 280 * and helps PostScript printing manage its memory efficiently. 281 */ 282 PDF_save(p); 283 PDF_rect(p, c * colwidth, sheetheight - (r + 1) * rowheight, 284 colwidth, rowheight); 285 PDF_clip(p); 286 287 PDF_setcolor(p, "stroke", "gray", 0.0f, 0.0f, 0.0f, 0.0f); 288 289 /* TODO: adjust scaling factor if page doesn't fit into cell */ 290 PDF_place_pdi_page(p, page, 291 c * colwidth, sheetheight - (r + 1) * rowheight, 292 scale, scale); 293 294 PDF_close_pdi_page(p, page); 295 296 /* only half of the linewidth will be drawn due to clip() */ 297 if (boxes) { 298 PDF_setlinewidth(p, 1.0f * scale); 299 PDF_rect(p, c * colwidth, 300 sheetheight - (r + 1) * rowheight, 301 colwidth, rowheight); 302 PDF_stroke(p); 303 } 304 305 PDF_restore(p); 306 307 c++; 308 if (c == cols) { 309 c = 0; 310 r++; 311 } 312 if (r == rows) { 313 r = 0; 314 PDF_end_page(p); 315 } 316 } 317 } 318 319 PDF_close_pdi(p, doc); 320 } 321 322 /* finish last page if multi-page imposition */ 323 if ((rows != 1 || cols != 1) && (r != 0 || c != 0)) 324 PDF_end_page(p); 325 326 PDF_close(p); 327 PDF_delete(p); 328 exit(0); 329} 330