1/*
2 * muconvert -- command line tool for converting documents
3 */
4
5#include "mupdf/fitz.h"
6
7#include <stdlib.h>
8#include <stdio.h>
9
10/* input options */
11static const char *password = "";
12static int alphabits = 8;
13static float layout_w = FZ_DEFAULT_LAYOUT_W;
14static float layout_h = FZ_DEFAULT_LAYOUT_H;
15static float layout_em = FZ_DEFAULT_LAYOUT_EM;
16static char *layout_css = NULL;
17static int layout_use_doc_css = 1;
18
19/* output options */
20static const char *output = NULL;
21static const char *format = NULL;
22static const char *options = "";
23
24static fz_context *ctx;
25static fz_document *doc;
26static fz_document_writer *out;
27static int count;
28
29static void usage(void)
30{
31 fprintf(stderr,
32 "mutool convert version " FZ_VERSION "\n"
33 "Usage: mutool convert [options] file [pages]\n"
34 "\t-p -\tpassword\n"
35 "\n"
36 "\t-A -\tnumber of bits of antialiasing (0 to 8)\n"
37 "\t-W -\tpage width for EPUB layout\n"
38 "\t-H -\tpage height for EPUB layout\n"
39 "\t-S -\tfont size for EPUB layout\n"
40 "\t-U -\tfile name of user stylesheet for EPUB layout\n"
41 "\t-X\tdisable document styles for EPUB layout\n"
42 "\n"
43 "\t-o -\toutput file name (%%d for page number)\n"
44 "\t-F -\toutput format (default inferred from output file name)\n"
45 "\t\t\traster: cbz, png, pnm, pgm, ppm, pam, pbm, pkm.\n"
46 "\t\t\tprint-raster: pcl, pclm, ps, pwg.\n"
47 "\t\t\tvector: pdf, svg.\n"
48 "\t\t\ttext: html, xhtml, text, stext.\n"
49 "\t-O -\tcomma separated list of options for output format\n"
50 "\n"
51 "\tpages\tcomma separated list of page ranges (N=last page)\n"
52 "\n"
53 );
54 fputs(fz_draw_options_usage, stderr);
55 fputs(fz_pcl_write_options_usage, stderr);
56 fputs(fz_pclm_write_options_usage, stderr);
57 fputs(fz_pwg_write_options_usage, stderr);
58 fputs(fz_stext_options_usage, stderr);
59#if FZ_ENABLE_PDF
60 fputs(fz_pdf_write_options_usage, stderr);
61#endif
62 fputs(fz_svg_write_options_usage, stderr);
63 exit(1);
64}
65
66static void runpage(int number)
67{
68 fz_rect mediabox;
69 fz_page *page;
70 fz_device *dev = NULL;
71
72 page = fz_load_page(ctx, doc, number - 1);
73
74 fz_var(dev);
75
76 fz_try(ctx)
77 {
78 mediabox = fz_bound_page(ctx, page);
79 dev = fz_begin_page(ctx, out, mediabox);
80 fz_run_page(ctx, page, dev, fz_identity, NULL);
81 fz_end_page(ctx, out);
82 }
83 fz_always(ctx)
84 {
85 fz_drop_page(ctx, page);
86 }
87 fz_catch(ctx)
88 fz_rethrow(ctx);
89}
90
91static void runrange(const char *range)
92{
93 int start, end, i;
94
95 while ((range = fz_parse_page_range(ctx, range, &start, &end, count)))
96 {
97 if (start < end)
98 for (i = start; i <= end; ++i)
99 runpage(i);
100 else
101 for (i = start; i >= end; --i)
102 runpage(i);
103 }
104}
105
106int muconvert_main(int argc, char **argv)
107{
108 int i, c;
109
110 while ((c = fz_getopt(argc, argv, "p:A:W:H:S:U:Xo:F:O:")) != -1)
111 {
112 switch (c)
113 {
114 default: usage(); break;
115
116 case 'p': password = fz_optarg; break;
117 case 'A': alphabits = atoi(fz_optarg); break;
118 case 'W': layout_w = fz_atof(fz_optarg); break;
119 case 'H': layout_h = fz_atof(fz_optarg); break;
120 case 'S': layout_em = fz_atof(fz_optarg); break;
121 case 'U': layout_css = fz_optarg; break;
122 case 'X': layout_use_doc_css = 0; break;
123
124 case 'o': output = fz_optarg; break;
125 case 'F': format = fz_optarg; break;
126 case 'O': options = fz_optarg; break;
127 }
128 }
129
130 if (fz_optind == argc || (!format && !output))
131 usage();
132
133 /* Create a context to hold the exception stack and various caches. */
134 ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
135 if (!ctx)
136 {
137 fprintf(stderr, "cannot create mupdf context\n");
138 return EXIT_FAILURE;
139 }
140
141 /* Register the default file types to handle. */
142 fz_try(ctx)
143 fz_register_document_handlers(ctx);
144 fz_catch(ctx)
145 {
146 fprintf(stderr, "cannot register document handlers: %s\n", fz_caught_message(ctx));
147 fz_drop_context(ctx);
148 return EXIT_FAILURE;
149 }
150
151 fz_set_aa_level(ctx, alphabits);
152
153 if (layout_css)
154 {
155 fz_buffer *buf = fz_read_file(ctx, layout_css);
156 fz_set_user_css(ctx, fz_string_from_buffer(ctx, buf));
157 fz_drop_buffer(ctx, buf);
158 }
159
160 fz_set_use_document_css(ctx, layout_use_doc_css);
161
162 /* Open the output document. */
163 fz_try(ctx)
164 out = fz_new_document_writer(ctx, output, format, options);
165 fz_catch(ctx)
166 {
167 fprintf(stderr, "cannot create document: %s\n", fz_caught_message(ctx));
168 fz_drop_context(ctx);
169 return EXIT_FAILURE;
170 }
171
172 for (i = fz_optind; i < argc; ++i)
173 {
174 doc = fz_open_document(ctx, argv[i]);
175 if (fz_needs_password(ctx, doc))
176 if (!fz_authenticate_password(ctx, doc, password))
177 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot authenticate password: %s", argv[i]);
178 fz_layout_document(ctx, doc, layout_w, layout_h, layout_em);
179 count = fz_count_pages(ctx, doc);
180
181 if (i+1 < argc && fz_is_page_range(ctx, argv[i+1]))
182 runrange(argv[++i]);
183 else
184 runrange("1-N");
185
186 fz_drop_document(ctx, doc);
187 }
188
189 fz_close_document_writer(ctx, out);
190
191 fz_drop_document_writer(ctx, out);
192 fz_drop_context(ctx);
193 return EXIT_SUCCESS;
194}
195