diff options
author | Michael Vrhel <michael.vrhel@artifex.com> | 2016-03-15 16:33:22 -0700 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2016-04-19 18:30:40 +0100 |
commit | 1bbde93ba39613877ded2015965aaab2341d3d36 (patch) | |
tree | f2a4936de895c6ddc40deb7bc93ccfb66de514d3 /source/pdf/pdf-graft.c | |
parent | 335798189cbd40cd518ce49d1fa4c7eaa2811977 (diff) | |
download | mupdf-1bbde93ba39613877ded2015965aaab2341d3d36.tar.xz |
Add mutool merge
This commit adds a page merging tool. The tool demonstrates the
use of object grafting. The object grafting function recursively
goes through the object to add all referenced objects. A map is
maintained to ensure that objects that have already been copied are
not copied again.
Diffstat (limited to 'source/pdf/pdf-graft.c')
-rw-r--r-- | source/pdf/pdf-graft.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/source/pdf/pdf-graft.c b/source/pdf/pdf-graft.c new file mode 100644 index 00000000..bbe5e17b --- /dev/null +++ b/source/pdf/pdf-graft.c @@ -0,0 +1,163 @@ +#include "mupdf/pdf.h" + +pdf_graft_map * +pdf_new_graft_map(fz_context *ctx, pdf_document *src) +{ + pdf_graft_map *map = NULL; + + map = fz_malloc_struct(ctx, pdf_graft_map); + + fz_try(ctx) + { + 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->refs = 1; + return map; +} + +pdf_graft_map * +fz_keep_graft_map(fz_context *ctx, pdf_graft_map *map) +{ + if (map) + ++map->refs; + return map; +} + +void +pdf_drop_graft_map(fz_context *ctx, pdf_graft_map *map) +{ + if (map && --map->refs == 0) + { + fz_free(ctx, map->dst_from_src); + fz_free(ctx, 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_obj *val, *key; + pdf_obj *new_obj = NULL; + pdf_obj *new_dict = NULL; + pdf_obj *new_array = NULL; + pdf_obj *ref = NULL; + fz_buffer *buffer = NULL; + pdf_graft_map *drop_map = NULL; + int new_num, src_num, len, i; + + if (map == NULL) + drop_map = map = pdf_new_graft_map(ctx, src); + + if (pdf_is_indirect(ctx, obj_ref)) + { + src_num = pdf_to_num(ctx, obj_ref); + + /* Check if we have done this one. If yes, then drop map (if allocated) + * and 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); + } + + fz_var(buffer); + fz_var(ref); + + fz_try(ctx) + { + /* 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); + map->dst_from_src[src_num] = new_num; + new_obj = pdf_graft_object(ctx, dst, src, pdf_resolve_indirect(ctx, obj_ref), map); + + /* Return a ref to the new_obj making sure to attach any stream */ + pdf_update_object(ctx, 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)) + { + buffer = pdf_load_raw_stream(ctx, src, src_num, 0); + pdf_update_stream(ctx, 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); + fz_rethrow(ctx); + } + return ref; + } + else if (pdf_is_dict(ctx, obj_ref)) + { + fz_var(new_dict); + + 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)); + } + } + fz_always(ctx) + { + pdf_drop_graft_map(ctx, drop_map); + } + fz_catch(ctx) + { + pdf_drop_obj(ctx, new_dict); + fz_rethrow(ctx); + } + return new_dict; + } + else if (pdf_is_array(ctx, obj_ref)) + { + fz_var(new_array); + + 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)); + } + } + fz_always(ctx) + { + pdf_drop_graft_map(ctx, drop_map); + } + fz_catch(ctx) + { + pdf_drop_obj(ctx, new_array); + fz_rethrow(ctx); + } + return new_array; + } + else + { + pdf_drop_graft_map(ctx, drop_map); + return pdf_keep_obj(ctx, obj_ref);; + } +} |