diff options
author | Paul Gardiner <paulg.artifex@glidos.net> | 2013-07-04 12:11:20 +0100 |
---|---|---|
committer | Paul Gardiner <paulg.artifex@glidos.net> | 2013-07-04 12:11:20 +0100 |
commit | ac84904af638b243284e24d5f401c3f1a21cb0ef (patch) | |
tree | 32e9f6b3b0d0ad83cb8f2dd0c41bc5e60b53ed3e | |
parent | b33b3b41100f2bb0b63dbf270bdd4401451c081a (diff) | |
download | mupdf-ac84904af638b243284e24d5f401c3f1a21cb0ef.tar.xz |
Update pdf_write_document to support incremental update
-rw-r--r-- | include/mupdf/fitz/write-document.h | 1 | ||||
-rw-r--r-- | include/mupdf/pdf/xref.h | 1 | ||||
-rw-r--r-- | platform/android/jni/mupdf.c | 31 | ||||
-rw-r--r-- | platform/x11/jstest_main.c | 4 | ||||
-rw-r--r-- | platform/x11/pdfapp.c | 7 | ||||
-rw-r--r-- | platform/x11/pdfapp.h | 1 | ||||
-rw-r--r-- | platform/x11/win_main.c | 22 | ||||
-rw-r--r-- | platform/x11/x11_main.c | 11 | ||||
-rw-r--r-- | source/pdf/pdf-write.c | 156 | ||||
-rw-r--r-- | source/pdf/pdf-xref.c | 44 | ||||
-rw-r--r-- | source/tools/pdfclean.c | 1 | ||||
-rw-r--r-- | source/tools/pdfposter.c | 1 |
12 files changed, 220 insertions, 60 deletions
diff --git a/include/mupdf/fitz/write-document.h b/include/mupdf/fitz/write-document.h index f345cc56..9fe27f5f 100644 --- a/include/mupdf/fitz/write-document.h +++ b/include/mupdf/fitz/write-document.h @@ -12,6 +12,7 @@ */ struct fz_write_options_s { + int do_incremental; /* Write just the changed objects */ int do_ascii; /* If non-zero then attempt (where possible) to make the output ascii. */ int do_expand; /* Bitflags; each non zero bit indicates an aspect diff --git a/include/mupdf/pdf/xref.h b/include/mupdf/pdf/xref.h index c0544717..5d4ecde9 100644 --- a/include/mupdf/pdf/xref.h +++ b/include/mupdf/pdf/xref.h @@ -76,6 +76,7 @@ pdf_xref_entry *pdf_get_populating_xref_entry(pdf_document *doc, int i); pdf_xref_entry *pdf_get_xref_entry(pdf_document *doc, int i); void pdf_replace_xref(pdf_document *doc, pdf_xref_entry *entries, int n); void pdf_xref_ensure_incremental_object(pdf_document *doc, int num); +int pdf_xref_is_incremental(pdf_document *doc, int num); void pdf_repair_xref(pdf_document *doc, pdf_lexbuf *buf); void pdf_repair_obj_stms(pdf_document *doc); diff --git a/platform/android/jni/mupdf.c b/platform/android/jni/mupdf.c index bb827778..889abe07 100644 --- a/platform/android/jni/mupdf.c +++ b/platform/android/jni/mupdf.c @@ -2342,21 +2342,42 @@ JNI_FN(MuPDFCore_saveInternal)(JNIEnv * env, jobject thiz) { char *tmp; fz_write_options opts; - opts.do_ascii = 1; + opts.do_incremental = 1; + opts.do_ascii = 0; opts.do_expand = 0; - opts.do_garbage = 1; + opts.do_garbage = 0; opts.do_linear = 0; tmp = tmp_path(glo->current_path); if (tmp) { - int written; + int written = 0; fz_var(written); fz_try(ctx) { - fz_write_document(glo->doc, tmp, &opts); - written = 1; + FILE *fin = fopen(glo->current_path, "rb"); + FILE *fout = fopen(tmp, "wb"); + char buf[256]; + int n, err = 1; + + if (fin && fout) + { + while ((n = fread(buf, 1, sizeof(buf), fin)) > 0) + fwrite(buf, 1, n, fout); + err = (ferror(fin) || ferror(fout)); + } + + if (fin) + fclose(fin); + if (fout) + fclose(fout); + + if (!err) + { + fz_write_document(glo->doc, tmp, &opts); + written = 1; + } } fz_catch(ctx) { diff --git a/platform/x11/jstest_main.c b/platform/x11/jstest_main.c index 2003ad55..a07385bc 100644 --- a/platform/x11/jstest_main.c +++ b/platform/x11/jstest_main.c @@ -108,6 +108,10 @@ void winreplacefile(char *source, char *target) { } +void wincopyfile(char *source, char *target) +{ +} + void wincursor(pdfapp_t *app, int curs) { } diff --git a/platform/x11/pdfapp.c b/platform/x11/pdfapp.c index e76c6c7c..71561f14 100644 --- a/platform/x11/pdfapp.c +++ b/platform/x11/pdfapp.c @@ -299,13 +299,15 @@ static int pdfapp_save(pdfapp_t *app) { fz_write_options opts; - opts.do_ascii = 1; + opts.do_incremental = 1; + opts.do_ascii = 0; opts.do_expand = 0; - opts.do_garbage = 1; + opts.do_garbage = 0; opts.do_linear = 0; if (strcmp(buf, app->docpath) != 0) { + wincopyfile(app->docpath, buf); fz_write_document(app->doc, buf, &opts); return 1; } @@ -316,6 +318,7 @@ static int pdfapp_save(pdfapp_t *app) fz_try(app->ctx) { + wincopyfile(app->docpath, buf); fz_write_document(app->doc, buf, &opts); written = 1; } diff --git a/platform/x11/pdfapp.h b/platform/x11/pdfapp.h index 3e40e0c4..0b89923e 100644 --- a/platform/x11/pdfapp.h +++ b/platform/x11/pdfapp.h @@ -42,6 +42,7 @@ extern void winalert(pdfapp_t *, pdf_alert_event *alert); extern void winprint(pdfapp_t *); extern void winadvancetimer(pdfapp_t *, float duration); extern void winreplacefile(char *source, char *target); +extern void wincopyfile(char *source, char *target); struct pdfapp_s { diff --git a/platform/x11/win_main.c b/platform/x11/win_main.c index cc01d539..a22e7fc0 100644 --- a/platform/x11/win_main.c +++ b/platform/x11/win_main.c @@ -248,6 +248,28 @@ void winreplacefile(char *source, char *target) #endif } +void wincopyfile(char *source, char *target) +{ + wchar_t wsource[PATH_MAX]; + wchar_t wtarget[PATH_MAX]; + + int sz = MultiByteToWideChar(CP_UTF8, 0, source, -1, wsource, PATH_MAX); + if (sz == 0) + { + winerror(&gapp, "cannot convert filename to Unicode"); + return; + } + + sz = MultiByteToWideChar(CP_UTF8, 0, target, -1, wtarget, PATH_MAX); + if (sz == 0) + { + winerror(&gapp, "cannot convert filename to Unicode"); + return; + } + + CopyFile(wsource, wtarget, FALSE); +} + static char pd_filename[256] = "The file is encrypted."; static char pd_password[256] = ""; static wchar_t pd_passwordw[256] = {0}; diff --git a/platform/x11/x11_main.c b/platform/x11/x11_main.c index 481adce1..0bcb98f4 100644 --- a/platform/x11/x11_main.c +++ b/platform/x11/x11_main.c @@ -281,6 +281,17 @@ void winreplacefile(char *source, char *target) rename(source, target); } +void wincopyfile(char *source, char *target) +{ + char *buf = malloc(strlen(source)+strlen(target)+4); + if (buf) + { + sprintf(buf, "cp %s %s", source, target); + system(buf); + free(buf); + } +} + void cleanup(pdfapp_t *app) { fz_context *ctx = app->ctx; diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c index 4e6ddb21..63fab4f1 100644 --- a/source/pdf/pdf-write.c +++ b/source/pdf/pdf-write.c @@ -46,6 +46,7 @@ typedef struct { struct pdf_write_options_s { FILE *out; + int do_incremental; int do_ascii; int do_expand; int do_garbage; @@ -1750,16 +1751,11 @@ static void writeobject(pdf_document *doc, pdf_write_options *opts, int num, int pdf_drop_obj(obj); } -static void writexref(pdf_document *doc, pdf_write_options *opts, int from, int to, int first, int main_xref_offset, int startxref) +static void writexrefsubsect(pdf_write_options *opts, int from, int to) { - pdf_obj *trailer = NULL; - pdf_obj *obj; - pdf_obj *nobj = NULL; int num; - fz_context *ctx = doc->ctx; - fprintf(opts->out, "xref\n%d %d\n", from, to - from); - opts->first_xref_entry_offset = ftell(opts->out); + fprintf(opts->out, "%d %d\n", from, to - from); for (num = from; num < to; num++) { if (opts->use_list[num]) @@ -1767,6 +1763,43 @@ static void writexref(pdf_document *doc, pdf_write_options *opts, int from, int else fprintf(opts->out, "%010d %05d f \n", opts->ofs_list[num], opts->gen_list[num]); } +} + +static void writexref(pdf_document *doc, pdf_write_options *opts, int from, int to, int first, int main_xref_offset, int startxref) +{ + pdf_obj *trailer = NULL; + pdf_obj *obj; + pdf_obj *nobj = NULL; + fz_context *ctx = doc->ctx; + + fprintf(opts->out, "xref\n"); + opts->first_xref_entry_offset = ftell(opts->out); + + if (opts->do_incremental) + { + int subfrom = from; + int subto; + + while (subfrom < to) + { + while (subfrom < to && !pdf_xref_is_incremental(doc, subfrom)) + subfrom++; + + subto = subfrom; + while (subto < to && pdf_xref_is_incremental(doc, subto)) + subto++; + + if (subfrom < subto) + writexrefsubsect(opts, subfrom, subto); + + subfrom = subto; + } + } + else + { + writexrefsubsect(opts, from, to); + } + fprintf(opts->out, "\n"); fz_var(trailer); @@ -1774,33 +1807,43 @@ static void writexref(pdf_document *doc, pdf_write_options *opts, int from, int fz_try(ctx) { - trailer = pdf_new_dict(doc, 5); - - nobj = pdf_new_int(doc, to); - pdf_dict_puts(trailer, "Size", nobj); - pdf_drop_obj(nobj); - nobj = NULL; - - if (first) + if (opts->do_incremental) { - obj = pdf_dict_gets(pdf_trailer(doc), "Info"); - if (obj) - pdf_dict_puts(trailer, "Info", obj); - - obj = pdf_dict_gets(pdf_trailer(doc), "Root"); - if (obj) - pdf_dict_puts(trailer, "Root", obj); - - obj = pdf_dict_gets(pdf_trailer(doc), "ID"); - if (obj) - pdf_dict_puts(trailer, "ID", obj); + trailer = pdf_keep_obj(pdf_trailer(doc)); + pdf_dict_puts_drop(trailer, "Size", pdf_new_int(doc, pdf_xref_len(doc))); + pdf_dict_puts_drop(trailer, "Prev", pdf_new_int(doc, doc->startxref)); + doc->startxref = startxref; } - if (main_xref_offset != 0) + else { - nobj = pdf_new_int(doc, main_xref_offset); - pdf_dict_puts(trailer, "Prev", nobj); + trailer = pdf_new_dict(doc, 5); + + nobj = pdf_new_int(doc, to); + pdf_dict_puts(trailer, "Size", nobj); pdf_drop_obj(nobj); nobj = NULL; + + if (first) + { + obj = pdf_dict_gets(pdf_trailer(doc), "Info"); + if (obj) + pdf_dict_puts(trailer, "Info", obj); + + obj = pdf_dict_gets(pdf_trailer(doc), "Root"); + if (obj) + pdf_dict_puts(trailer, "Root", obj); + + obj = pdf_dict_gets(pdf_trailer(doc), "ID"); + if (obj) + pdf_dict_puts(trailer, "ID", obj); + } + if (main_xref_offset != 0) + { + nobj = pdf_new_int(doc, main_xref_offset); + pdf_dict_puts(trailer, "Prev", nobj); + pdf_drop_obj(nobj); + nobj = NULL; + } } } fz_always(ctx) @@ -1861,7 +1904,8 @@ dowriteobject(pdf_document *doc, pdf_write_options *opts, int num, int pass) if (pass > 0) padto(opts->out, opts->ofs_list[num]); opts->ofs_list[num] = ftell(opts->out); - writeobject(doc, opts, num, opts->gen_list[num]); + if (!opts->do_incremental || pdf_xref_is_incremental(doc, num)) + writeobject(doc, opts, num, opts->gen_list[num]); } else opts->use_list[num] = 0; @@ -1873,8 +1917,11 @@ writeobjects(pdf_document *doc, pdf_write_options *opts, int pass) int num; int xref_len = pdf_xref_len(doc); - fprintf(opts->out, "%%PDF-%d.%d\n", doc->version / 10, doc->version % 10); - fprintf(opts->out, "%%\316\274\341\277\246\n\n"); + if (!opts->do_incremental) + { + fprintf(opts->out, "%%PDF-%d.%d\n", doc->version / 10, doc->version % 10); + fprintf(opts->out, "%%\316\274\341\277\246\n\n"); + } dowriteobject(doc, opts, opts->start, pass); @@ -2241,12 +2288,23 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_ xref_len = pdf_xref_len(doc); - opts.out = fopen(filename, "wb"); + if (fz_opts->do_incremental) + { + opts.out = fopen(filename, "ab"); + if (opts.out) + fseek(opts.out, 0, SEEK_END); + } + else + { + opts.out = fopen(filename, "wb"); + } + if (!opts.out) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open output file '%s'", filename); fz_try(ctx) { + opts.do_incremental = fz_opts ? fz_opts->do_incremental : 0; opts.do_expand = fz_opts ? fz_opts->do_expand : 0; opts.do_garbage = fz_opts ? fz_opts->do_garbage : 0; opts.do_ascii = fz_opts ? fz_opts->do_ascii: 0; @@ -2275,7 +2333,8 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_ } /* Make sure any objects hidden in compressed streams have been loaded */ - preloadobjstms(doc); + if (!opts.do_incremental) + preloadobjstms(doc); /* Sweep & mark objects from the trailer */ if (opts.do_garbage >= 1) @@ -2307,15 +2366,30 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_ dump_object_details(doc, &opts); #endif - /* Construct linked list of free object slots */ - lastfree = 0; - for (num = 0; num < xref_len; num++) + if (opts.do_incremental) { - if (!opts.use_list[num]) + for (num = 0; num < xref_len; num++) { - opts.gen_list[num]++; - opts.ofs_list[lastfree] = num; - lastfree = num; + if (!opts.use_list[num] && pdf_xref_is_incremental(doc, num)) + { + /* Make unreusable. FIXME: would be better to link to existing free list */ + opts.gen_list[num] = 65535; + opts.ofs_list[num] = 0; + } + } + } + else + { + /* Construct linked list of free object slots */ + lastfree = 0; + for (num = 0; num < xref_len; num++) + { + if (!opts.use_list[num]) + { + opts.gen_list[num]++; + opts.ofs_list[lastfree] = num; + lastfree = num; + } } } diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c index 0337bb16..71213fd7 100644 --- a/source/pdf/pdf-xref.c +++ b/source/pdf/pdf-xref.c @@ -154,21 +154,34 @@ pdf_xref_entry *pdf_get_xref_entry(pdf_document *doc, int i) static void ensure_incremental_xref(pdf_document *doc) { fz_context *ctx = doc->ctx; - pdf_xref *xref, *pxref; if (!doc->xref_altered) { - pdf_xref_entry *new_table; - doc->xref_sections = fz_resize_array(ctx, doc->xref_sections, doc->num_xref_sections + 1, sizeof(pdf_xref)); - xref = &doc->xref_sections[0]; - pxref = &doc->xref_sections[1]; - new_table = fz_calloc(ctx, xref->len, sizeof(pdf_xref_entry)); - memmove(pxref, xref, doc->num_xref_sections * sizeof(pdf_xref)); - doc->num_xref_sections++; - /* xref->len is already correct */ - xref->table = new_table; - xref->trailer = pdf_keep_obj(pxref->trailer); - doc->xref_altered = 1; + pdf_xref *xref = &doc->xref_sections[0]; + pdf_xref *pxref; + pdf_xref_entry *new_table = fz_calloc(ctx, xref->len, sizeof(pdf_xref_entry)); + pdf_obj *trailer = NULL; + + fz_var(trailer); + fz_try(ctx) + { + trailer = pdf_copy_dict(xref->trailer); + doc->xref_sections = fz_resize_array(ctx, doc->xref_sections, doc->num_xref_sections + 1, sizeof(pdf_xref)); + xref = &doc->xref_sections[0]; + pxref = &doc->xref_sections[1]; + memmove(pxref, xref, doc->num_xref_sections * sizeof(pdf_xref)); + /* xref->len is already correct */ + xref->table = new_table; + xref->trailer = trailer; + doc->num_xref_sections++; + doc->xref_altered = 1; + } + fz_catch(ctx) + { + fz_free(ctx, new_table); + pdf_drop_obj(trailer); + fz_rethrow(ctx); + } } } @@ -188,6 +201,13 @@ static pdf_xref_entry *pdf_get_incremental_xref_entry(pdf_document *doc, int i) return &xref->table[i]; } +int pdf_xref_is_incremental(pdf_document *doc, int num) +{ + pdf_xref *xref = &doc->xref_sections[0]; + + return doc->xref_altered && num < xref->len && xref->table[num].type; +} + /* Ensure that an object has been cloned into the incremental xref section */ void pdf_xref_ensure_incremental_object(pdf_document *doc, int num) { diff --git a/source/tools/pdfclean.c b/source/tools/pdfclean.c index aac3a888..f42269a8 100644 --- a/source/tools/pdfclean.c +++ b/source/tools/pdfclean.c @@ -163,6 +163,7 @@ int pdfclean_main(int argc, char **argv) int write_failed = 0; int errors = 0; + opts.do_incremental = 0; opts.do_garbage = 0; opts.do_expand = 0; opts.do_ascii = 0; diff --git a/source/tools/pdfposter.c b/source/tools/pdfposter.c index 981bf0c0..4702c2aa 100644 --- a/source/tools/pdfposter.c +++ b/source/tools/pdfposter.c @@ -133,6 +133,7 @@ int pdfposter_main(int argc, char **argv) pdf_document *doc; fz_context *ctx; + opts.do_incremental = 0; opts.do_garbage = 0; opts.do_expand = 0; opts.do_ascii = 0; |