From 0afe72e5fc386aa0ebceec9618f2b681f9bfdc3d Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Mon, 25 Mar 2013 16:42:46 +0000 Subject: Initial PDF editing/page creation commit --- include/mupdf/fitz/compressed-buffer.h | 2 +- include/mupdf/pdf/document.h | 22 ++++++ source/pdf/pdf-device.c | 67 ++++++++++++----- source/pdf/pdf-page.c | 129 +++++++++++++++++++++++++++++++++ source/pdf/pdf-write.c | 98 ++++++++++++++++++++++++- source/pdf/pdf-xref.c | 45 ++++++++++++ source/tools/mudraw.c | 62 +++++++++++++++- 7 files changed, 399 insertions(+), 26 deletions(-) diff --git a/include/mupdf/fitz/compressed-buffer.h b/include/mupdf/fitz/compressed-buffer.h index 10977a86..784c2eb0 100644 --- a/include/mupdf/fitz/compressed-buffer.h +++ b/include/mupdf/fitz/compressed-buffer.h @@ -34,7 +34,7 @@ struct fz_compression_params_s int type; union { struct { - int color_transform; + int color_transform; /* Use -1 for unset */ } jpeg; struct { int smask_in_data; diff --git a/include/mupdf/pdf/document.h b/include/mupdf/pdf/document.h index a096384d..a8bc332a 100644 --- a/include/mupdf/pdf/document.h +++ b/include/mupdf/pdf/document.h @@ -191,6 +191,7 @@ struct pdf_document_s pdf_obj **page_objs; pdf_obj **page_refs; int resources_localised; + int needs_page_tree_rebuild; pdf_lexbuf_large lexbuf; @@ -206,4 +207,25 @@ struct pdf_document_s void *event_cb_data; }; +/* + PDF creation +*/ + +/* + pdf_create_document: Create a blank PDF document +*/ +pdf_document *pdf_create_document(fz_context *ctx); + +pdf_page *pdf_create_page(pdf_document *doc, fz_rect rect, int res, int rotate); + +void pdf_insert_page(pdf_document *doc, pdf_page *page, int at); + +void pdf_delete_page(pdf_document *doc, int number); + +void pdf_delete_page_range(pdf_document *doc, int start, int end); + +fz_device *pdf_page_write(pdf_document *doc, pdf_page *page); + +void pdf_finish_edit(pdf_document *doc); + #endif diff --git a/source/pdf/pdf-device.c b/source/pdf/pdf-device.c index 602a778f..29d2556d 100644 --- a/source/pdf/pdf-device.c +++ b/source/pdf/pdf-device.c @@ -118,6 +118,9 @@ send_image(pdf_device *pdev, fz_image *image, int mask, int smask) int bpc = 8; fz_colorspace *colorspace = image->colorspace; + /* If we can maintain compression, do so */ + cbuffer = image->buffer; + fz_var(pixmap); fz_var(buffer); fz_var(imobj); @@ -125,7 +128,12 @@ send_image(pdf_device *pdev, fz_image *image, int mask, int smask) fz_try(ctx) { - if (cbuffer == NULL) + if (cbuffer != NULL && cbuffer->params.type != FZ_IMAGE_PNG && cbuffer->params.type != FZ_IMAGE_TIFF) + { + buffer = fz_keep_buffer(ctx, cbuffer->buffer); + cp = &cbuffer->params; + } + else { unsigned int size; int n; @@ -156,11 +164,6 @@ send_image(pdf_device *pdev, fz_image *image, int mask, int smask) } } } - else - { - buffer = fz_keep_buffer(ctx, cbuffer->buffer); - cp = &cbuffer->params; - } fz_md5_init(&state); fz_md5_update(&state, buffer->data, buffer->len); @@ -202,9 +205,11 @@ send_image(pdf_device *pdev, fz_image *image, int mask, int smask) pdf_dict_puts_drop(imobj, "ColorSpace", pdf_new_name(ctx, "DeviceRGB")); else if (colorspace->n == 4) pdf_dict_puts_drop(imobj, "ColorSpace", pdf_new_name(ctx, "DeviceCMYK")); + if (!mask) + pdf_dict_puts_drop(imobj, "BitsPerComponent", pdf_new_int(ctx, image->bpc)); switch (cp ? cp->type : FZ_IMAGE_UNKNOWN) { - case FZ_IMAGE_UNKNOWN: + case FZ_IMAGE_UNKNOWN: /* Unknown also means raw */ default: break; case FZ_IMAGE_JPEG: @@ -251,6 +256,7 @@ send_image(pdf_device *pdev, fz_image *image, int mask, int smask) if (cp->u.flate.bpc) bpc = cp->u.flate.bpc; pdf_dict_puts(imobj, "Filter", pdf_new_name(ctx, "FlateDecode")); + pdf_dict_puts_drop(imobj, "BitsPerComponent", pdf_new_int(ctx, image->bpc)); break; case FZ_IMAGE_LZW: if (cp->u.lzw.columns) @@ -279,8 +285,6 @@ send_image(pdf_device *pdev, fz_image *image, int mask, int smask) int smasknum = send_image(pdev, image->mask, 0, 1); pdf_dict_puts(imobj, "SMask", pdev->images[smasknum].ref); } - if (bpc) - pdf_dict_puts_drop(imobj, "BitsPerComponent", pdf_new_int(ctx, bpc)); imref = pdf_new_ref(pdev->xref, imobj); pdf_update_stream(pdev->xref, pdf_to_num(imref), buffer); @@ -371,23 +375,23 @@ pdf_dev_path(pdf_device *pdev, fz_path *path) case FZ_MOVETO: x = path->items[i++].v; y = path->items[i++].v; - fz_buffer_printf(ctx, gs->buf, "%g %g m\n", x, y); + fz_buffer_printf(ctx, gs->buf, "%f %f m\n", x, y); break; case FZ_LINETO: x = path->items[i++].v; y = path->items[i++].v; - fz_buffer_printf(ctx, gs->buf, "%g %g l\n", x, y); + fz_buffer_printf(ctx, gs->buf, "%f %f l\n", x, y); break; case FZ_CURVETO: x = path->items[i++].v; y = path->items[i++].v; - fz_buffer_printf(ctx, gs->buf, "%g %g ", x, y); + fz_buffer_printf(ctx, gs->buf, "%f %f ", x, y); x = path->items[i++].v; y = path->items[i++].v; - fz_buffer_printf(ctx, gs->buf, "%g %g ", x, y); + fz_buffer_printf(ctx, gs->buf, "%f %f ", x, y); x = path->items[i++].v; y = path->items[i++].v; - fz_buffer_printf(ctx, gs->buf, "%g %g c\n", x, y); + fz_buffer_printf(ctx, gs->buf, "%f %f c\n", x, y); break; case FZ_CLOSE_PATH: fz_buffer_printf(ctx, gs->buf, "h\n"); @@ -589,7 +593,7 @@ pdf_dev_font(pdf_device *pdev, fz_font *font, float size) } pdev->num_fonts++; } - fz_buffer_printf(ctx, gs->buf, "/F%d %g Tf\n", i, size); + fz_buffer_printf(ctx, gs->buf, "/F%d %f Tf\n", i, size); } static void @@ -677,7 +681,7 @@ pdf_dev_text(pdf_device *pdev, fz_text *text) fz_transform_point(&delta, &inverse); if (delta.x != 0 || delta.y != 0) { - fz_buffer_printf(pdev->ctx, gs->buf, "%g %g Td ", delta.x, delta.y); + fz_buffer_printf(pdev->ctx, gs->buf, "%f %f Td ", delta.x, delta.y); trm.e = it->x; trm.f = it->y; } @@ -901,6 +905,9 @@ pdf_dev_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, pdf_dev_begin_text(pdev, &text->trm, 0); pdf_dev_font(pdev, text->font, 1); + pdf_dev_ctm(pdev, ctm); + pdf_dev_alpha(pdev, alpha, 0); + pdf_dev_color(pdev, colorspace, color, 0); pdf_dev_text(pdev, text); } @@ -912,6 +919,9 @@ pdf_dev_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, cons pdf_dev_begin_text(pdev, &text->trm, 1); pdf_dev_font(pdev, text->font, 1); + pdf_dev_ctm(pdev, ctm); + pdf_dev_alpha(pdev, alpha, 1); + pdf_dev_color(pdev, colorspace, color, 1); pdf_dev_text(pdev, text); } @@ -921,6 +931,7 @@ pdf_dev_clip_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, int accum pdf_device *pdev = dev->user; pdf_dev_begin_text(pdev, &text->trm, 0); + pdf_dev_ctm(pdev, ctm); pdf_dev_font(pdev, text->font, 7); pdf_dev_text(pdev, text); } @@ -932,6 +943,7 @@ pdf_dev_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, pdf_dev_begin_text(pdev, &text->trm, 0); pdf_dev_font(pdev, text->font, 5); + pdf_dev_ctm(pdev, ctm); pdf_dev_text(pdev, text); } @@ -941,6 +953,7 @@ pdf_dev_ignore_text(fz_device *dev, fz_text *text, const fz_matrix *ctm) pdf_device *pdev = dev->user; pdf_dev_begin_text(pdev, &text->trm, 0); + pdf_dev_ctm(pdev, ctm); pdf_dev_font(pdev, text->font, 3); pdf_dev_text(pdev, text); } @@ -955,13 +968,12 @@ pdf_dev_fill_image(fz_device *dev, fz_image *image, const fz_matrix *ctm, float pdf_dev_end_text(pdev); num = send_image(pdev, image, 0, 0); - fz_buffer_printf(dev->ctx, gs->buf, "q\n"); pdf_dev_alpha(pdev, alpha, 0); /* PDF images are upside down, so fiddle the ctm */ fz_pre_scale(&local_ctm, 1, -1); fz_pre_translate(&local_ctm, 0, -1); pdf_dev_ctm(pdev, &local_ctm); - fz_buffer_printf(dev->ctx, gs->buf, "/Img%d Do Q\n", num); + fz_buffer_printf(dev->ctx, gs->buf, "/Img%d Do\n", num); } static void @@ -1169,8 +1181,6 @@ pdf_dev_free_user(fz_device *dev) pdf_dict_puts_drop(pdev->contents, "Length", pdf_new_int(ctx, gs->buf->len)); - pdf_update_stream(pdev->xref, pdf_to_num(pdev->contents), gs->buf); - for (i = pdev->num_gstates-1; i >= 0; i--) { fz_drop_stroke_state(ctx, pdev->gstates[i].stroke_state); @@ -1186,6 +1196,9 @@ pdf_dev_free_user(fz_device *dev) pdf_drop_obj(pdev->images[i].ref); } + pdf_update_stream(pdev->xref, pdf_to_num(pdev->contents), pdev->gstates[0].buf); + fz_drop_buffer(ctx, pdev->gstates[0].buf); + pdf_drop_obj(pdev->contents); pdf_drop_obj(pdev->resources); @@ -1261,3 +1274,17 @@ fz_device *pdf_new_pdf_device(pdf_document *doc, pdf_obj *contents, pdf_obj *res return dev; } + +fz_device *pdf_page_write(pdf_document *doc, pdf_page *page) +{ + pdf_obj *resources = pdf_dict_gets(page->me, "Resources"); + fz_matrix ctm; + fz_pre_translate(fz_scale(&ctm, 1, -1), 0, page->mediabox.y0-page->mediabox.y1); + if (resources == NULL) + { + resources = pdf_new_dict(doc->ctx, 0); + pdf_dict_puts_drop(page->me, "Resources", resources); + } + + return pdf_new_pdf_device(doc, page->contents, resources, &ctm); +} diff --git a/source/pdf/pdf-page.c b/source/pdf/pdf-page.c index 8a12b67b..715f773e 100644 --- a/source/pdf/pdf-page.c +++ b/source/pdf/pdf-page.c @@ -487,3 +487,132 @@ pdf_free_page(pdf_document *xref, pdf_page *page) pdf_drop_obj(page->me); fz_free(xref->ctx, page); } + +void +pdf_delete_page(pdf_document *xref, int page) +{ + pdf_delete_page_range(xref, page, page+1); +} + +void +pdf_delete_page_range(pdf_document *xref, int start, int end) +{ + int i; + + if (start > end) + { + int tmp = start; + start = end; + end = tmp; + } + + if (!xref || start >= xref->page_len || end < 0) + return; + + for (i=start; i < end; i++) + pdf_drop_obj(xref->page_refs[i]); + if (xref->page_len > end) + { + memmove(&xref->page_refs[start], &xref->page_refs[end], sizeof(pdf_page *) * (xref->page_len - end + start)); + memmove(&xref->page_refs[start], &xref->page_refs[end], sizeof(pdf_page *) * (xref->page_len - end + start)); + } + + xref->page_len -= end - start; + xref->needs_page_tree_rebuild = 1; +} + +void +pdf_insert_page(pdf_document *xref, pdf_page *page, int at) +{ + if (!xref || !page) + return; + if (at < 0) + at = 0; + if (at > xref->page_len) + at = xref->page_len; + + if (xref->page_len + 1 >= xref->page_cap) + { + int newmax = xref->page_cap * 2; + if (newmax == 0) + newmax = 4; + xref->page_refs = fz_resize_array(xref->ctx, xref->page_refs, newmax, sizeof(pdf_page *)); + xref->page_objs = fz_resize_array(xref->ctx, xref->page_objs, newmax, sizeof(pdf_page *)); + xref->page_cap = newmax; + } + if (xref->page_len > at) + { + memmove(&xref->page_objs[at+1], &xref->page_objs[at], xref->page_len - at); + memmove(&xref->page_refs[at+1], &xref->page_refs[at], xref->page_len - at); + } + + xref->page_len++; + xref->page_objs[at] = pdf_keep_obj(page->me); + xref->page_refs[at] = NULL; + xref->page_refs[at] = pdf_new_ref(xref, page->me); + xref->needs_page_tree_rebuild = 1; +} + +pdf_page * +pdf_create_page(pdf_document *xref, fz_rect mediabox, int res, int rotate) +{ + pdf_page *page = NULL; + pdf_obj *pageobj, *obj; + float userunit = 1; + fz_context *ctx = xref->ctx; + fz_matrix ctm, tmp; + fz_rect realbox; + + page = fz_malloc_struct(ctx, pdf_page); + obj = NULL; + fz_var(obj); + + fz_try(ctx) + { + page->resources = NULL; + page->contents = NULL; + page->transparency = 0; + page->links = NULL; + page->annots = NULL; + page->me = pageobj = pdf_new_dict(ctx, 4); + + pdf_dict_puts_drop(pageobj, "Type", pdf_new_name(ctx, "Page")); + + page->mediabox.x0 = fz_min(mediabox.x0, mediabox.x1) * userunit; + page->mediabox.y0 = fz_min(mediabox.y0, mediabox.y1) * userunit; + page->mediabox.x1 = fz_max(mediabox.x0, mediabox.x1) * userunit; + page->mediabox.y1 = fz_max(mediabox.y0, mediabox.y1) * userunit; + pdf_dict_puts_drop(pageobj, "MediaBox", pdf_new_rect(ctx, &page->mediabox)); + + /* Snap page->rotate to 0, 90, 180 or 270 */ + if (page->rotate < 0) + page->rotate = 360 - ((-page->rotate) % 360); + if (page->rotate >= 360) + page->rotate = page->rotate % 360; + page->rotate = 90*((page->rotate + 45)/90); + if (page->rotate > 360) + page->rotate = 0; + pdf_dict_puts_drop(pageobj, "Rotate", pdf_new_int(ctx, page->rotate)); + + fz_pre_rotate(fz_scale(&ctm, 1, -1), -page->rotate); + realbox = page->mediabox; + fz_transform_rect(&realbox, &ctm); + fz_pre_scale(fz_translate(&tmp, -realbox.x0, -realbox.y0), userunit, userunit); + fz_concat(&ctm, &ctm, &tmp); + page->ctm = ctm; + obj = pdf_new_dict(ctx, 4); + page->contents = pdf_new_ref(xref, obj); + pdf_drop_obj(obj); + obj = NULL; + pdf_dict_puts(pageobj, "Contents", page->contents); + } + fz_catch(ctx) + { + pdf_drop_obj(page->me); + pdf_drop_obj(obj); + fz_free(ctx, page); + fz_rethrow_message(ctx, "Failed to create page"); + } + + return page; +} diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c index a423edef..e211372b 100644 --- a/source/pdf/pdf-write.c +++ b/source/pdf/pdf-write.c @@ -2223,13 +2223,17 @@ void pdf_write_document(pdf_document *xref, char *filename, fz_write_options *fz int num; pdf_write_options opts = { 0 }; fz_context *ctx; - int xref_len = pdf_xref_len(xref); + int xref_len; if (!xref) return; ctx = xref->ctx; + pdf_finish_edit(xref); + + xref_len = pdf_xref_len(xref); + opts.out = fopen(filename, "wb"); if (!opts.out) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open output file '%s'", filename); @@ -2361,3 +2365,95 @@ void pdf_write_document(pdf_document *xref, char *filename, fz_write_options *fz fz_rethrow(ctx); } } + +#define KIDS_PER_LEVEL 32 + +static pdf_obj * +make_page_tree_node(pdf_document *xref, int l, int r, pdf_obj *parent_ref, int root) +{ + fz_context *ctx = xref->ctx; + int count_per_kid, spaces; + pdf_obj *a = NULL; + pdf_obj *me = NULL; + pdf_obj *o = NULL; + pdf_obj *me_ref = NULL; + + count_per_kid = 1; + while(count_per_kid * KIDS_PER_LEVEL < r-l) + count_per_kid *= KIDS_PER_LEVEL; + + fz_var(o); + fz_var(me); + fz_var(a); + fz_var(me_ref); + + fz_try(ctx) + { + me = pdf_new_dict(ctx, 2); + pdf_dict_puts_drop(me, "Type", pdf_new_name(ctx, "Pages")); + pdf_dict_puts_drop(me, "Count", pdf_new_int(ctx, r-l)); + if (!root) + pdf_dict_puts(me, "Parent", parent_ref); + a = pdf_new_array(ctx, KIDS_PER_LEVEL); + me_ref = pdf_new_ref(xref, me); + + for (spaces = KIDS_PER_LEVEL; l < r; spaces--) + { + if (spaces >= r-l) + { + o = pdf_keep_obj(xref->page_refs[l++]); + pdf_dict_puts(o, "Parent", me_ref); + } + else + { + int j = l+count_per_kid; + if (j > r) + j = r; + o = make_page_tree_node(xref, l, j, me_ref, 0); + l = j; + } + pdf_array_push(a, o); + pdf_drop_obj(o); + o = NULL; + } + pdf_dict_puts_drop(me, "Kids", a); + a = NULL; + } + fz_always(ctx) + { + pdf_drop_obj(me); + } + fz_catch(ctx) + { + pdf_drop_obj(a); + pdf_drop_obj(o); + pdf_drop_obj(me); + fz_rethrow_message(ctx, "Failed to synthesize new page tree"); + } + return me_ref; +} + +static void +pdf_rebuild_page_tree(pdf_document *xref) +{ + pdf_obj *catalog; + pdf_obj *pages; + + if (!xref || !xref->needs_page_tree_rebuild) + return; + + catalog = pdf_dict_gets(pdf_trailer(xref), "Root"); + pages = make_page_tree_node(xref, 0, xref->page_len, catalog, 1); + pdf_dict_puts_drop(catalog, "Pages", pages); + + xref->needs_page_tree_rebuild = 0; +} + + +void pdf_finish_edit(pdf_document *xref) +{ + if (!xref) + return; + + pdf_rebuild_page_tree(xref); +} diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c index 9224d515..d4b94e3f 100644 --- a/source/pdf/pdf-xref.c +++ b/source/pdf/pdf-xref.c @@ -1550,3 +1550,48 @@ pdf_document *pdf_specifics(fz_document *doc) { return (pdf_document *)(doc->close == (void *)pdf_close_document ? doc : NULL); } + +pdf_document *pdf_create_document(fz_context *ctx) +{ + pdf_document *xref; + pdf_obj *o = NULL; + pdf_obj *root; + pdf_obj *pages; + pdf_obj *trailer = NULL; + + fz_var(o); + fz_var(trailer); + + xref = pdf_new_document(ctx, NULL); + fz_try(ctx) + { + xref->version = 14; + xref->file_size = 0; + xref->startxref = 0; + xref->num_xref_sections = 0; + pdf_get_populating_xref_entry(xref, 0); + xref->xref_altered = 1; + trailer = pdf_new_dict(ctx, 2); + pdf_dict_puts_drop(trailer, "Size", pdf_new_int(ctx, 3)); + o = root = pdf_new_dict(ctx, 2); + pdf_dict_puts_drop(trailer, "Root", pdf_new_ref(xref, o)); + pdf_drop_obj(o); + o = NULL; + pdf_dict_puts_drop(root, "Type", pdf_new_name(ctx, "Catalog")); + o = pages = pdf_new_dict(ctx, 3); + pdf_dict_puts_drop(root, "Pages", pdf_new_ref(xref, o)); + pdf_drop_obj(o); + o = NULL; + pdf_dict_puts_drop(pages, "Type", pdf_new_name(ctx, "Pages")); + pdf_dict_puts_drop(pages, "Count", pdf_new_int(ctx, 0)); + pdf_dict_puts_drop(pages, "Kids", pdf_new_array(ctx, 1)); + pdf_set_populating_xref_trailer(xref, trailer); + } + fz_catch(ctx) + { + pdf_drop_obj(trailer); + pdf_drop_obj(o); + fz_rethrow_message(ctx, "Failed to create empty document"); + } + return xref; +} diff --git a/source/tools/mudraw.c b/source/tools/mudraw.c index 57bd4be2..1803447b 100644 --- a/source/tools/mudraw.c +++ b/source/tools/mudraw.c @@ -14,7 +14,7 @@ enum { TEXT_PLAIN = 1, TEXT_HTML = 2, TEXT_XML = 3 }; -enum { OUT_PNG, OUT_PPM, OUT_PNM, OUT_PAM, OUT_PGM, OUT_PBM, OUT_SVG, OUT_PWG, OUT_PCL }; +enum { OUT_PNG, OUT_PPM, OUT_PNM, OUT_PAM, OUT_PGM, OUT_PBM, OUT_SVG, OUT_PWG, OUT_PCL, OUT_PDF }; enum { CS_INVALID, CS_UNSET, CS_MONO, CS_GRAY, CS_GRAYALPHA, CS_RGB, CS_RGBA }; @@ -34,7 +34,8 @@ static const suffix_t suffix_table[] = { ".pbm", OUT_PBM }, { ".svg", OUT_SVG }, { ".pwg", OUT_PWG }, - { ".pcl", OUT_PCL } + { ".pcl", OUT_PCL }, + { ".pdf", OUT_PDF }, }; typedef struct @@ -75,7 +76,8 @@ static const format_cs_table_t format_cs_table[] = { OUT_PBM, CS_MONO, { CS_MONO } }, { OUT_SVG, CS_RGB, { CS_RGB } }, { OUT_PWG, CS_RGB, { CS_MONO, CS_GRAY, CS_RGB } }, - { OUT_PCL, CS_MONO, { CS_MONO } } + { OUT_PCL, CS_MONO, { CS_MONO } }, + { OUT_PDF, CS_RGB, { CS_RGB } } }; /* @@ -137,6 +139,7 @@ static int showxml = 0; static int showtext = 0; static int showtime = 0; static int showmd5 = 0; +static pdf_document *pdfout = NULL; static int showoutline = 0; static int uselist = 1; static int alphabits = 8; @@ -473,6 +476,44 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) if (showmd5 || showtime) printf("page %s %d", filename, pagenum); + if (pdfout) + { + fz_matrix ctm; + fz_rect bounds, tbounds; + pdf_page *newpage; + + fz_bound_page(doc, page, &bounds); + fz_rotate(&ctm, rotation); + tbounds = bounds; + fz_transform_rect(&tbounds, &ctm); + + newpage = pdf_create_page(pdfout, bounds, 72, 0); + + fz_try(ctx) + { + dev = pdf_page_write(pdfout, newpage); + if (list) + fz_run_display_list(list, dev, &ctm, &tbounds, &cookie); + else + fz_run_page(doc, page, dev, &ctm, &cookie); + fz_free_device(dev); + dev = NULL; + } + fz_always(ctx) + { + fz_free_device(dev); + dev = NULL; + } + fz_catch(ctx) + { + fz_drop_display_list(ctx, list); + fz_free_page(doc, page); + fz_rethrow(ctx); + } + pdf_insert_page(pdfout, newpage, INT_MAX); + pdf_free_page(pdfout, newpage); + } + if (output && output_format == OUT_SVG) { float zoom; @@ -519,7 +560,7 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) } } - if ((output && output_format != OUT_SVG)|| showmd5 || showtime) + if ((output && output_format != OUT_SVG && !pdfout)|| showmd5 || showtime) { float zoom; fz_matrix ctm; @@ -936,6 +977,11 @@ int main(int argc, char **argv) break; } + if (output_format == OUT_PDF) + { + pdfout = pdf_create_document(ctx); + } + timing.count = 0; timing.total = 0; timing.min = 1 << 30; @@ -1037,6 +1083,14 @@ int main(int argc, char **argv) errored = 1; } + if (pdfout) + { + fz_write_options opts = { 0 }; + + pdf_write_document(pdfout, output, &opts); + pdf_close_document(pdfout); + } + if (showtext == TEXT_HTML) { fz_printf(out, "\n"); -- cgit v1.2.3