1/*
2 * PDF creation tool: Tool for creating pdf content.
3 *
4 * Simple test bed to work with adding content and creating PDFs
5 */
6
7#include "mupdf/fitz.h"
8#include "mupdf/pdf.h"
9
10#include <string.h>
11#include <stdlib.h>
12#include <stdio.h>
13
14static void usage(void)
15{
16 fprintf(stderr,
17 "usage: mutool create [-o output.pdf] [-O options] page.txt [page2.txt ...]\n"
18 "\t-o -\tname of PDF file to create\n"
19 "\t-O -\tcomma separated list of output options\n"
20 "\tpage.txt\tcontent stream with annotations for creating resources\n\n"
21 "Content stream special commands:\n"
22 "\t%%%%MediaBox LLX LLY URX URY\n"
23 "\t%%%%Rotate Angle\n"
24 "\t%%%%Font Name Filename (or base 14 font name)\n"
25 "\t%%%%CJKFont Name Language WMode Style (Language=zh-Hant|zh-Hans|ja|ko, WMode=H|V, Style=serif|sans)\n"
26 "\t%%%%Image Name Filename\n\n"
27 );
28 fputs(fz_pdf_write_options_usage, stderr);
29 exit(1);
30}
31
32static fz_context *ctx = NULL;
33static pdf_document *doc = NULL;
34
35static void add_font_res(pdf_obj *resources, char *name, char *path, char *encname)
36{
37 const unsigned char *data;
38 int size, enc;
39 fz_font *font;
40 pdf_obj *subres, *ref;
41
42 data = fz_lookup_base14_font(ctx, path, &size);
43 if (data)
44 font = fz_new_font_from_memory(ctx, path, data, size, 0, 0);
45 else
46 font = fz_new_font_from_file(ctx, NULL, path, 0, 0);
47
48 subres = pdf_dict_get(ctx, resources, PDF_NAME(Font));
49 if (!subres)
50 {
51 subres = pdf_new_dict(ctx, doc, 10);
52 pdf_dict_put_drop(ctx, resources, PDF_NAME(Font), subres);
53 }
54
55 enc = PDF_SIMPLE_ENCODING_LATIN;
56 if (encname)
57 {
58 if (!strcmp(encname, "Latin") || !strcmp(encname, "Latn"))
59 enc = PDF_SIMPLE_ENCODING_LATIN;
60 else if (!strcmp(encname, "Greek") || !strcmp(encname, "Grek"))
61 enc = PDF_SIMPLE_ENCODING_GREEK;
62 else if (!strcmp(encname, "Cyrillic") || !strcmp(encname, "Cyrl"))
63 enc = PDF_SIMPLE_ENCODING_CYRILLIC;
64 }
65
66 ref = pdf_add_simple_font(ctx, doc, font, enc);
67 pdf_dict_puts(ctx, subres, name, ref);
68 pdf_drop_obj(ctx, ref);
69
70 fz_drop_font(ctx, font);
71}
72
73static void add_cjkfont_res(pdf_obj *resources, char *name, char *lang, char *wm, char *style)
74{
75 const unsigned char *data;
76 int size, index, ordering, wmode, serif;
77 fz_font *font;
78 pdf_obj *subres, *ref;
79
80 ordering = fz_lookup_cjk_ordering_by_language(lang);
81
82 if (wm && !strcmp(wm, "V"))
83 wmode = 1;
84 else
85 wmode = 0;
86
87 if (style && (!strcmp(style, "sans") || !strcmp(style, "sans-serif")))
88 serif = 0;
89 else
90 serif = 1;
91
92 data = fz_lookup_cjk_font(ctx, ordering, &size, &index);
93 font = fz_new_font_from_memory(ctx, NULL, data, size, index, 0);
94
95 subres = pdf_dict_get(ctx, resources, PDF_NAME(Font));
96 if (!subres)
97 {
98 subres = pdf_new_dict(ctx, doc, 10);
99 pdf_dict_put_drop(ctx, resources, PDF_NAME(Font), subres);
100 }
101
102 ref = pdf_add_cjk_font(ctx, doc, font, ordering, wmode, serif);
103 pdf_dict_puts(ctx, subres, name, ref);
104 pdf_drop_obj(ctx, ref);
105
106 fz_drop_font(ctx, font);
107}
108
109static void add_image_res(pdf_obj *resources, char *name, char *path)
110{
111 fz_image *image;
112 pdf_obj *subres, *ref;
113
114 image = fz_new_image_from_file(ctx, path);
115
116 subres = pdf_dict_get(ctx, resources, PDF_NAME(XObject));
117 if (!subres)
118 {
119 subres = pdf_new_dict(ctx, doc, 10);
120 pdf_dict_put_drop(ctx, resources, PDF_NAME(XObject), subres);
121 }
122
123 ref = pdf_add_image(ctx, doc, image);
124 pdf_dict_puts(ctx, subres, name, ref);
125 pdf_drop_obj(ctx, ref);
126
127 fz_drop_image(ctx, image);
128}
129
130/*
131The input is a raw content stream, with commands embedded in comments:
132
133%%MediaBox LLX LLY URX URY
134%%Rotate Angle
135%%Font Name Filename (or base 14 font name) [Encoding (Latin, Greek or Cyrillic)]
136%%CJKFont Name Language WMode Style (Language=zh-Hant|zh-Hans|ja|ko, WMode=H|V, Style=serif|sans)
137%%Image Name Filename
138*/
139static void create_page(char *input)
140{
141 fz_rect mediabox = { 0, 0, 595, 842 };
142 int rotate = 0;
143
144 char line[4096];
145 char *s, *p;
146 fz_stream *stm;
147
148 fz_buffer *contents;
149 pdf_obj *resources;
150 pdf_obj *page;
151
152 resources = pdf_new_dict(ctx, doc, 2);
153 contents = fz_new_buffer(ctx, 1024);
154
155 stm = fz_open_file(ctx, input);
156 while (fz_read_line(ctx, stm, line, sizeof line))
157 {
158 if (line[0] == '%' && line[1] == '%')
159 {
160 p = line;
161 s = fz_strsep(&p, " ");
162 if (!strcmp(s, "%%MediaBox"))
163 {
164 mediabox.x0 = fz_atoi(fz_strsep(&p, " "));
165 mediabox.y0 = fz_atoi(fz_strsep(&p, " "));
166 mediabox.x1 = fz_atoi(fz_strsep(&p, " "));
167 mediabox.y1 = fz_atoi(fz_strsep(&p, " "));
168 }
169 else if (!strcmp(s, "%%Rotate"))
170 {
171 rotate = fz_atoi(fz_strsep(&p, " "));
172 }
173 else if (!strcmp(s, "%%Font"))
174 {
175 char *name = fz_strsep(&p, " ");
176 char *path = fz_strsep(&p, " ");
177 char *enc = fz_strsep(&p, " ");
178 if (!name || !path)
179 fz_throw(ctx, FZ_ERROR_GENERIC, "Font directive missing arguments");
180 add_font_res(resources, name, path, enc);
181 }
182 else if (!strcmp(s, "%%CJKFont"))
183 {
184 char *name = fz_strsep(&p, " ");
185 char *lang = fz_strsep(&p, " ");
186 char *wmode = fz_strsep(&p, " ");
187 char *style = fz_strsep(&p, " ");
188 if (!name || !lang)
189 fz_throw(ctx, FZ_ERROR_GENERIC, "CJKFont directive missing arguments");
190 add_cjkfont_res(resources, name, lang, wmode, style);
191 }
192 else if (!strcmp(s, "%%Image"))
193 {
194 char *name = fz_strsep(&p, " ");
195 char *path = fz_strsep(&p, " ");
196 if (!name || !path)
197 fz_throw(ctx, FZ_ERROR_GENERIC, "Image directive missing arguments");
198 add_image_res(resources, name, path);
199 }
200 }
201 else
202 {
203 fz_append_string(ctx, contents, line);
204 fz_append_byte(ctx, contents, '\n');
205 }
206 }
207 fz_drop_stream(ctx, stm);
208
209 page = pdf_add_page(ctx, doc, mediabox, rotate, resources, contents);
210 pdf_insert_page(ctx, doc, -1, page);
211 pdf_drop_obj(ctx, page);
212
213 fz_drop_buffer(ctx, contents);
214 pdf_drop_obj(ctx, resources);
215}
216
217int pdfcreate_main(int argc, char **argv)
218{
219 pdf_write_options opts = pdf_default_write_options;
220 char *output = "out.pdf";
221 char *flags = "compress";
222 int i, c;
223
224 while ((c = fz_getopt(argc, argv, "o:O:")) != -1)
225 {
226 switch (c)
227 {
228 case 'o': output = fz_optarg; break;
229 case 'O': flags = fz_optarg; break;
230 default: usage(); break;
231 }
232 }
233
234 if (fz_optind == argc)
235 usage();
236
237 ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
238 if (!ctx)
239 {
240 fprintf(stderr, "cannot initialise context\n");
241 exit(1);
242 }
243
244 pdf_parse_write_options(ctx, &opts, flags);
245
246 doc = pdf_create_document(ctx);
247
248 for (i = fz_optind; i < argc; ++i)
249 create_page(argv[i]);
250
251 pdf_save_document(ctx, doc, output, &opts);
252
253 pdf_drop_document(ctx, doc);
254
255 fz_flush_warnings(ctx);
256 fz_drop_context(ctx);
257 return 0;
258}
259