diff options
author | Robin Watts <robin.watts@artifex.com> | 2016-11-23 16:28:25 +0000 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2016-12-12 13:40:40 +0100 |
commit | fd2cb625e77cf71eec9d37bdd034cee6ef184d62 (patch) | |
tree | 38809491d6b1c7f7623e0b41fc3477f41e728d28 /source/tools | |
parent | e3180169b42481fbbc4886db741782ca1391c46e (diff) | |
download | mupdf-fd2cb625e77cf71eec9d37bdd034cee6ef184d62.tar.xz |
PDF Portfolio support.
New PDF Portfolio manipulation API.
Simple mutool 'portfolio' tool for listing/extracting/embedding
files.
Diffstat (limited to 'source/tools')
-rw-r--r-- | source/tools/mutool.c | 2 | ||||
-rw-r--r-- | source/tools/pdfportfolio.c | 245 |
2 files changed, 247 insertions, 0 deletions
diff --git a/source/tools/mutool.c b/source/tools/mutool.c index 97c74fae..8cba3cff 100644 --- a/source/tools/mutool.c +++ b/source/tools/mutool.c @@ -20,6 +20,7 @@ int pdfshow_main(int argc, char *argv[]); int pdfpages_main(int argc, char *argv[]); int pdfcreate_main(int argc, char *argv[]); int pdfmerge_main(int argc, char *argv[]); +int pdfportfolio_main(int argc, char *argv[]); static struct { int (*func)(int argc, char *argv[]); @@ -40,6 +41,7 @@ static struct { { pdfshow_main, "show", "show internal pdf objects" }, { pdfcreate_main, "create", "create pdf document" }, { pdfmerge_main, "merge", "merge pages from multiple pdf sources into a new pdf" }, + { pdfportfolio_main, "portfolio", "manipulate PDF portfolios" }, #endif }; diff --git a/source/tools/pdfportfolio.c b/source/tools/pdfportfolio.c new file mode 100644 index 00000000..51b43ae3 --- /dev/null +++ b/source/tools/pdfportfolio.c @@ -0,0 +1,245 @@ +/* + * pdfportfolio -- manipulate embedded files in a PDF + */ + +#include "mupdf/pdf.h" + +static pdf_document *doc = NULL; +static fz_context *ctx = NULL; + +static void usage(void) +{ + fprintf(stderr, "usage: mutool portfolio [options] infile.pdf [actions]\n"); + fprintf(stderr, "\tOptions are:\n"); + fprintf(stderr, "\t-p -\tpassword\n"); + fprintf(stderr, "Actions are:\n"); + fprintf(stderr, "\tl\tlist embedded files\n"); + fprintf(stderr, "\tx N <filename>\n\t\textract Nth embedded file as <filename>\n"); + fprintf(stderr, "\te outfile.pdf <filename> <embed>\n\t\tembed <filename> as <embed>, saving the result as outfile.pdf\n"); + fprintf(stderr, "\nFor safety, keep all filenames as 7 bit clean for now.\n"); + exit(1); +} + +static void +safe_print_pdf_string(fz_context *ctx, unsigned char *str, int len) +{ + int c; + + if (len > 1 && str[0] == 0xFE && str[1] == 0xFF) + { + str += 2; + len -= 2; + while (len) + { + c = (*str++<<8); + c += *str++; + if (c >= 32 && c != 127 && c < 256) + fprintf(stderr, "%c", c); + else + fprintf(stderr, "<%04x>", c); + len -= 2; + }; + } + else + { + while (len) + { + c = *str++; + if (c >= 32 && c != 127 && c < 256) + fprintf(stderr, "%c", c); + else + fprintf(stderr, "<%02x>", c); + len--; + }; + } +} + +static void +safe_print_pdf_obj(fz_context *ctx, pdf_obj *obj, const char *dflt) +{ + if (obj == NULL) + fprintf(stderr, "%s", dflt); + else if (pdf_is_string(ctx, obj)) + safe_print_pdf_string(ctx, (unsigned char *)pdf_to_str_buf(ctx, obj), pdf_to_str_len(ctx, obj)); + else + pdf_print_obj(ctx, fz_stderr(ctx), obj, 1); +} + +int pdfportfolio_main(int argc, char **argv) +{ + char *infile; + char *password = ""; + int c; + int exit_code = 0; + + while ((c = fz_getopt(argc, argv, "p:")) != -1) + { + switch (c) + { + case 'p': password = fz_optarg; break; + default: usage(); break; + } + } + + if (fz_optind == argc) + usage(); + + infile = argv[fz_optind++]; + + ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); + if (!ctx) + { + fprintf(stderr, "cannot initialise context\n"); + exit(1); + } + + doc = pdf_open_document(ctx, infile); + if (pdf_needs_password(ctx, doc)) + if (!pdf_authenticate_password(ctx, doc, password)) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot authenticate password: %s", infile); + + if (fz_optind == argc) + usage(); + fz_optarg = argv[fz_optind++]; + if (*fz_optarg == 0 || (*fz_optarg != 'l' && *fz_optarg != 'x' && *fz_optarg != 'e') || fz_optarg[1] != 0) + usage(); + + fz_try(ctx) + { + switch (*fz_optarg) + { + case 'l': + { + /* List files */ + int m = pdf_count_portfolio_schema(ctx, doc); + int n = pdf_count_portfolio_entries(ctx, doc); + int i, j; + + for (i = 0; i < n; i++) + { + pdf_obj *name = pdf_portfolio_entry_name(ctx, doc, i); + + fprintf(stderr, " %s%d: ", i < 10 ? " " : "", i); + safe_print_pdf_obj(ctx, name, "(Unnamed)"); + fprintf(stderr, "\n"); + for (j = 0; j < m; j++) + { + pdf_portfolio_schema info; + pdf_obj *obj; + char *type; + + pdf_portfolio_schema_info(ctx, doc, j, &info); + obj = pdf_portfolio_entry_info(ctx, doc, i, j); + fprintf(stderr, " "); + safe_print_pdf_obj(ctx, info.name, "(Unnamed)"); + switch(info.type) + { + case PDF_SCHEMA_TEXT: + type = "T"; + break; + case PDF_SCHEMA_DATE: + type = "D"; + break; + case PDF_SCHEMA_NUMBER: + type = "N"; + break; + case PDF_SCHEMA_FILENAME: + type = "F"; + break; + case PDF_SCHEMA_DESC: + type = "E"; + break; + case PDF_SCHEMA_MODDATE: + type = "M"; + break; + case PDF_SCHEMA_CREATIONDATE: + type = "C"; + break; + case PDF_SCHEMA_SIZE: + type = "S"; + break; + default: + type = "?"; + break; + } + fprintf(stderr, ":%s:", type); + safe_print_pdf_obj(ctx, obj, ""); + if (info.editable) + fprintf(stderr, " (Editable)"); + if (info.visible) + fprintf(stderr, " (Visible)"); + fprintf(stderr, "\n"); + } + } + break; + } + case 'x': + { + int entry; + char *filename; + fz_buffer *buf; + unsigned char *data; + int len; + FILE *file; + + if (fz_optind > argc-2) + usage(); + + entry = fz_atoi(argv[fz_optind++]); + filename = argv[fz_optind++]; + + buf = pdf_portfolio_entry(ctx, doc, entry); + len = fz_buffer_storage(ctx, buf, &data); + + file = fopen(filename, "wb"); + if (file == NULL) + { + fprintf(stderr, "Failed to open '%s' for writing\n", filename); + exit(1); + } + fwrite(data, 1, len, file); + fclose(file); + fz_drop_buffer(ctx, buf); + break; + } + case 'e': + { + char *outfile; + char *filename; + char *ename; + fz_buffer *buf; + + if (fz_optind > argc-3) + usage(); + + outfile = argv[fz_optind++]; + filename = argv[fz_optind++]; + ename = argv[fz_optind++]; + + if (ename == NULL) + ename = filename; + + buf = fz_read_file(ctx, filename); + pdf_add_portfolio_entry(ctx, doc, + ename, strlen(ename), /* name */ + ename, strlen(ename), /* desc */ + ename, strlen(ename), /* filename */ + ename, strlen(ename), /* unifile */ + buf); + fz_drop_buffer(ctx, buf); + pdf_save_document(ctx, doc, outfile, NULL); + break; + } + } + } + fz_catch(ctx) + { + /* Swallow any errors */ + exit_code = 1; + } + + pdf_drop_document(ctx, doc); + fz_flush_warnings(ctx); + fz_drop_context(ctx); + return exit_code; +} |