diff options
-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) { |