mubar.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Copyright (C) 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. * mudraw -- command line tool for drawing and converting documents
  24. */
  25. #include "mupdf/fitz.h"
  26. #if FZ_ENABLE_BARCODE
  27. #if FZ_ENABLE_PDF
  28. #include "mupdf/pdf.h" /* for pdf output */
  29. #endif
  30. static int mubar_usage(void)
  31. {
  32. int i, n, c;
  33. const char *s;
  34. fprintf(stderr,
  35. "usage to decode: mutool barcode -d [options] input [pages]\n"
  36. "\t-p -\tpassword for encrypted PDF files\n"
  37. "\t-o -\toutput file (default: stdout)\n"
  38. "\t-r -\trotation\n"
  39. );
  40. fprintf(stderr,
  41. "usage to create: mutool barcode -c [options] text\n"
  42. "\t-o -\toutput file (default: out.png)\n"
  43. "\t-q\tadd quiet zones\n"
  44. "\t-t\tadd human readable text (when possible)\n"
  45. "\t-e -\terror correction level (0-8)\n"
  46. "\t-s -\tsize of barcode image\n"
  47. "\t-F -\tbarcode format (default: qrcode)\n"
  48. );
  49. for (c = 0, i = FZ_BARCODE_NONE + 1; i < FZ_BARCODE__LIMIT; i++)
  50. {
  51. s = fz_string_from_barcode_type(i);
  52. n = (int)strlen(s);
  53. if (c + 2 + n > 78)
  54. {
  55. fprintf(stderr, ",\n\t\t%s", s);
  56. c = 8 + n;
  57. }
  58. else
  59. {
  60. if (c == 0)
  61. {
  62. fprintf(stderr, "\t\t%s", s);
  63. c += 8 + n;
  64. }
  65. else
  66. {
  67. fprintf(stderr, ", %s", s);
  68. c += n + 2;
  69. }
  70. }
  71. }
  72. fprintf(stderr, "\n");
  73. return EXIT_FAILURE;
  74. }
  75. int mubar_create(int argc, char **argv)
  76. {
  77. fz_context *ctx;
  78. fz_pixmap *pixmap = NULL;
  79. int retval = EXIT_SUCCESS;
  80. const char *output = "out.png";
  81. const char *format = "png";
  82. fz_barcode_type bartype = FZ_BARCODE_QRCODE;
  83. int quiet = 0;
  84. int hrt = 0;
  85. int ec_level = 0;
  86. int size = 256;
  87. int c;
  88. while ((c = fz_getopt(argc, argv, "F:ce:o:qs:td:")) != -1)
  89. {
  90. switch (c)
  91. {
  92. case 'F':
  93. bartype = fz_barcode_type_from_string(fz_optarg);
  94. if (bartype == FZ_BARCODE_NONE)
  95. return mubar_usage();
  96. break;
  97. case 'c': break;
  98. case 'e': ec_level = fz_atoi(fz_optarg); break;
  99. case 'o': output = fz_optarg; break;
  100. case 'q': quiet = 1; break;
  101. case 's': size = fz_atoi(fz_optarg); break;
  102. case 't': hrt = 1; break;
  103. default: return mubar_usage();
  104. }
  105. }
  106. if (fz_optind == argc)
  107. return mubar_usage();
  108. ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT);
  109. if (!ctx)
  110. {
  111. fprintf(stderr, "cannot initialise context\n");
  112. return EXIT_FAILURE;
  113. }
  114. format = strrchr(output, '.');
  115. if (format == NULL)
  116. return mubar_usage();
  117. fz_var(pixmap);
  118. fz_try(ctx)
  119. {
  120. pixmap = fz_new_barcode_pixmap(ctx, bartype, argv[fz_optind], size, ec_level, quiet, hrt);
  121. if (!fz_strcasecmp(format, ".png"))
  122. {
  123. fz_save_pixmap_as_png(ctx, pixmap, output);
  124. }
  125. else if (!fz_strcasecmp(format, ".pdf"))
  126. {
  127. fz_pclm_options opts = { 0 };
  128. opts.compress = 1;
  129. opts.strip_height = pixmap->h;
  130. fz_save_pixmap_as_pclm(ctx, pixmap, output, 0, &opts);
  131. }
  132. else
  133. {
  134. fz_throw(ctx, FZ_ERROR_ARGUMENT, "invalid output format (must be PNG or PDF)\n");
  135. }
  136. }
  137. fz_always(ctx)
  138. {
  139. fz_drop_pixmap(ctx, pixmap);
  140. }
  141. fz_catch(ctx)
  142. {
  143. fz_report_error(ctx);
  144. retval = EXIT_FAILURE;
  145. }
  146. fz_drop_context(ctx);
  147. return retval;
  148. }
  149. static void mubar_decode_page(fz_context *ctx, fz_output *out, fz_document *doc, int page_no, int rotation)
  150. {
  151. fz_barcode_type type;
  152. fz_page *page = fz_load_page(ctx, doc, page_no-1);
  153. char *text;
  154. fz_try(ctx)
  155. {
  156. text = fz_decode_barcode_from_page(ctx, &type, page, fz_infinite_rect, rotation);
  157. if (text && type != FZ_BARCODE_NONE)
  158. fz_write_printf(ctx, out, "%s: %s\n", fz_string_from_barcode_type(type), text);
  159. else
  160. fz_write_string(ctx, out, "none\n");
  161. }
  162. fz_always(ctx)
  163. {
  164. fz_free(ctx, text);
  165. fz_drop_page(ctx, page);
  166. }
  167. fz_catch(ctx)
  168. fz_rethrow(ctx);
  169. }
  170. int mubar_decode(int argc, char **argv)
  171. {
  172. fz_context *ctx;
  173. fz_document *doc = NULL;
  174. fz_output *out = NULL;
  175. int i, c, start, end, p, count;
  176. const char *range = NULL;
  177. int retval = EXIT_SUCCESS;
  178. const char *output = NULL;
  179. const char *password = NULL;
  180. int rotation = 0;
  181. while ((c = fz_getopt(argc, argv, "do:r:p:")) != -1)
  182. {
  183. switch (c)
  184. {
  185. case 'd': break;
  186. case 'o': output = fz_optarg; break;
  187. case 'r': rotation = fz_atof(fz_optarg); break;
  188. case 'p': password = fz_optarg; break;
  189. default: return mubar_usage();
  190. }
  191. }
  192. if (fz_optind == argc)
  193. return mubar_usage();
  194. ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT);
  195. if (!ctx)
  196. {
  197. fprintf(stderr, "cannot initialise context\n");
  198. return EXIT_FAILURE;
  199. }
  200. fz_try(ctx)
  201. fz_register_document_handlers(ctx);
  202. fz_catch(ctx)
  203. {
  204. fz_report_error(ctx);
  205. fprintf(stderr, "cannot register document handlers\n");
  206. fz_drop_context(ctx);
  207. return EXIT_FAILURE;
  208. }
  209. fz_var(doc);
  210. fz_var(out);
  211. fz_try(ctx)
  212. {
  213. if (output)
  214. out = fz_new_output_with_path(ctx, output, 0);
  215. else
  216. out = fz_stdout(ctx);
  217. for (i = fz_optind; i < argc; ++i)
  218. {
  219. doc = fz_open_document(ctx, argv[i]);
  220. if (fz_needs_password(ctx, doc))
  221. if (!fz_authenticate_password(ctx, doc, password))
  222. fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot authenticate password: %s", argv[i]);
  223. count = fz_count_pages(ctx, doc);
  224. if (i+1 < argc && fz_is_page_range(ctx, argv[i+1]))
  225. range = argv[++i];
  226. else
  227. range = "1-N";
  228. while ((range = fz_parse_page_range(ctx, range, &start, &end, count)))
  229. {
  230. if (start < end)
  231. for (p = start; p <= end; ++p)
  232. mubar_decode_page(ctx, out, doc, p, rotation);
  233. else
  234. for (p = start; p >= end; --p)
  235. mubar_decode_page(ctx, out, doc, p, rotation);
  236. }
  237. fz_drop_document(ctx, doc);
  238. doc = NULL;
  239. }
  240. if (output)
  241. fz_close_output(ctx, out);
  242. }
  243. fz_always(ctx)
  244. {
  245. if (output)
  246. fz_drop_output(ctx, out);
  247. fz_drop_document(ctx, doc);
  248. }
  249. fz_catch(ctx)
  250. {
  251. fz_report_error(ctx);
  252. retval = EXIT_FAILURE;
  253. }
  254. fz_drop_context(ctx);
  255. return retval;
  256. }
  257. int mubar_main(int argc, char **argv)
  258. {
  259. if (argc > 2 && !strcmp(argv[1], "-c"))
  260. return mubar_create(argc, argv);
  261. if (argc > 2 && !strcmp(argv[1], "-d"))
  262. return mubar_decode(argc, argv);
  263. return mubar_usage();
  264. }
  265. #else
  266. #include <stdio.h>
  267. int mubar_main(int argc, char **argv)
  268. {
  269. fprintf(stderr, "barcode support disabled\n");
  270. return 1;
  271. }
  272. #endif