summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2016-05-04 18:00:37 +0200
committerTor Andersson <tor.andersson@artifex.com>2016-05-13 11:42:00 +0200
commit9dda5aa73d6dcb72c9f10b87564afe7491575faf (patch)
tree31c3e2b2fb16431ad7236f7a44e206a3a391061b
parent74d75a7a6f3ea4bef5b4489c65e8a876ae480c76 (diff)
downloadmupdf-9dda5aa73d6dcb72c9f10b87564afe7491575faf.tar.xz
Add long output option parsing.
Use comma-separated list of flags and key/value pairs, for example: "linearize,resolution=72,colorspace=gray"
-rw-r--r--docs/mutool/examples/pdf-create.js2
-rw-r--r--docs/mutool/examples/pdf-merge.js2
-rw-r--r--docs/mutool/run.html22
-rw-r--r--include/mupdf/fitz/writer.h5
-rw-r--r--source/fitz/output-cbz.c18
-rw-r--r--source/fitz/writer.c41
-rw-r--r--source/pdf/pdf-write.c64
-rw-r--r--source/tools/muconvert.c4
-rw-r--r--source/tools/murun.c2
-rw-r--r--source/tools/pdfcreate.c10
-rw-r--r--source/tools/pdfmerge.c7
11 files changed, 136 insertions, 41 deletions
diff --git a/docs/mutool/examples/pdf-create.js b/docs/mutool/examples/pdf-create.js
index 131e72b3..290d1737 100644
--- a/docs/mutool/examples/pdf-create.js
+++ b/docs/mutool/examples/pdf-create.js
@@ -32,4 +32,4 @@ var page = pdf.addPage([0,0,300,350], 0, resources, contents)
pdf.insertPage(-1, page)
// Save the document to file.
-pdf.save("out.pdf", "paif")
+pdf.save("out.pdf", "pretty,ascii,compress-images,compress-fonts")
diff --git a/docs/mutool/examples/pdf-merge.js b/docs/mutool/examples/pdf-merge.js
index 6f5d4692..dd5fb2a5 100644
--- a/docs/mutool/examples/pdf-merge.js
+++ b/docs/mutool/examples/pdf-merge.js
@@ -57,7 +57,7 @@ function pdfmerge() {
srcDoc = new PDFDocument(argv[i])
copyAllPages(dstDoc, srcDoc)
}
- dstDoc.save(argv[1], "z")
+ dstDoc.save(argv[1], "compress")
}
if (argv.length < 3)
diff --git a/docs/mutool/run.html b/docs/mutool/run.html
index f9278b2b..ac76a7f5 100644
--- a/docs/mutool/run.html
+++ b/docs/mutool/run.html
@@ -483,16 +483,18 @@ using low level access to the objects and streams contained in a PDF file.
<dd>Cast the PDF document to a Document.
<dt>PDFDocument#save(fileName, options)
<dd>Write the PDF document to file.
-The write options are a string of flag characters:
-<br>l: linearize,
-<br>g: garbage collect, gg: ...and compact, ggg: ...and de-duplicate,
-<br>p: pretty-print objects,
-<br>a: ascii hex encode streams,
-<br>f: compress fonts,
-<br>i: compress images,
-<br>z: compress all streams,
-<br>d: decompress all streams (except fonts or images if 'f' or 'i'),
-<br>s: sanitize content streams.
+The write options are a string of comma separated options:
+<br>linearize (optimize for "web"),
+<br>garbage (remove unused objects),
+<br>or garbage=compact (... and compact xref table),
+<br>or garbage=deduplicate (... and remove duplicate objects),
+<br>pretty (pretty-print objects),
+<br>ascii (ascii hex encode streams),
+<br>compress-fonts (compress embedded font data),
+<br>compress-images (compress image data),
+<br>compress (compress all streams),
+<br>decompress (decompress all streams (except fonts or images if compress-fonts/images)),
+<br>sanitize (sanitize content streams).
</dl>
<h3>
diff --git a/include/mupdf/fitz/writer.h b/include/mupdf/fitz/writer.h
index e318568e..5d2b06ba 100644
--- a/include/mupdf/fitz/writer.h
+++ b/include/mupdf/fitz/writer.h
@@ -16,6 +16,8 @@ struct fz_document_writer_s
void (*drop_imp)(fz_context *ctx, fz_document_writer *wri);
};
+int fz_has_option(fz_context *ctx, const char *opts, const char *key, const char **val);
+
fz_document_writer *fz_new_document_writer(fz_context *ctx, const char *path, const char *format, const char *options);
fz_device *fz_begin_page(fz_context *ctx, fz_document_writer *wri, const fz_rect *mediabox, fz_matrix *ctm);
@@ -25,4 +27,7 @@ void fz_drop_document_writer(fz_context *ctx, fz_document_writer *wri);
fz_document_writer *fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options);
fz_document_writer *fz_new_pdf_writer(fz_context *ctx, const char *path, const char *options);
+extern const char *fz_cbz_write_options_usage;
+extern const char *fz_pdf_write_options_usage;
+
#endif
diff --git a/source/fitz/output-cbz.c b/source/fitz/output-cbz.c
index df5c0640..d6f1e07c 100644
--- a/source/fitz/output-cbz.c
+++ b/source/fitz/output-cbz.c
@@ -8,11 +8,16 @@ struct fz_cbz_writer_s
{
fz_document_writer super;
fz_zip_writer *zip;
- int resolution;
+ float resolution;
fz_pixmap *pixmap;
int count;
};
+const char *fz_cbz_write_options_usage =
+ "CBZ output options:\n"
+ "\tresolution=N: resolution of rendered pages in pixels per inch (default 96)\n"
+ ;
+
static fz_device *
cbz_begin_page(fz_context *ctx, fz_document_writer *wri_, const fz_rect *mediabox, fz_matrix *ctm)
{
@@ -69,8 +74,10 @@ cbz_drop_imp(fz_context *ctx, fz_document_writer *wri_)
fz_document_writer *
fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options)
{
- fz_cbz_writer *wri = fz_malloc_struct(ctx, fz_cbz_writer);
+ const char *val;
+ fz_cbz_writer *wri;
+ wri = fz_malloc_struct(ctx, fz_cbz_writer);
wri->super.begin_page = cbz_begin_page;
wri->super.end_page = cbz_end_page;
wri->super.drop_imp = cbz_drop_imp;
@@ -83,11 +90,10 @@ fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options)
fz_rethrow(ctx);
}
- // TODO: getopt-like comma separated list of options
- if (options)
- wri->resolution = atoi(options);
+ if (fz_has_option(ctx, options, "resolution", &val))
+ wri->resolution = fz_atof(val);
- if (wri->resolution == 0)
+ if (wri->resolution <= 0)
wri->resolution = 96;
return (fz_document_writer*)wri;
diff --git a/source/fitz/writer.c b/source/fitz/writer.c
index c25ff2f9..b015b5bb 100644
--- a/source/fitz/writer.c
+++ b/source/fitz/writer.c
@@ -1,5 +1,46 @@
#include "mupdf/fitz.h"
+/* Return non-null terminated pointers to key/value entries in comma separated
+ * option string. A plain key has the default value 'yes'. Use strncmp to compare
+ * key/value strings. */
+static const char *
+fz_get_option(fz_context *ctx, const char **key, const char **val, const char *opts)
+{
+ if (!opts || *opts == 0)
+ return NULL;
+
+ if (*opts == ',')
+ ++opts;
+
+ *key = opts;
+ while (*opts != 0 && *opts != ',' && *opts != '=')
+ ++opts;
+
+ if (*opts == '=')
+ {
+ *val = ++opts;
+ while (*opts != 0 && *opts != ',')
+ ++opts;
+ }
+ else
+ {
+ *val = "yes";
+ }
+
+ return opts;
+}
+
+int
+fz_has_option(fz_context *ctx, const char *opts, const char *key, const char **val)
+{
+ const char *straw;
+ int n = strlen(key);
+ while ((opts = fz_get_option(ctx, &straw, val, opts)))
+ if (!strncmp(straw, key, n) && (straw[n] == '=' || straw[n] == ',' || straw[n] == 0))
+ return 1;
+ return 0;
+}
+
fz_document_writer *
fz_new_document_writer(fz_context *ctx, const char *path, const char *format, const char *options)
{
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index b50e5db3..b4c565cf 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -2748,27 +2748,59 @@ static void finalise_write_state(fz_context *ctx, pdf_write_state *opts)
fz_drop_output(ctx, opts->out);
}
+static int opteq(const char *a, const char *b)
+{
+ int n = strlen(b);
+ return !strncmp(a, b, n) && (a[n] == ',' || a[n] == 0);
+}
+
+const char *fz_pdf_write_options_usage =
+ "PDF output options:\n"
+ "\tdecompress: decompress all streams (except when compress-fonts or compress-images)\n"
+ "\tcompress: compress all streams\n"
+ "\tcompress-fonts: compress embedded fonts\n"
+ "\tcompress-images: compress images\n"
+ "\tascii: ASCII hex encode binary streams\n"
+ "\tpretty: pretty-print objects with indentation\n"
+ "\tlinearize: optimize for web browsers\n"
+ "\tsanitize: clean up graphics commands in content streams\n"
+ "\tgarbage: garbage collect unused objects\n"
+ "\tor garbage=compact: ... and compact cross reference table\n"
+ "\tor garbage=deduplicate: ... and remove duplicate objects\n"
+ ;
+
void pdf_parse_write_options(fz_context *ctx, pdf_write_options *opts, const char *args)
{
- int c;
+ const char *val;
memset(opts, 0, sizeof *opts);
- while ((c = *args++))
- {
- switch (c)
- {
- case 'd': opts->do_decompress += 1; break;
- case 'z': opts->do_compress += 1; break;
- case 'f': opts->do_compress_fonts += 1; break;
- case 'i': opts->do_compress_images += 1; break;
- case 'p': opts->do_pretty += 1; break;
- case 'a': opts->do_ascii += 1; break;
- case 'g': opts->do_garbage += 1; break;
- case 'l': opts->do_linear += 1; break;
- case 's': opts->do_clean += 1; break;
- default: fz_warn(ctx, "unrecognized pdf-write option: '%c'", c);
- }
+ if (fz_has_option(ctx, args, "decompress", &val))
+ opts->do_decompress = opteq(val, "yes");
+ if (fz_has_option(ctx, args, "compress", &val))
+ opts->do_compress = opteq(val, "yes");
+ if (fz_has_option(ctx, args, "compress-fonts", &val))
+ opts->do_compress_fonts = opteq(val, "yes");
+ if (fz_has_option(ctx, args, "compress-images", &val))
+ opts->do_compress_images = opteq(val, "yes");
+ if (fz_has_option(ctx, args, "ascii", &val))
+ opts->do_ascii = opteq(val, "yes");
+ if (fz_has_option(ctx, args, "pretty", &val))
+ opts->do_pretty = opteq(val, "yes");
+ if (fz_has_option(ctx, args, "linearize", &val))
+ opts->do_linear = opteq(val, "yes");
+ if (fz_has_option(ctx, args, "sanitize", &val))
+ opts->do_clean = opteq(val, "yes");
+ if (fz_has_option(ctx, args, "garbage", &val))
+ {
+ if (opteq(val, "yes"))
+ opts->do_garbage = 1;
+ else if (opteq(val, "compact"))
+ opts->do_garbage = 2;
+ else if (opteq(val, "deduplicate"))
+ opts->do_garbage = 3;
+ else
+ opts->do_garbage = atoi(val);
}
}
diff --git a/source/tools/muconvert.c b/source/tools/muconvert.c
index 5e72b5d3..18bbd46b 100644
--- a/source/tools/muconvert.c
+++ b/source/tools/muconvert.c
@@ -37,10 +37,12 @@ static void usage(void)
"\t-o -\toutput file name (%%d for page number)\n"
"\t-F -\toutput format (default inferred from output file name)\n"
"\t\tcbz, pdf\n"
- "\t-O -\toutput format options\n"
+ "\t-O -\tcomma separated list of options for output format\n"
"\n"
"\tpages\tcomma separated list of page numbers and ranges\n"
+ "\n"
);
+ fprintf(stderr, "%s\n", fz_cbz_write_options_usage);
exit(1);
}
diff --git a/source/tools/murun.c b/source/tools/murun.c
index 6d9881a2..9b52558f 100644
--- a/source/tools/murun.c
+++ b/source/tools/murun.c
@@ -2511,7 +2511,7 @@ static void ffi_PDFDocument_save(js_State *J)
fz_context *ctx = js_getcontext(J);
pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
const char *filename = js_tostring(J, 1);
- const char *options = js_isdefined(J, 2) ? js_tostring(J, 2) : "ga";
+ const char *options = js_isdefined(J, 2) ? js_tostring(J, 2) : NULL;
pdf_write_options pwo;
fz_try(ctx) {
diff --git a/source/tools/pdfcreate.c b/source/tools/pdfcreate.c
index 839e493e..77f0c819 100644
--- a/source/tools/pdfcreate.c
+++ b/source/tools/pdfcreate.c
@@ -11,9 +11,15 @@ static void usage(void)
fprintf(stderr,
"usage: mutool create [-o output.pdf] [-O options] page.txt [page2.txt ...]\n"
"\t-o\tname of PDF file to create\n"
- "\t-O\tPDF write options\n"
- "\tpage.txt file defines page size, fonts, images and contents\n"
+ "\t-O\tcomma separated list of output options\n"
+ "\tpage.txt\tcontent stream with annotations for creating resources\n\n"
+ "Content stream special commands:\n"
+ "\t%%%%MediaBox LLX LLY URX URY\n"
+ "\t%%%%Rotate Angle\n"
+ "\t%%%%Font Name Filename (or base 14 font name)\n"
+ "\t%%%%Image Name Filename\n\n"
);
+ fprintf(stderr, "%s\n", fz_pdf_write_options_usage);
exit(1);
}
diff --git a/source/tools/pdfmerge.c b/source/tools/pdfmerge.c
index f63a90c7..597bd4ce 100644
--- a/source/tools/pdfmerge.c
+++ b/source/tools/pdfmerge.c
@@ -11,10 +11,11 @@ static void usage(void)
fprintf(stderr,
"usage: mutool merge [-o output.pdf] [-O options] input.pdf [pages] [input2.pdf] [pages2] ...\n"
"\t-o\tname of PDF file to create\n"
- "\t-O\tPDF write options\n"
- "\tinput.pdf\tname of first PDF file from which we are copying pages\n"
- "\tpages: comma separated list of page ranges (for example: 1-5,6,10-)\n"
+ "\t-O\tcomma separated list of output options\n"
+ "\tinput.pdf\tname of input file from which to copy pages\n"
+ "\tpages\tcomma separated list of page ranges to copy (for example: 1-5,6,10-)\n\n"
);
+ fprintf(stderr, "%s\n", fz_pdf_write_options_usage);
exit(1);
}