From 0d342fb664c36488bbc0d7f4ca0aa4ab5e7c85b8 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 4 May 2016 18:01:36 +0200 Subject: Add pdf write support to mutool convert. --- source/fitz/output-cbz.c | 4 +-- source/fitz/writer.c | 15 ++++++-- source/pdf/pdf-write.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ source/tools/muconvert.c | 91 +++++++++++++++++++++++++++++++++++++--------- 4 files changed, 184 insertions(+), 20 deletions(-) diff --git a/source/fitz/output-cbz.c b/source/fitz/output-cbz.c index d6f1e07c..d9aff180 100644 --- a/source/fitz/output-cbz.c +++ b/source/fitz/output-cbz.c @@ -60,7 +60,7 @@ cbz_end_page(fz_context *ctx, fz_document_writer *wri_, fz_device *dev) } static void -cbz_drop_imp(fz_context *ctx, fz_document_writer *wri_) +cbz_close(fz_context *ctx, fz_document_writer *wri_) { fz_cbz_writer *wri = (fz_cbz_writer*)wri_; fz_try(ctx) @@ -80,7 +80,7 @@ fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options) 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; + wri->super.close = cbz_close; fz_try(ctx) wri->zip = fz_new_zip_writer(ctx, path); diff --git a/source/fitz/writer.c b/source/fitz/writer.c index b015b5bb..cb4ca77a 100644 --- a/source/fitz/writer.c +++ b/source/fitz/writer.c @@ -54,15 +54,26 @@ fz_new_document_writer(fz_context *ctx, const char *path, const char *format, co if (!fz_strcasecmp(format, "cbz")) return fz_new_cbz_writer(ctx, path, options); + if (!fz_strcasecmp(format, "pdf")) + return fz_new_pdf_writer(ctx, path, options); fz_throw(ctx, FZ_ERROR_GENERIC, "unknown document format: %s", format); } +void +fz_close_document_writer(fz_context *ctx, fz_document_writer *wri) +{ + if (wri->close) + wri->close(ctx, wri); + wri->close = NULL; + fz_free(ctx, wri); +} + void fz_drop_document_writer(fz_context *ctx, fz_document_writer *wri) { - if (wri->drop_imp) - wri->drop_imp(ctx, wri); + if (wri->close) + wri->close(ctx, wri); fz_free(ctx, wri); } diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c index b4c565cf..5154f818 100644 --- a/source/pdf/pdf-write.c +++ b/source/pdf/pdf-write.c @@ -3102,3 +3102,97 @@ void pdf_finish_edit(fz_context *ctx, pdf_document *doc) return; pdf_rebalance_page_tree(ctx, doc); } + +typedef struct pdf_writer_s pdf_writer; + +struct pdf_writer_s +{ + fz_document_writer super; + pdf_document *pdf; + pdf_write_options opts; + char *filename; + + fz_rect mediabox; + pdf_obj *resources; + fz_buffer *contents; +}; + +static fz_device * +pdf_writer_begin_page(fz_context *ctx, fz_document_writer *wri_, const fz_rect *mediabox, fz_matrix *ctm) +{ + pdf_writer *wri = (pdf_writer*)wri_; + wri->mediabox = *mediabox; + *ctm = fz_identity; + return pdf_page_write(ctx, wri->pdf, &wri->mediabox, &wri->resources, &wri->contents); +} + +static void +pdf_writer_end_page(fz_context *ctx, fz_document_writer *wri_, fz_device *dev) +{ + pdf_writer *wri = (pdf_writer*)wri_; + pdf_obj *obj = NULL; + + fz_var(obj); + + fz_try(ctx) + { + fz_drop_device(ctx, dev); + obj = pdf_add_page(ctx, wri->pdf, &wri->mediabox, 0, wri->resources, wri->contents); + pdf_insert_page(ctx, wri->pdf, -1, obj); + } + fz_always(ctx) + { + pdf_drop_obj(ctx, obj); + fz_drop_buffer(ctx, wri->contents); + wri->contents = NULL; + pdf_drop_obj(ctx, wri->resources); + wri->resources = NULL; + } + fz_catch(ctx) + fz_rethrow(ctx); +} + +static void +pdf_writer_close(fz_context *ctx, fz_document_writer *wri_) +{ + pdf_writer *wri = (pdf_writer*)wri_; + fz_try(ctx) + pdf_save_document(ctx, wri->pdf, wri->filename, &wri->opts); + fz_always(ctx) + { + fz_drop_buffer(ctx, wri->contents); + pdf_drop_obj(ctx, wri->resources); + pdf_drop_document(ctx, wri->pdf); + fz_free(ctx, wri->filename); + } + fz_catch(ctx) + fz_rethrow(ctx); +} + +fz_document_writer * +fz_new_pdf_writer(fz_context *ctx, const char *path, const char *options) +{ + pdf_writer *wri; + + wri = fz_malloc_struct(ctx, pdf_writer); + wri->super.begin_page = pdf_writer_begin_page; + wri->super.end_page = pdf_writer_end_page; + wri->super.close = pdf_writer_close; + + fz_try(ctx) + { + wri->filename = fz_strdup(ctx, path); + wri->pdf = pdf_create_document(ctx); + } + fz_catch(ctx) + { + pdf_drop_document(ctx, wri->pdf); + fz_free(ctx, wri->filename); + fz_free(ctx, wri); + fz_rethrow(ctx); + } + + pdf_parse_write_options(ctx, &wri->opts, options); + + return (fz_document_writer*)wri; +} diff --git a/source/tools/muconvert.c b/source/tools/muconvert.c index 18bbd46b..7c2d1f4f 100644 --- a/source/tools/muconvert.c +++ b/source/tools/muconvert.c @@ -20,6 +20,7 @@ static const char *options = ""; static fz_context *ctx; static fz_document *doc; static fz_document_writer *out; +static int count; static void usage(void) { @@ -43,12 +44,80 @@ static void usage(void) "\n" ); fprintf(stderr, "%s\n", fz_cbz_write_options_usage); + fprintf(stderr, "%s\n", fz_pdf_write_options_usage); exit(1); } +static int isrange(const char *s) +{ + while (*s) + { + if ((*s < '0' || *s > '9') && *s != 'N' && *s != '-' && *s != ',') + return 0; + s++; + } + return 1; +} + +static void runpage(int number) +{ + fz_matrix ctm; + fz_rect mediabox; + fz_page *page; + fz_device *dev; + + page = fz_load_page(ctx, doc, number - 1); + fz_bound_page(ctx, page, &mediabox); + dev = fz_begin_page(ctx, out, &mediabox, &ctm); + fz_run_page(ctx, page, dev, &ctm, NULL); + fz_end_page(ctx, out, dev); + fz_drop_page(ctx, page); +} + +static void runrange(char *s) +{ + int start, end, i; + while (s[0]) + { + if (s[0] == 'N') + { + start = count; + s += 1; + } + else + start = strtol(s, &s, 10); + + if (s[0] == '-') + { + if (s[1] == 'N') + { + end = count; + s += 2; + } + else + end = strtol(s+1, &s, 10); + } + else + end = start; + + start = fz_clampi(start, 1, count); + end = fz_clampi(end, 1, count); + + if (start < end) + for (i = start; i <= end; ++i) + runpage(i); + else + for (i = start; i >= end; --i) + runpage(i); + + if (s[0] != ',') + break; + } +} + int muconvert_main(int argc, char **argv) { - int i, k, n, c; + int i, c; while ((c = fz_getopt(argc, argv, "p:A:W:H:S:U:o:F:O:")) != -1) { @@ -117,22 +186,12 @@ int muconvert_main(int argc, char **argv) if (!fz_authenticate_password(ctx, doc, password)) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot authenticate password: %s", argv[i]); fz_layout_document(ctx, doc, layout_w, layout_h, layout_em); + count = fz_count_pages(ctx, doc); - n = fz_count_pages(ctx, doc); - for (k = 0; k < n; ++k) - { - fz_matrix ctm; - fz_rect mediabox; - fz_page *page; - fz_device *dev; - - page = fz_load_page(ctx, doc, k); - fz_bound_page(ctx, page, &mediabox); - dev = fz_begin_page(ctx, out, &mediabox, &ctm); - fz_run_page(ctx, page, dev, &ctm, NULL); - fz_end_page(ctx, out, dev); - fz_drop_page(ctx, page); - } + if (isrange(argv[i+1])) + runrange(argv[++i]); + else + runrange("1-N"); fz_drop_document(ctx, doc); } -- cgit v1.2.3