pdfcreate.c 7.8 KB

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