1 /*
2  * PDF merge tool: Tool for merging pdf content.
3  *
4  * Simple test bed to work with merging pages from multiple PDFs into a single PDF.
5  */
6 
7 #include "mupdf/fitz.h"
8 #include "mupdf/pdf.h"
9 
10 #include <stdlib.h>
11 #include <stdio.h>
12 
usage(void)13 static void usage(void)
14 {
15 	fprintf(stderr,
16 		"usage: mutool merge [-o output.pdf] [-O options] input.pdf [pages] [input2.pdf] [pages2] ...\n"
17 		"\t-o -\tname of PDF file to create\n"
18 		"\t-O -\tcomma separated list of output options\n"
19 		"\tinput.pdf\tname of input file from which to copy pages\n"
20 		"\tpages\tcomma separated list of page numbers and ranges\n\n"
21 		);
22 	fputs(fz_pdf_write_options_usage, stderr);
23 	exit(1);
24 }
25 
26 static fz_context *ctx = NULL;
27 static pdf_document *doc_des = NULL;
28 static pdf_document *doc_src = NULL;
29 
page_merge(int page_from,int page_to,pdf_graft_map * graft_map)30 static void page_merge(int page_from, int page_to, pdf_graft_map *graft_map)
31 {
32 	pdf_graft_mapped_page(ctx, graft_map, page_to - 1, doc_src, page_from - 1);
33 }
34 
merge_range(const char * range)35 static void merge_range(const char *range)
36 {
37 	int start, end, i, count;
38 	pdf_graft_map *graft_map;
39 
40 	count = pdf_count_pages(ctx, doc_src);
41 	graft_map = pdf_new_graft_map(ctx, doc_des);
42 
43 	fz_try(ctx)
44 	{
45 		while ((range = fz_parse_page_range(ctx, range, &start, &end, count)))
46 		{
47 			if (start < end)
48 				for (i = start; i <= end; ++i)
49 					page_merge(i, -1, graft_map);
50 			else
51 				for (i = start; i >= end; --i)
52 					page_merge(i, -1, graft_map);
53 		}
54 	}
55 	fz_always(ctx)
56 	{
57 		pdf_drop_graft_map(ctx, graft_map);
58 	}
59 	fz_catch(ctx)
60 	{
61 		fz_rethrow(ctx);
62 	}
63 }
64 
pdfmerge_main(int argc,char ** argv)65 int pdfmerge_main(int argc, char **argv)
66 {
67 	pdf_write_options opts = pdf_default_write_options;
68 	char *output = "out.pdf";
69 	char *flags = "";
70 	char *input;
71 	int c;
72 
73 	while ((c = fz_getopt(argc, argv, "o:O:")) != -1)
74 	{
75 		switch (c)
76 		{
77 		case 'o': output = fz_optarg; break;
78 		case 'O': flags = fz_optarg; break;
79 		default: usage(); break;
80 		}
81 	}
82 
83 	if (fz_optind == argc)
84 		usage();
85 
86 	ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
87 	if (!ctx)
88 	{
89 		fprintf(stderr, "error: Cannot initialize MuPDF context.\n");
90 		exit(1);
91 	}
92 
93 	pdf_parse_write_options(ctx, &opts, flags);
94 
95 	fz_try(ctx)
96 	{
97 		doc_des = pdf_create_document(ctx);
98 	}
99 	fz_catch(ctx)
100 	{
101 		fprintf(stderr, "error: Cannot create destination document.\n");
102 		fz_flush_warnings(ctx);
103 		fz_drop_context(ctx);
104 		exit(1);
105 	}
106 
107 	/* Step through the source files */
108 	while (fz_optind < argc)
109 	{
110 		doc_src = NULL;
111 		input = argv[fz_optind++];
112 
113 		fz_try(ctx)
114 		{
115 			doc_src = pdf_open_document(ctx, input);
116 			if (fz_optind == argc || !fz_is_page_range(ctx, argv[fz_optind]))
117 				merge_range("1-N");
118 			else
119 				merge_range(argv[fz_optind++]);
120 		}
121 		fz_always(ctx)
122 			pdf_drop_document(ctx, doc_src);
123 		fz_catch(ctx)
124 			fprintf(stderr, "error: Cannot merge document '%s'.\n", input);
125 	}
126 
127 	if (fz_optind == argc)
128 	{
129 		fz_try(ctx)
130 			pdf_save_document(ctx, doc_des, output, &opts);
131 		fz_catch(ctx)
132 			fprintf(stderr, "error: Cannot save output file: '%s'.\n", output);
133 	}
134 
135 	pdf_drop_document(ctx, doc_des);
136 	fz_flush_warnings(ctx);
137 	fz_drop_context(ctx);
138 	return 0;
139 }
140