muconvert.c 6.2 KB

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