diff options
author | Robin Watts <Robin.Watts@artifex.com> | 2017-06-03 21:27:33 -0700 |
---|---|---|
committer | Robin Watts <Robin.Watts@artifex.com> | 2017-06-03 21:27:33 -0700 |
commit | 7f0a9b9f4448f7f2e87313e9e147b631b687e81b (patch) | |
tree | 5259a54b29e55d19fe65d75ac35cbb56022e591c | |
parent | 876f1fe8aaa9b110b3211fedbe5decbd67cf8c45 (diff) | |
download | mupdf-7f0a9b9f4448f7f2e87313e9e147b631b687e81b.tar.xz |
Tweak pdf_graft_map API.
Passing a pdf_document to pdf_graft_object to specify the source
document is redundant, as if we need to know the document, it will
be pickled into the object we are copying.
Similarly, repeatedly having to pass the destination document
seems silly when we can just pickle it into the map too (and this
removes the possibility of people using a different destination
document part way through).
This leaves to simplifying the pdf_graft_object call, at the expense
of splitting it into 2 calls - one with a map, and one without.
Also, we can delay the creation of the mapping table until we are
first asked to copy an object that requires deep copying. This
avoids us ever having to manually pass in the source document.
This has knock-on effects in the java and javascript classes, but
with the advantage of being clearer in the end (IMHO).
Conflicts:
include/mupdf/pdf/document.h
-rw-r--r-- | docs/manual-mutool-run.html | 10 | ||||
-rw-r--r-- | include/mupdf/pdf/document.h | 44 | ||||
-rw-r--r-- | platform/java/mupdf_native.c | 31 | ||||
-rw-r--r-- | platform/java/mupdf_native.h | 14 | ||||
-rw-r--r-- | platform/java/src/com/artifex/mupdf/fitz/PDFDocument.java | 2 | ||||
-rw-r--r-- | platform/java/src/com/artifex/mupdf/fitz/PDFGraftMap.java | 2 | ||||
-rw-r--r-- | source/pdf/pdf-graft.c | 150 | ||||
-rw-r--r-- | source/tools/murun.c | 30 | ||||
-rw-r--r-- | source/tools/pdfmerge.c | 4 |
9 files changed, 193 insertions, 94 deletions
diff --git a/docs/manual-mutool-run.html b/docs/manual-mutool-run.html index 596d11a2..59bb8cc1 100644 --- a/docs/manual-mutool-run.html +++ b/docs/manual-mutool-run.html @@ -678,11 +678,15 @@ The buffer must contain already compressed data that matches the Filter and Deco The following functions can be used to copy objects from one document to another: <dl> -<dt>PDFDocument#graftObject(sourceDocument, object, sourceGraftMap) -<dd>Deep copy an object into the destination document. The graft map may be null, but should be used if you -are copying several objects from the same source document using multiple calls to graftObject. +<dt>PDFDocument#graftObject(object) +<dd>Deep copy an object into the destination document. This function will not remember previously +copied objects. +If you are copying several objects from the same source document using multiple calls, you should +use a graft map instead. <dt>PDFDocument#newGraftMap() <dd>Create a graft map for the source document, so that objects that have already been copied can be found again. +<dt>PDFGraftMap#graftObject(object) +<dd>Use the graft map to copy objects, with the ability to remember previously copied objects. </dl> <p> diff --git a/include/mupdf/pdf/document.h b/include/mupdf/pdf/document.h index 68303f05..fd1d83e3 100644 --- a/include/mupdf/pdf/document.h +++ b/include/mupdf/pdf/document.h @@ -684,9 +684,49 @@ pdf_document *pdf_create_document(fz_context *ctx); */ typedef struct pdf_graft_map_s pdf_graft_map; -pdf_graft_map *pdf_new_graft_map(fz_context *ctx, pdf_document *src); +/* + pdf_graft_object: Return a deep copied object equivalent to the + supplied object, suitable for use within the given document. + + dst: The document in which the returned object is to be used. + + obj: The object deep copy. + + Note: If grafting multiple objects, you should use a pdf_graft_map + to avoid potential duplication of target objects. +*/ +pdf_obj *pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_obj *obj); + +/* + pdf_new_graft_map: Prepare a graft map object to allow objects + to be deep copied from one document to the given one, avoiding + problems with duplicated child objects. + + dst: The document to copy objects to. + + Note: all the source objects must come from the same document. +*/ +pdf_graft_map *pdf_new_graft_map(fz_context *ctx, pdf_document *dst); + +/* + pdf_drop_graft_map: Drop a graft map. +*/ void pdf_drop_graft_map(fz_context *ctx, pdf_graft_map *map); -pdf_obj *pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_document *src, pdf_obj *obj, pdf_graft_map *map); + +/* + pdf_graft_mapped_object: Return a deep copied object equivalent + to the supplied object, suitable for use within the target + document of the map. + + map: A map targeted at the document in which the returned + object is to be used. + + obj: The object deep copy. + + Note: Copying multiple objects via the same graft map ensures + that any shared child are not duplicated more than once. +*/ +pdf_obj *pdf_graft_mapped_object(fz_context *ctx, pdf_graft_map *map, pdf_obj *obj); /* pdf_page_write: Create a device that will record the diff --git a/platform/java/mupdf_native.c b/platform/java/mupdf_native.c index f485f4f5..a0a509bf 100644 --- a/platform/java/mupdf_native.c +++ b/platform/java/mupdf_native.c @@ -6396,19 +6396,17 @@ FUN(PDFDocument_newPDFGraftMap)(JNIEnv *env, jobject self) } JNIEXPORT jobject JNICALL -FUN(PDFDocument_graftObject)(JNIEnv *env, jobject self, jobject jsrc, jobject jobj, jobject jmap) +FUN(PDFDocument_graftObject)(JNIEnv *env, jobject self, jobject jobj) { fz_context *ctx = get_context(env); - pdf_document *dst = from_PDFDocument(env, self); - pdf_document *src = from_PDFDocument(env, jsrc); pdf_obj *obj = from_PDFObject(env, jobj); - pdf_graft_map *map = from_PDFGraftMap(env, jmap); + pdf_document *dst = from_PDFDocument(env, self); if (!ctx || !dst) return NULL; - if (!src) { jni_throw_arg(env, "source must not be null"); return NULL; } + if (!dst) { jni_throw_arg(env, "dst must not be null"); return NULL; } fz_try(ctx) - obj = pdf_graft_object(ctx, dst, src, obj, map); + obj = pdf_graft_object(ctx, dst, obj); fz_catch(ctx) { jni_rethrow(env, ctx); @@ -8101,6 +8099,27 @@ FUN(PDFGraftMap_finalize)(JNIEnv *env, jobject self) pdf_drop_graft_map(ctx, map); } +JNIEXPORT jobject JNICALL +FUN(PDFGraftMap_graftObject)(JNIEnv *env, jobject self, jobject jobj) +{ + fz_context *ctx = get_context(env); + pdf_obj *obj = from_PDFObject(env, jobj); + pdf_graft_map *map = from_PDFGraftMap(env, self); + + if (!ctx) return NULL; + if (!map) { jni_throw_arg(env, "map must not be null"); return NULL; } + + fz_try(ctx) + obj = pdf_graft_mapped_object(ctx, map, obj); + fz_catch(ctx) + { + jni_rethrow(env, ctx); + return NULL; + } + + return to_PDFObject_safe_own(ctx, env, self, obj); +} + /* PDFPage interface */ JNIEXPORT jobject JNICALL diff --git a/platform/java/mupdf_native.h b/platform/java/mupdf_native.h index 7641f32b..cdcebc50 100644 --- a/platform/java/mupdf_native.h +++ b/platform/java/mupdf_native.h @@ -1722,7 +1722,7 @@ JNIEXPORT void JNICALL Java_com_artifex_mupdf_fitz_PDFDocument_deleteObject /* * Class: com_artifex_mupdf_fitz_PDFDocument * Method: newPDFGraftMap - * Signature: ()Lcom/artifex/mupdf/fitz/PDFGraftMap; + * Signature: (Lcom/artifex/mupdf/fitz/PDFDocument)Lcom/artifex/mupdf/fitz/PDFGraftMap; */ JNIEXPORT jobject JNICALL Java_com_artifex_mupdf_fitz_PDFDocument_newPDFGraftMap (JNIEnv *, jobject); @@ -1730,10 +1730,10 @@ JNIEXPORT jobject JNICALL Java_com_artifex_mupdf_fitz_PDFDocument_newPDFGraftMap /* * Class: com_artifex_mupdf_fitz_PDFDocument * Method: graftObject - * Signature: (Lcom/artifex/mupdf/fitz/PDFDocument;Lcom/artifex/mupdf/fitz/PDFObject;Lcom/artifex/mupdf/fitz/PDFGraftMap;)Lcom/artifex/mupdf/fitz/PDFObject; + * Signature: (Lcom/artifex/mupdf/fitz/PDFDocument;Lcom/artifex/mupdf/fitz/PDFObject)Lcom/artifex/mupdf/fitz/PDFObject; */ JNIEXPORT jobject JNICALL Java_com_artifex_mupdf_fitz_PDFDocument_graftObject - (JNIEnv *, jobject, jobject, jobject, jobject); + (JNIEnv *, jobject, jobject); /* * Class: com_artifex_mupdf_fitz_PDFDocument @@ -1850,6 +1850,14 @@ extern "C" { JNIEXPORT void JNICALL Java_com_artifex_mupdf_fitz_PDFGraftMap_finalize (JNIEnv *, jobject); +/* + * Class: com_artifex_mupdf_fitz_PDFGraftMap + * Method: graftObject + * Signature: (Lcom/artifex/mupdf/fitz/PDFGraftMap;Lcom/artifex/mupdf/fitz/PDFObject;)Lcom/artifex/mupdf/fitz/PDFObject; + */ +JNIEXPORT jobject JNICALL Java_com_artifex_mupdf_fitz_PDFGraftMap_graftObject + (JNIEnv *, jobject, jobject, jobject); + #ifdef __cplusplus } #endif diff --git a/platform/java/src/com/artifex/mupdf/fitz/PDFDocument.java b/platform/java/src/com/artifex/mupdf/fitz/PDFDocument.java index a925ac90..5c0cc5ec 100644 --- a/platform/java/src/com/artifex/mupdf/fitz/PDFDocument.java +++ b/platform/java/src/com/artifex/mupdf/fitz/PDFDocument.java @@ -40,7 +40,7 @@ public class PDFDocument extends Document } public native PDFGraftMap newPDFGraftMap(); - public native PDFObject graftObject(PDFDocument src, PDFObject obj, PDFGraftMap map); + public native PDFObject graftObject(PDFObject obj); private native PDFObject addStreamBuffer(Buffer buf, Object obj, boolean compressed); private native PDFObject addStreamString(String str, Object obj, boolean compressed); diff --git a/platform/java/src/com/artifex/mupdf/fitz/PDFGraftMap.java b/platform/java/src/com/artifex/mupdf/fitz/PDFGraftMap.java index 5587ed2c..fedace4f 100644 --- a/platform/java/src/com/artifex/mupdf/fitz/PDFGraftMap.java +++ b/platform/java/src/com/artifex/mupdf/fitz/PDFGraftMap.java @@ -11,6 +11,8 @@ public class PDFGraftMap pointer = 0; } + public native PDFObject graftObject(PDFObject obj); + private PDFGraftMap(long p) { pointer = p; } diff --git a/source/pdf/pdf-graft.c b/source/pdf/pdf-graft.c index d2276ccc..d6c53676 100644 --- a/source/pdf/pdf-graft.c +++ b/source/pdf/pdf-graft.c @@ -6,27 +6,18 @@ struct pdf_graft_map_s int refs; int len; pdf_document *src; + pdf_document *dst; int *dst_from_src; }; pdf_graft_map * -pdf_new_graft_map(fz_context *ctx, pdf_document *src) +pdf_new_graft_map(fz_context *ctx, pdf_document *dst) { pdf_graft_map *map = NULL; map = fz_malloc_struct(ctx, pdf_graft_map); - fz_try(ctx) - { - map->src = (pdf_document*) fz_keep_document(ctx, (fz_document*)src); - map->len = pdf_xref_len(ctx, src); - map->dst_from_src = fz_calloc(ctx, map->len, sizeof(int)); - } - fz_catch(ctx) - { - fz_free(ctx, map); - fz_rethrow(ctx); - } + map->dst = pdf_keep_document(ctx, dst); map->refs = 1; return map; } @@ -42,7 +33,8 @@ pdf_drop_graft_map(fz_context *ctx, pdf_graft_map *map) { if (fz_drop_imp(ctx, map, &map->refs)) { - fz_drop_document(ctx, &map->src->super); + pdf_drop_document(ctx, map->src); + pdf_drop_document(ctx, map->dst); fz_free(ctx, map->dst_from_src); fz_free(ctx, map); } @@ -50,48 +42,77 @@ pdf_drop_graft_map(fz_context *ctx, pdf_graft_map *map) /* Graft object from dst to source */ pdf_obj * -pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_document *src, pdf_obj *obj_ref, pdf_graft_map *map) +pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_obj *obj) +{ + pdf_document *src; + pdf_graft_map *map; + + /* Primitive objects are not bound to a document, so can be re-used as is. */ + src = pdf_get_bound_document(ctx, obj); + if (src == NULL) + return pdf_keep_obj(ctx, obj); + + map = pdf_new_graft_map(ctx, dst); + + fz_try(ctx) + obj = pdf_graft_mapped_object(ctx, map, obj); + fz_always(ctx) + pdf_drop_graft_map(ctx, map); + fz_catch(ctx) + fz_rethrow(ctx); + + return obj; +} + +pdf_obj * +pdf_graft_mapped_object(fz_context *ctx, pdf_graft_map *map, pdf_obj *obj) { pdf_obj *val, *key; pdf_obj *new_obj = NULL; - pdf_obj *new_dict = NULL; - pdf_obj *new_array = NULL; + pdf_obj *new_dict; + pdf_obj *new_array; pdf_obj *ref = NULL; fz_buffer *buffer = NULL; - pdf_graft_map *drop_map = NULL; - pdf_document *bound; + pdf_document *src; int new_num, src_num, len, i; /* Primitive objects are not bound to a document, so can be re-used as is. */ - if (!pdf_is_indirect(ctx, obj_ref) && !pdf_is_dict(ctx, obj_ref) && !pdf_is_array(ctx, obj_ref)) - return pdf_keep_obj(ctx, obj_ref); - - if (map == NULL) - drop_map = map = pdf_new_graft_map(ctx, src); - else if (src != map->src) - fz_throw(ctx, FZ_ERROR_GENERIC, "graft map does not belong to the source document"); + src = pdf_get_bound_document(ctx, obj); + if (!src) + return pdf_keep_obj(ctx, obj); - bound = pdf_get_bound_document(ctx, obj_ref); - if (bound && bound != src) - fz_throw(ctx, FZ_ERROR_GENERIC, "grafted object does not belong to the source document"); + if (map->src && src != map->src) + fz_throw(ctx, FZ_ERROR_GENERIC, "grafted objects must all belong to the same source document"); - if (pdf_is_indirect(ctx, obj_ref)) + if (pdf_is_indirect(ctx, obj)) { - src_num = pdf_to_num(ctx, obj_ref); + src_num = pdf_to_num(ctx, obj); - if (src_num < 1 || src_num >= map->len) + if (map->src == NULL) { - pdf_drop_graft_map(ctx, drop_map); - fz_throw(ctx, FZ_ERROR_GENERIC, "source object number out of range"); + fz_try(ctx) + { + map->src = pdf_keep_document(ctx, src); + map->len = pdf_xref_len(ctx, src); + map->dst_from_src = fz_calloc(ctx, map->len, sizeof(int)); + } + fz_catch(ctx) + { + pdf_drop_document(ctx, map->src); + map->src = NULL; + fz_rethrow(ctx); + } } - /* Check if we have done this one. If yes, then drop map (if allocated) - * and return our indirect ref */ + if (src_num < 1 || src_num >= map->len) + fz_throw(ctx, FZ_ERROR_GENERIC, "source object number out of range"); + + /* Check if we have done this one. If yes, then just + * return our indirect ref */ if (map->dst_from_src[src_num] != 0) { int dest_num = map->dst_from_src[src_num]; - pdf_drop_graft_map(ctx, drop_map); - return pdf_new_indirect(ctx, dst, dest_num, 0); + return pdf_new_indirect(ctx, map->dst, dest_num, 0); } fz_var(buffer); @@ -101,25 +122,22 @@ pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_document *src, pdf_obj { /* Create new slot for our src object, set the mapping and call again * using the resolved indirect reference */ - new_num = pdf_create_object(ctx, dst); + new_num = pdf_create_object(ctx, map->dst); map->dst_from_src[src_num] = new_num; - new_obj = pdf_graft_object(ctx, dst, src, pdf_resolve_indirect(ctx, obj_ref), map); + new_obj = pdf_graft_mapped_object(ctx, map, pdf_resolve_indirect(ctx, obj)); /* Return a ref to the new_obj making sure to attach any stream */ - pdf_update_object(ctx, dst, new_num, new_obj); + pdf_update_object(ctx, map->dst, new_num, new_obj); pdf_drop_obj(ctx, new_obj); - ref = pdf_new_indirect(ctx, dst, new_num, 0); - if (pdf_is_stream(ctx, obj_ref)) + ref = pdf_new_indirect(ctx, map->dst, new_num, 0); + if (pdf_is_stream(ctx, obj)) { buffer = pdf_load_raw_stream_number(ctx, src, src_num); - pdf_update_stream(ctx, dst, ref, buffer, 1); + pdf_update_stream(ctx, map->dst, ref, buffer, 1); } } fz_always(ctx) - { fz_drop_buffer(ctx, buffer); - pdf_drop_graft_map(ctx, drop_map); - } fz_catch(ctx) { pdf_drop_obj(ctx, ref); @@ -127,26 +145,20 @@ pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_document *src, pdf_obj } return ref; } - else if (pdf_is_dict(ctx, obj_ref)) + else if (pdf_is_dict(ctx, obj)) { - fz_var(new_dict); + len = pdf_dict_len(ctx, obj); + new_dict = pdf_new_dict(ctx, map->dst, len); fz_try(ctx) { - len = pdf_dict_len(ctx, obj_ref); - new_dict = pdf_new_dict(ctx, dst, len); - for (i = 0; i < len; i++) { - key = pdf_dict_get_key(ctx, obj_ref, i); - val = pdf_dict_get_val(ctx, obj_ref, i); - pdf_dict_put_drop(ctx, new_dict, key, pdf_graft_object(ctx, dst, src, val, map)); + key = pdf_dict_get_key(ctx, obj, i); + val = pdf_dict_get_val(ctx, obj, i); + pdf_dict_put_drop(ctx, new_dict, key, pdf_graft_mapped_object(ctx, map, val)); } } - fz_always(ctx) - { - pdf_drop_graft_map(ctx, drop_map); - } fz_catch(ctx) { pdf_drop_obj(ctx, new_dict); @@ -154,26 +166,20 @@ pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_document *src, pdf_obj } return new_dict; } - else if (pdf_is_array(ctx, obj_ref)) + else if (pdf_is_array(ctx, obj)) { - fz_var(new_array); + /* Step through the array items handling indirect refs */ + len = pdf_array_len(ctx, obj); + new_array = pdf_new_array(ctx, map->dst, len); fz_try(ctx) { - /* Step through the array items handling indirect refs */ - len = pdf_array_len(ctx, obj_ref); - new_array = pdf_new_array(ctx, dst, len); - for (i = 0; i < len; i++) { - val = pdf_array_get(ctx, obj_ref, i); - pdf_array_push_drop(ctx, new_array, pdf_graft_object(ctx, dst, src, val, map)); + val = pdf_array_get(ctx, obj, i); + pdf_array_push_drop(ctx, new_array, pdf_graft_mapped_object(ctx, map, val)); } } - fz_always(ctx) - { - pdf_drop_graft_map(ctx, drop_map); - } fz_catch(ctx) { pdf_drop_obj(ctx, new_array); @@ -183,7 +189,7 @@ pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_document *src, pdf_obj } else { - pdf_drop_graft_map(ctx, drop_map); - return pdf_keep_obj(ctx, obj_ref);; + assert("This never happens" == NULL); + return NULL; } } diff --git a/source/tools/murun.c b/source/tools/murun.c index cbfd2a78..205e8f91 100644 --- a/source/tools/murun.c +++ b/source/tools/murun.c @@ -3425,11 +3425,21 @@ static void ffi_PDFDocument_graftObject(js_State *J) { fz_context *ctx = js_getcontext(J); pdf_document *dst = js_touserdata(J, 0, "pdf_document"); - pdf_document *src = js_touserdata(J, 1, "pdf_document"); - pdf_obj *obj = js_touserdata(J, 2, "pdf_obj"); - pdf_graft_map *map = js_iscoercible(J, 3) ? js_touserdata(J, 3, "pdf_graft_map") : NULL; + pdf_obj *obj = js_touserdata(J, 1, "pdf_obj"); fz_try(ctx) - obj = pdf_graft_object(ctx, dst, src, obj, map); + obj = pdf_graft_object(ctx, dst, obj); + fz_catch(ctx) + rethrow(J); + ffi_pushobj(J, obj); +} + +static void ffi_PDFGraftMap_graftObject(js_State *J) +{ + fz_context *ctx = js_getcontext(J); + pdf_graft_map *map = js_touserdata(J, 0, "pdf_graft_map"); + pdf_obj *obj = js_touserdata(J, 1, "pdf_obj"); + fz_try(ctx) + obj = pdf_graft_mapped_object(ctx, map, obj); fz_catch(ctx) rethrow(J); ffi_pushobj(J, obj); @@ -4493,10 +4503,17 @@ int murun_main(int argc, char **argv) jsB_propfun(J, "PDFDocument.newDictionary", ffi_PDFDocument_newDictionary, 1); jsB_propfun(J, "PDFDocument.newGraftMap", ffi_PDFDocument_newGraftMap, 0); - jsB_propfun(J, "PDFDocument.graftObject", ffi_PDFDocument_graftObject, 3); + jsB_propfun(J, "PDFDocument.graftObject", ffi_PDFDocument_graftObject, 1); } js_setregistry(J, "pdf_document"); + js_getregistry(J, "pdf_graft_map"); + js_newobjectx(J); + { + jsB_propfun(J, "PDFGraftMap.graftObject", ffi_PDFGraftMap_graftObject, 1); + } + js_setregistry(J, "pdf_graft_map"); + js_getregistry(J, "fz_page"); js_newobjectx(J); { @@ -4563,6 +4580,9 @@ int murun_main(int argc, char **argv) js_setregistry(J, "pdf_obj"); js_newobject(J); + { + jsB_propfun(J, "PDFGraftMap.graftObject", ffi_PDFGraftMap_graftObject, 1); + } js_setregistry(J, "pdf_graft_map"); #endif diff --git a/source/tools/pdfmerge.c b/source/tools/pdfmerge.c index 7e38f0e1..14551ecf 100644 --- a/source/tools/pdfmerge.c +++ b/source/tools/pdfmerge.c @@ -56,7 +56,7 @@ static void page_merge(int page_from, int page_to, pdf_graft_map *graft_map) { obj = pdf_dict_get(ctx, page_ref, copy_list[i]); if (obj != NULL) - pdf_dict_put_drop(ctx, page_dict, copy_list[i], pdf_graft_object(ctx, doc_des, doc_src, obj, graft_map)); + pdf_dict_put_drop(ctx, page_dict, copy_list[i], pdf_graft_mapped_object(ctx, graft_map, obj)); } /* Add the page object to the destination document. */ @@ -81,7 +81,7 @@ static void merge_range(const char *range) pdf_graft_map *graft_map; count = pdf_count_pages(ctx, doc_src); - graft_map = pdf_new_graft_map(ctx, doc_src); + graft_map = pdf_new_graft_map(ctx, doc_des); fz_try(ctx) { |