void pdf_delete_portfolio_schema(fz_context *ctx, pdf_document *doc, int entry) { pdf_portfolio **pp; pdf_portfolio *p; pdf_obj *s; if (!doc) fz_throw(ctx, FZ_ERROR_GENERIC, "Bad pdf_delete_portfolio_schema call"); if (doc->portfolio == NULL) load_portfolio(ctx, doc); pp = &doc->portfolio; while (*pp && entry > 0) pp = &(*pp)->next, entry--; p = *pp; if (p == NULL || entry) fz_throw(ctx, FZ_ERROR_GENERIC, "entry out of range in pdf_delete_portfolio_schema"); *pp = p->next; /* Delete the key from the schema */ s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Collection, PDF_NAME_Schema, NULL); pdf_dict_del(ctx, s, p->key); /* Delete this entry from all the collection entries */ s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Names, PDF_NAME_EmbeddedFiles, NULL); pdf_name_tree_map(ctx, s, delete_from_node, p->key); pdf_drop_obj(ctx, p->entry.name); pdf_drop_obj(ctx, p->key); pdf_drop_obj(ctx, p->val); fz_free(ctx, p); }
ErrorCode juggler_add_pages_from_file(juggler_t *dest, juggler_t *src, int dest_index) { pdf_obj *dest_pages = pdf_dict_getp(dest->ctx, pdf_trailer(dest->ctx, dest->pdf), "Root/Pages"); int dest_pages_index = pdf_array_len(dest->ctx, pdf_dict_gets(dest->ctx, dest_pages, "Kids")); /* be aware that this function does not change the two variables if the page index is greater than the number of pages */ find_destination_pages(dest->ctx, dest_pages, dest_index, &dest_pages, &dest_pages_index); pdf_obj *dest_kids = pdf_dict_gets(dest->ctx, dest_pages, "Kids"); if(!pdf_is_indirect(dest->ctx, dest_pages) || !pdf_is_dict(dest->ctx, dest_pages) || !pdf_is_array(dest->ctx, dest_kids)) { return(ERROR_INVALID_RANGE); } pdf_obj *pages_root = pdf_dict_getp(src->ctx, pdf_trailer(src->ctx, src->pdf), "Root/Pages"); if(!pdf_is_indirect(src->ctx, pages_root) || !pdf_is_dict(src->ctx, pages_root)) return(ERROR_NO_PAGES); /* if we copy the root pages-node and it's referenced objects, we will copy all pages and all objects those pages need */ pdf_obj *new_pages_ref = copy_object_single(dest->ctx, dest->pdf, src->ctx, src->pdf, pages_root); /* insert new pages-node */ pdf_array_insert_drop(dest->ctx, dest_kids, new_pages_ref, dest_pages_index); /* update the parent */ pdf_obj *new_pages_parent = pdf_new_indirect(dest->ctx, dest->pdf, pdf_to_num(dest->ctx, dest_pages), pdf_to_gen(dest->ctx, dest_pages)); pdf_dict_puts_drop(dest->ctx, new_pages_ref, "Parent", new_pages_parent); /* TODO: If dest_pages contains anything inheritable but not the new node we need to insert empty items to prevent this inerhitance */ /* update count */ int new_count = pdf_to_int(dest->ctx, pdf_dict_gets(dest->ctx, dest_pages, "Count")) + src->pagecount; pdf_dict_puts_drop(dest->ctx, dest_pages, "Count", pdf_new_int(dest->ctx, dest->pdf, new_count)); /* let MuPDF rebuild the page tree */ pdf_finish_edit(dest->ctx, dest->pdf); dest->pdf->page_count = new_count; /* update juggler's state */ juggler_page_tree_changed_due_to_insert(dest, dest_index, src->pagecount); return(NoError); }
pdf_obj * pdf_lookup_dest(pdf_document *xref, pdf_obj *needle) { fz_context *ctx = xref->ctx; pdf_obj *root = pdf_dict_gets(pdf_trailer(xref), "Root"); pdf_obj *dests = pdf_dict_gets(root, "Dests"); pdf_obj *names = pdf_dict_gets(root, "Names"); pdf_obj *dest = NULL; /* PDF 1.1 has destinations in a dictionary */ if (dests) { if (pdf_is_name(needle)) return pdf_dict_get(dests, needle); else return pdf_dict_gets(dests, pdf_to_str_buf(needle)); } /* PDF 1.2 has destinations in a name tree */ if (names && !dest) { pdf_obj *tree = pdf_dict_gets(names, "Dests"); return pdf_lookup_name_imp(ctx, tree, needle); } return NULL; }
static void load_portfolio(fz_context *ctx, pdf_document *doc) { pdf_obj *obj; int i, n; pdf_portfolio **pp; obj = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Collection, PDF_NAME_Schema, NULL); n = pdf_dict_len(ctx, obj); for (i = 0; i < n; i++) { pdf_obj *k = pdf_dict_get_key(ctx, obj, i); pdf_obj *v = pdf_dict_get_val(ctx, obj, i); int sort = pdf_to_int(ctx, pdf_dict_get(ctx, v, PDF_NAME_O)); pdf_obj *eo = pdf_dict_get(ctx, v, PDF_NAME_E); int editable = eo ? pdf_to_bool(ctx, eo) : 0; pdf_obj *vo = pdf_dict_get(ctx, v, PDF_NAME_V); int visible = vo ? pdf_to_bool(ctx, vo) : 1; char *subtype = pdf_to_name(ctx, pdf_dict_get(ctx, v, PDF_NAME_Subtype)); pdf_obj *name = pdf_dict_get(ctx, v, PDF_NAME_N); pdf_portfolio *p = fz_malloc_struct(ctx, pdf_portfolio); p->key = pdf_keep_obj(ctx, k); p->val = pdf_keep_obj(ctx, v); p->sort = sort; p->entry.visible = visible; p->entry.editable = editable; p->entry.name = pdf_keep_obj(ctx, name); if (!strcmp(subtype, "S")) p->entry.type = PDF_SCHEMA_TEXT; else if (!strcmp(subtype, "D")) p->entry.type = PDF_SCHEMA_DATE; else if (!strcmp(subtype, "N")) p->entry.type = PDF_SCHEMA_NUMBER; else if (!strcmp(subtype, "F")) p->entry.type = PDF_SCHEMA_FILENAME; else if (!strcmp(subtype, "Desc")) p->entry.type = PDF_SCHEMA_DESC; else if (!strcmp(subtype, "ModDate")) p->entry.type = PDF_SCHEMA_MODDATE; else if (!strcmp(subtype, "CreationDate")) p->entry.type = PDF_SCHEMA_CREATIONDATE; else if (!strcmp(subtype, "Size")) p->entry.type = PDF_SCHEMA_SIZE; else p->entry.type = PDF_SCHEMA_UNKNOWN; /* Now insert p */ pp = &doc->portfolio; while (*pp && (*pp)->sort <= p->sort) pp = &(*pp)->next; p->next = *pp; *pp = p; } }
pdf_obj * pdf_lookup_name(pdf_document *xref, char *which, pdf_obj *needle) { fz_context *ctx = xref->ctx; pdf_obj *root = pdf_dict_gets(pdf_trailer(xref), "Root"); pdf_obj *names = pdf_dict_gets(root, "Names"); pdf_obj *tree = pdf_dict_gets(names, which); return pdf_lookup_name_imp(ctx, tree, needle); }
int pdf_count_pages(pdf_document *doc) { if (doc->page_count == 0) { pdf_obj *count = pdf_dict_getp(pdf_trailer(doc), "Root/Pages/Count"); doc->page_count = pdf_to_int(count); } return doc->page_count; }
pdf_obj * pdf_lookup_page_loc(pdf_document *doc, int needle, pdf_obj **parentp, int *indexp) { pdf_obj *root = pdf_dict_gets(pdf_trailer(doc), "Root"); pdf_obj *node = pdf_dict_gets(root, "Pages"); int skip = needle; pdf_obj *hit = pdf_lookup_page_loc_imp(doc, node, &skip, parentp, indexp); if (!hit) fz_throw(doc->ctx, FZ_ERROR_GENERIC, "cannot find page %d in page tree", needle); return hit; }
fz_outline * pdf_load_outline(fz_context *ctx, pdf_document *doc) { pdf_obj *root, *obj, *first; root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root); obj = pdf_dict_get(ctx, root, PDF_NAME_Outlines); first = pdf_dict_get(ctx, obj, PDF_NAME_First); if (first) return pdf_load_outline_imp(ctx, doc, first); return NULL; }
static void showglobalinfo(void) { pdf_obj *obj; printf("\nPDF-%d.%d\n", doc->version / 10, doc->version % 10); obj = pdf_dict_gets(pdf_trailer(doc), "Info"); if (obj) { printf("Info object (%d %d R):\n", pdf_to_num(obj), pdf_to_gen(obj)); pdf_fprint_obj(stdout, pdf_resolve_indirect(obj), 0); } obj = pdf_dict_gets(pdf_trailer(doc), "Encrypt"); if (obj) { printf("\nEncryption object (%d %d R):\n", pdf_to_num(obj), pdf_to_gen(obj)); pdf_fprint_obj(stdout, pdf_resolve_indirect(obj), 0); } printf("\nPages: %d\n\n", pagecount); }
pdf_obj * pdf_load_name_tree(pdf_document *xref, char *which) { fz_context *ctx = xref->ctx; pdf_obj *root = pdf_dict_gets(pdf_trailer(xref), "Root"); pdf_obj *names = pdf_dict_gets(root, "Names"); pdf_obj *tree = pdf_dict_gets(names, which); if (pdf_is_dict(tree)) { pdf_obj *dict = pdf_new_dict(ctx, 100); pdf_load_name_tree_imp(dict, xref, tree); return dict; } return NULL; }
DocumentInfo j_mu_get_doc_info(void* p_ctx, void* p_doc) { fz_context* ctx = (fz_context*) p_ctx; pdf_document* doc = (pdf_document*)p_doc; pdf_obj* info = pdf_dict_gets(ctx, pdf_trailer(ctx, doc), "Info"); DocumentInfo doc_info; if (info) { doc_info.author = get_prop_str(ctx, info, "Author"); doc_info.creator = get_prop_str(ctx, info, "Creator"); doc_info.creation_date = get_prop_str(ctx, info, "CreationDate"); doc_info.producer = get_prop_str(ctx, info, "Producer"); doc_info.title = get_prop_str(ctx, info, "Title"); } return doc_info; }
/* pdf_count_portfolio_entries: Get the number of portfolio entries in this document. doc: The document in question. */ int pdf_count_portfolio_entries(fz_context *ctx, pdf_document *doc) { pdf_obj *s; int count; if (!doc) return 0; if (doc->portfolio == NULL) load_portfolio(ctx, doc); s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Names, PDF_NAME_EmbeddedFiles, NULL); count = 0; pdf_name_tree_map(ctx, s, count_nodes, &count); return count; }
pdfout_data * pdfout_page_labels_get (fz_context *ctx, pdf_document *doc) { pdf_obj *trailer = pdf_trailer (ctx, doc); pdf_obj *labels_obj = pdf_dict_getp (ctx, trailer, "Root/PageLabels"); pdf_obj *array = pdf_dict_gets (ctx, labels_obj, "Nums"); if (array && pdf_is_array (ctx, array) == false) pdfout_throw (ctx, "Nums is not an array"); int length = pdf_array_len (ctx, array); pdfout_data *labels = pdfout_data_array_new (ctx); for (int i = 0; i < length / 2; ++i) { pdf_obj *object = pdf_array_get (ctx, array, 2 * i); if (pdf_is_int (ctx, object) == false) pdfout_throw (ctx, "key in number tree not an int"); pdfout_data *hash = pdfout_data_hash_new (ctx); int page = pdf_to_int (ctx, object); if (page < 0) pdfout_throw (ctx, "key in number tree is < 0"); push_int_key (ctx, hash, "page", page); pdf_obj *dict = pdf_array_get (ctx, array, 2 * i + 1); if (pdf_is_dict (ctx, dict) == false) pdfout_throw (ctx, "value in number tree not a dict"); parse_dict (ctx, dict, hash); pdfout_data_array_push (ctx, labels, hash); } return labels; }
fz_outline * pdf_load_outline(fz_context *ctx, pdf_document *doc) { pdf_obj *root, *obj, *first; fz_outline *outline = NULL; pdf_load_page_tree(ctx, doc); /* cache page tree for fast link destination lookups */ fz_try(ctx) { root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root); obj = pdf_dict_get(ctx, root, PDF_NAME_Outlines); first = pdf_dict_get(ctx, obj, PDF_NAME_First); if (first) outline = pdf_load_outline_imp(ctx, doc, first); } fz_always(ctx) pdf_drop_page_tree(ctx, doc); fz_catch(ctx) fz_rethrow(ctx); return outline; }
void pdfout_page_labels_set (fz_context *ctx, pdf_document *doc, pdfout_data *labels) { if (labels) check_page_labels (ctx, labels); pdf_obj *root = pdf_dict_get (ctx, pdf_trailer (ctx, doc), PDF_NAME_Root); if (root == NULL) pdfout_throw (ctx, "no document catalog, cannot set/unset page labels"); if (labels == NULL) { /* Remove page labels. */ pdf_dict_dels (ctx, root, "PageLabels"); return; } int num = pdfout_data_array_len (ctx, labels); pdf_obj *array_obj = pdf_new_array (ctx, doc, 2 * num); for (int i = 0; i < num; ++i) { pdfout_data *hash = pdfout_data_array_get (ctx, labels, i); int page; pdf_obj *dict_obj = hash_to_pdf_dict (ctx, doc, hash, &page); pdf_obj *page_obj = pdf_new_int (ctx, doc, page); pdf_array_push_drop (ctx, array_obj, page_obj); pdf_array_push_drop (ctx, array_obj, dict_obj); } pdf_obj *labels_obj = pdf_new_dict (ctx, doc, 1); pdf_dict_puts_drop (ctx, labels_obj, "Nums", array_obj); pdf_dict_puts_drop (ctx, root, "PageLabels", labels_obj); }
/* pdf_portfolio_entry_info: Fetch information about a given portfolio entry. doc: The document in question. entry: A value in the 0..n-1 range, where n is the value returned from pdf_count_portfolio. Returns pdf_object representing this entry. This reference is borrowed, so call pdf_keep_obj on it if you wish to keep it. */ pdf_obj *pdf_portfolio_entry_obj_name(fz_context *ctx, pdf_document *doc, int entry, pdf_obj **name) { struct find_data data; pdf_obj *s; if (name) *name = NULL; if (!doc) return NULL; if (doc->portfolio == NULL) load_portfolio(ctx, doc); s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Names, PDF_NAME_EmbeddedFiles, NULL); data.count = entry; data.key = NULL; data.val = NULL; pdf_name_tree_map(ctx, s, find_entry, &data); if (name) *name = data.key; return data.val; }
void pdf_insert_page(pdf_document *doc, pdf_page *page, int at) { fz_context *ctx = doc->ctx; int count = pdf_count_pages(doc); pdf_obj *parent, *kids; pdf_obj *page_ref; int i; page_ref = pdf_new_ref(doc, page->me); fz_try(ctx) { if (count == 0) { pdf_obj *root = pdf_dict_gets(pdf_trailer(doc), "Root"); parent = pdf_dict_gets(root, "Pages"); if (!parent) fz_throw(doc->ctx, FZ_ERROR_GENERIC, "cannot find page tree"); kids = pdf_dict_gets(parent, "Kids"); if (!kids) fz_throw(doc->ctx, FZ_ERROR_GENERIC, "malformed page tree"); pdf_array_insert(kids, page_ref, 0); } else if (at >= count) { if (at == INT_MAX) at = count; if (at > count) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot insert page beyond end of page tree"); /* append after last page */ pdf_lookup_page_loc(doc, count - 1, &parent, &i); kids = pdf_dict_gets(parent, "Kids"); pdf_array_insert(kids, page_ref, i + 1); } else { /* insert before found page */ pdf_lookup_page_loc(doc, at, &parent, &i); kids = pdf_dict_gets(parent, "Kids"); pdf_array_insert(kids, page_ref, i); } pdf_dict_puts(page->me, "Parent", parent); /* Adjust page counts */ while (parent) { int count = pdf_to_int(pdf_dict_gets(parent, "Count")); pdf_dict_puts_drop(parent, "Count", pdf_new_int(doc, count + 1)); parent = pdf_dict_gets(parent, "Parent"); } } fz_always(ctx) { pdf_drop_obj(page_ref); } fz_catch(ctx) { fz_rethrow(ctx); } doc->page_count = 0; /* invalidate cached value */ }
static void retainpages(fz_context *ctx, globals *glo, int argc, char **argv) { pdf_obj *oldroot, *root, *pages, *kids, *countobj, *parent, *olddests; pdf_document *doc = glo->doc; int argidx = 0; pdf_obj *names_list = NULL; int pagecount; int i; /* Keep only pages/type and (reduced) dest entries to avoid * references to unretained pages */ oldroot = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root); pages = pdf_dict_get(ctx, oldroot, PDF_NAME_Pages); olddests = pdf_load_name_tree(ctx, doc, PDF_NAME_Dests); root = pdf_new_dict(ctx, doc, 2); pdf_dict_put(ctx, root, PDF_NAME_Type, pdf_dict_get(ctx, oldroot, PDF_NAME_Type)); pdf_dict_put(ctx, root, PDF_NAME_Pages, pdf_dict_get(ctx, oldroot, PDF_NAME_Pages)); pdf_update_object(ctx, doc, pdf_to_num(ctx, oldroot), root); pdf_drop_obj(ctx, root); /* Create a new kids array with only the pages we want to keep */ parent = pdf_new_indirect(ctx, doc, pdf_to_num(ctx, pages), pdf_to_gen(ctx, pages)); kids = pdf_new_array(ctx, doc, 1); /* Retain pages specified */ while (argc - argidx) { int page, spage, epage; char *spec, *dash; char *pagelist = argv[argidx]; pagecount = pdf_count_pages(ctx, doc); spec = fz_strsep(&pagelist, ","); while (spec) { dash = strchr(spec, '-'); if (dash == spec) spage = epage = pagecount; else spage = epage = atoi(spec); if (dash) { if (strlen(dash) > 1) epage = atoi(dash + 1); else epage = pagecount; } spage = fz_clampi(spage, 1, pagecount); epage = fz_clampi(epage, 1, pagecount); if (spage < epage) for (page = spage; page <= epage; ++page) retainpage(ctx, doc, parent, kids, page); else for (page = spage; page >= epage; --page) retainpage(ctx, doc, parent, kids, page); spec = fz_strsep(&pagelist, ","); } argidx++; } pdf_drop_obj(ctx, parent); /* Update page count and kids array */ countobj = pdf_new_int(ctx, doc, pdf_array_len(ctx, kids)); pdf_dict_put(ctx, pages, PDF_NAME_Count, countobj); pdf_drop_obj(ctx, countobj); pdf_dict_put(ctx, pages, PDF_NAME_Kids, kids); pdf_drop_obj(ctx, kids); /* Also preserve the (partial) Dests name tree */ if (olddests) { pdf_obj *names = pdf_new_dict(ctx, doc, 1); pdf_obj *dests = pdf_new_dict(ctx, doc, 1); int len = pdf_dict_len(ctx, olddests); names_list = pdf_new_array(ctx, doc, 32); for (i = 0; i < len; i++) { pdf_obj *key = pdf_dict_get_key(ctx, olddests, i); pdf_obj *val = pdf_dict_get_val(ctx, olddests, i); pdf_obj *dest = pdf_dict_get(ctx, val, PDF_NAME_D); dest = pdf_array_get(ctx, dest ? dest : val, 0); if (pdf_array_contains(ctx, pdf_dict_get(ctx, pages, PDF_NAME_Kids), dest)) { pdf_obj *key_str = pdf_new_string(ctx, doc, pdf_to_name(ctx, key), strlen(pdf_to_name(ctx, key))); pdf_array_push(ctx, names_list, key_str); pdf_array_push(ctx, names_list, val); pdf_drop_obj(ctx, key_str); } } root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root); pdf_dict_put(ctx, dests, PDF_NAME_Names, names_list); pdf_dict_put(ctx, names, PDF_NAME_Dests, dests); pdf_dict_put(ctx, root, PDF_NAME_Names, names); pdf_drop_obj(ctx, names); pdf_drop_obj(ctx, dests); pdf_drop_obj(ctx, names_list); pdf_drop_obj(ctx, olddests); } /* Force the next call to pdf_count_pages to recount */ glo->doc->page_count = 0; /* Edit each pages /Annot list to remove any links that point to * nowhere. */ pagecount = pdf_count_pages(ctx, doc); for (i = 0; i < pagecount; i++) { pdf_obj *pageref = pdf_lookup_page_obj(ctx, doc, i); pdf_obj *pageobj = pdf_resolve_indirect(ctx, pageref); pdf_obj *annots = pdf_dict_get(ctx, pageobj, PDF_NAME_Annots); int len = pdf_array_len(ctx, annots); int j; for (j = 0; j < len; j++) { pdf_obj *o = pdf_array_get(ctx, annots, j); pdf_obj *p; if (!pdf_name_eq(ctx, pdf_dict_get(ctx, o, PDF_NAME_Subtype), PDF_NAME_Link)) continue; p = pdf_dict_get(ctx, o, PDF_NAME_A); if (!pdf_name_eq(ctx, pdf_dict_get(ctx, p, PDF_NAME_S), PDF_NAME_GoTo)) continue; if (string_in_names_list(ctx, pdf_dict_get(ctx, p, PDF_NAME_D), names_list)) continue; /* FIXME: Should probably look at Next too */ /* Remove this annotation */ pdf_array_delete(ctx, annots, j); j--; } } }
static void decimatepages(pdf_document *xref) { pdf_obj *oldroot, *root, *pages, *kids, *parent; fz_context *ctx = xref->ctx; int num_pages = pdf_count_pages(xref); int page, kidcount; /* Keep only pages/type and (reduced) dest entries to avoid * references to unretained pages */ oldroot = pdf_dict_gets(pdf_trailer(xref), "Root"); pages = pdf_dict_gets(oldroot, "Pages"); root = pdf_new_dict(ctx, 2); pdf_dict_puts(root, "Type", pdf_dict_gets(oldroot, "Type")); pdf_dict_puts(root, "Pages", pdf_dict_gets(oldroot, "Pages")); pdf_update_object(xref, pdf_to_num(oldroot), root); pdf_drop_obj(root); /* Create a new kids array with only the pages we want to keep */ parent = pdf_new_indirect(ctx, pdf_to_num(pages), pdf_to_gen(pages), xref); kids = pdf_new_array(ctx, 1); kidcount = 0; for (page=0; page < num_pages; page++) { pdf_page *page_details = pdf_load_page(xref, page); int xf = x_factor, yf = y_factor; int x, y; float w = page_details->mediabox.x1 - page_details->mediabox.x0; float h = page_details->mediabox.y1 - page_details->mediabox.y0; if (xf == 0 && yf == 0) { /* Nothing specified, so split along the long edge */ if (w > h) xf = 2, yf = 1; else xf = 1, yf = 2; } else if (xf == 0) xf = 1; else if (yf == 0) yf = 1; for (y = yf-1; y >= 0; y--) { for (x = 0; x < xf; x++) { pdf_obj *newpageobj, *newpageref, *newmediabox; fz_rect mb; int num; newpageobj = pdf_copy_dict(ctx, xref->page_objs[page]); num = pdf_create_object(xref); pdf_update_object(xref, num, newpageobj); newpageref = pdf_new_indirect(ctx, num, 0, xref); newmediabox = pdf_new_array(ctx, 4); mb.x0 = page_details->mediabox.x0 + (w/xf)*x; if (x == xf-1) mb.x1 = page_details->mediabox.x1; else mb.x1 = page_details->mediabox.x0 + (w/xf)*(x+1); mb.y0 = page_details->mediabox.y0 + (h/yf)*y; if (y == yf-1) mb.y1 = page_details->mediabox.y1; else mb.y1 = page_details->mediabox.y0 + (h/yf)*(y+1); pdf_array_push(newmediabox, pdf_new_real(ctx, mb.x0)); pdf_array_push(newmediabox, pdf_new_real(ctx, mb.y0)); pdf_array_push(newmediabox, pdf_new_real(ctx, mb.x1)); pdf_array_push(newmediabox, pdf_new_real(ctx, mb.y1)); pdf_dict_puts(newpageobj, "Parent", parent); pdf_dict_puts(newpageobj, "MediaBox", newmediabox); /* Store page object in new kids array */ pdf_array_push(kids, newpageref); kidcount++; } } } pdf_drop_obj(parent); /* Update page count and kids array */ pdf_dict_puts(pages, "Count", pdf_new_int(ctx, kidcount)); pdf_dict_puts(pages, "Kids", kids); pdf_drop_obj(kids); }
int pdf_add_portfolio_entry(fz_context *ctx, pdf_document *doc, const char *name, int name_len, const char *desc, int desc_len, const char *filename, int filename_len, const char *unifile, int unifile_len, fz_buffer *buf) { int entry, len; pdf_obj *ef, *f, *params, *s; pdf_obj *key; pdf_obj *val = NULL; fz_var(val); if (!doc) fz_throw(ctx, FZ_ERROR_GENERIC, "Bad pdf_add_portfolio_entry call"); if (doc->portfolio == NULL) load_portfolio(ctx, doc); key = pdf_new_string(ctx, doc, name, name_len); fz_try(ctx) { val = pdf_new_dict(ctx, doc, 6); pdf_dict_put_drop(ctx, val, PDF_NAME_CI, pdf_new_dict(ctx, doc, 4)); pdf_dict_put_drop(ctx, val, PDF_NAME_EF, (ef = pdf_new_dict(ctx, doc, 4))); pdf_dict_put_drop(ctx, val, PDF_NAME_F, pdf_new_string(ctx, doc, filename, filename_len)); pdf_dict_put_drop(ctx, val, PDF_NAME_UF, pdf_new_string(ctx, doc, unifile, unifile_len)); pdf_dict_put_drop(ctx, val, PDF_NAME_Desc, pdf_new_string(ctx, doc, desc, desc_len)); pdf_dict_put_drop(ctx, val, PDF_NAME_Type, PDF_NAME_Filespec); pdf_dict_put_drop(ctx, ef, PDF_NAME_F, (f = pdf_add_stream(ctx, doc, buf, NULL, 0))); len = fz_buffer_storage(ctx, buf, NULL); pdf_dict_put_drop(ctx, f, PDF_NAME_DL, pdf_new_int(ctx, doc, len)); pdf_dict_put_drop(ctx, f, PDF_NAME_Length, pdf_new_int(ctx, doc, len)); pdf_dict_put_drop(ctx, f, PDF_NAME_Params, (params = pdf_new_dict(ctx, doc, 4))); pdf_dict_put_drop(ctx, params, PDF_NAME_Size, pdf_new_int(ctx, doc, len)); s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Collection, NULL); if (s == NULL) { s = pdf_new_dict(ctx, doc, 4); pdf_dict_putl_drop(ctx, pdf_trailer(ctx, doc), s, PDF_NAME_Root, PDF_NAME_Collection, NULL); } s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Names, PDF_NAME_EmbeddedFiles, NULL); if (s == NULL) { s = pdf_new_dict(ctx, doc, 4); pdf_dict_putl_drop(ctx, pdf_trailer(ctx, doc), s, PDF_NAME_Root, PDF_NAME_Names, PDF_NAME_EmbeddedFiles, NULL); } entry = pdf_name_tree_insert(ctx, doc, s, key, val); } fz_always(ctx) { pdf_drop_obj(ctx, key); pdf_drop_obj(ctx, val); } fz_catch(ctx) fz_rethrow(ctx); return entry; }
void pdf_add_portfolio_schema(fz_context *ctx, pdf_document *doc, int entry, const pdf_portfolio_schema *info) { pdf_portfolio **pp; pdf_portfolio *p; pdf_obj *s; pdf_obj *sc; int num; char str_name[32]; pdf_obj *num_name = NULL; if (!doc) fz_throw(ctx, FZ_ERROR_GENERIC, "Bad pdf_add_portfolio_schema call"); if (doc->portfolio == NULL) load_portfolio(ctx, doc); fz_var(num_name); pp = &doc->portfolio; while (*pp && entry > 0) pp = &(*pp)->next, entry--; fz_try(ctx) { /* Find a name for the new schema entry */ num = 0; do { pdf_drop_obj(ctx, num_name); num_name = NULL; num++; sprintf(str_name, "%d", num); num_name = pdf_new_name(ctx, doc, str_name); p = doc->portfolio; for (p = doc->portfolio; p; p = p->next) if (pdf_name_eq(ctx, num_name, p->key)) break; } while (p); sc = pdf_new_dict(ctx, doc, 4); pdf_dict_put_drop(ctx, sc, PDF_NAME_E, pdf_new_bool(ctx, doc, !!info->editable)); pdf_dict_put_drop(ctx, sc, PDF_NAME_V, pdf_new_bool(ctx, doc, !!info->visible)); pdf_dict_put_drop(ctx, sc, PDF_NAME_N, info->name); pdf_dict_put(ctx, sc, PDF_NAME_Subtype, PDF_NAME_S); /* Add to our linked list (in the correct sorted place) */ p = fz_malloc_struct(ctx, pdf_portfolio); p->entry = *info; p->sort = 0; /* Will be rewritten in a mo */ p->key = pdf_keep_obj(ctx, num_name); p->val = pdf_keep_obj(ctx, sc); p->next = *pp; *pp = p; /* Add the key to the schema */ s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Collection, PDF_NAME_Schema, NULL); pdf_dict_put(ctx, s, num_name, sc); /* Renumber the schema entries */ for (num = 0, p = doc->portfolio; p; num++, p = p->next) { pdf_dict_put_drop(ctx, p->val, PDF_NAME_O, pdf_new_int(ctx, doc, num)); p->sort = num; } } fz_always(ctx) pdf_drop_obj(ctx, num_name); fz_catch(ctx) fz_rethrow(ctx); }
char * pdf_parse_link_action(fz_context *ctx, pdf_document *doc, pdf_obj *action, int pagenum) { pdf_obj *obj, *dest, *file_spec; if (!action) return NULL; obj = pdf_dict_get(ctx, action, PDF_NAME_S); if (pdf_name_eq(ctx, PDF_NAME_GoTo, obj)) { dest = pdf_dict_get(ctx, action, PDF_NAME_D); return pdf_parse_link_dest(ctx, doc, dest); } else if (pdf_name_eq(ctx, PDF_NAME_URI, obj)) { /* URI entries are ASCII strings */ const char *uri = pdf_to_str_buf(ctx, pdf_dict_get(ctx, action, PDF_NAME_URI)); if (!fz_is_external_link(ctx, uri)) { pdf_obj *uri_base_obj = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/URI/Base"); const char *uri_base = uri_base_obj ? pdf_to_str_buf(ctx, uri_base_obj) : "file://"; char *new_uri = fz_malloc(ctx, strlen(uri_base) + strlen(uri) + 1); strcpy(new_uri, uri_base); strcat(new_uri, uri); return new_uri; } return fz_strdup(ctx, uri); } else if (pdf_name_eq(ctx, PDF_NAME_Launch, obj)) { file_spec = pdf_dict_get(ctx, action, PDF_NAME_F); return pdf_parse_file_spec(ctx, doc, file_spec, NULL); } else if (pdf_name_eq(ctx, PDF_NAME_GoToR, obj)) { dest = pdf_dict_get(ctx, action, PDF_NAME_D); file_spec = pdf_dict_get(ctx, action, PDF_NAME_F); return pdf_parse_file_spec(ctx, doc, file_spec, dest); } else if (pdf_name_eq(ctx, PDF_NAME_Named, obj)) { dest = pdf_dict_get(ctx, action, PDF_NAME_N); if (pdf_name_eq(ctx, PDF_NAME_FirstPage, dest)) pagenum = 0; else if (pdf_name_eq(ctx, PDF_NAME_LastPage, dest)) pagenum = pdf_count_pages(ctx, doc) - 1; else if (pdf_name_eq(ctx, PDF_NAME_PrevPage, dest) && pagenum >= 0) { if (pagenum > 0) pagenum--; } else if (pdf_name_eq(ctx, PDF_NAME_NextPage, dest) && pagenum >= 0) { if (pagenum < pdf_count_pages(ctx, doc) - 1) pagenum++; } else return NULL; return fz_asprintf(ctx, "#%d", pagenum + 1); } return NULL; }
static void retainpages(fz_context *ctx, globals *glo, int argc, char **argv) { pdf_obj *oldroot, *root, *pages, *kids, *countobj, *parent, *olddests; pdf_document *doc = glo->doc; int argidx = 0; pdf_obj *names_list = NULL; pdf_obj *outlines; int pagecount; int i; int *page_object_nums; /* Keep only pages/type and (reduced) dest entries to avoid * references to unretained pages */ oldroot = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root); pages = pdf_dict_get(ctx, oldroot, PDF_NAME_Pages); olddests = pdf_load_name_tree(ctx, doc, PDF_NAME_Dests); outlines = pdf_dict_get(ctx, oldroot, PDF_NAME_Outlines); root = pdf_new_dict(ctx, doc, 3); pdf_dict_put(ctx, root, PDF_NAME_Type, pdf_dict_get(ctx, oldroot, PDF_NAME_Type)); pdf_dict_put(ctx, root, PDF_NAME_Pages, pdf_dict_get(ctx, oldroot, PDF_NAME_Pages)); pdf_dict_put(ctx, root, PDF_NAME_Outlines, outlines); pdf_update_object(ctx, doc, pdf_to_num(ctx, oldroot), root); /* Create a new kids array with only the pages we want to keep */ parent = pdf_new_indirect(ctx, doc, pdf_to_num(ctx, pages), pdf_to_gen(ctx, pages)); kids = pdf_new_array(ctx, doc, 1); /* Retain pages specified */ while (argc - argidx) { int page, spage, epage; char *spec, *dash; char *pagelist = argv[argidx]; pagecount = pdf_count_pages(ctx, doc); spec = fz_strsep(&pagelist, ","); while (spec) { dash = strchr(spec, '-'); if (dash == spec) spage = epage = pagecount; else spage = epage = atoi(spec); if (dash) { if (strlen(dash) > 1) epage = atoi(dash + 1); else epage = pagecount; } spage = fz_clampi(spage, 1, pagecount); epage = fz_clampi(epage, 1, pagecount); if (spage < epage) for (page = spage; page <= epage; ++page) retainpage(ctx, doc, parent, kids, page); else for (page = spage; page >= epage; --page) retainpage(ctx, doc, parent, kids, page); spec = fz_strsep(&pagelist, ","); } argidx++; } pdf_drop_obj(ctx, parent); /* Update page count and kids array */ countobj = pdf_new_int(ctx, doc, pdf_array_len(ctx, kids)); pdf_dict_put(ctx, pages, PDF_NAME_Count, countobj); pdf_drop_obj(ctx, countobj); pdf_dict_put(ctx, pages, PDF_NAME_Kids, kids); pdf_drop_obj(ctx, kids); /* Force the next call to pdf_count_pages to recount */ glo->doc->page_count = 0; pagecount = pdf_count_pages(ctx, doc); page_object_nums = fz_calloc(ctx, pagecount, sizeof(*page_object_nums)); for (i = 0; i < pagecount; i++) { pdf_obj *pageref = pdf_lookup_page_obj(ctx, doc, i); page_object_nums[i] = pdf_to_num(ctx, pageref); } /* If we had an old Dests tree (now reformed as an olddests * dictionary), keep any entries in there that point to * valid pages. This may mean we keep more than we need, but * it's safe at least. */ if (olddests) { pdf_obj *names = pdf_new_dict(ctx, doc, 1); pdf_obj *dests = pdf_new_dict(ctx, doc, 1); int len = pdf_dict_len(ctx, olddests); names_list = pdf_new_array(ctx, doc, 32); for (i = 0; i < len; i++) { pdf_obj *key = pdf_dict_get_key(ctx, olddests, i); pdf_obj *val = pdf_dict_get_val(ctx, olddests, i); pdf_obj *dest = pdf_dict_get(ctx, val, PDF_NAME_D); dest = pdf_array_get(ctx, dest ? dest : val, 0); if (dest_is_valid_page(ctx, dest, page_object_nums, pagecount)) { pdf_obj *key_str = pdf_new_string(ctx, doc, pdf_to_name(ctx, key), strlen(pdf_to_name(ctx, key))); pdf_array_push(ctx, names_list, key_str); pdf_array_push(ctx, names_list, val); pdf_drop_obj(ctx, key_str); } } pdf_dict_put(ctx, dests, PDF_NAME_Names, names_list); pdf_dict_put(ctx, names, PDF_NAME_Dests, dests); pdf_dict_put(ctx, root, PDF_NAME_Names, names); pdf_drop_obj(ctx, names); pdf_drop_obj(ctx, dests); pdf_drop_obj(ctx, olddests); } /* Edit each pages /Annot list to remove any links that point to * nowhere. */ for (i = 0; i < pagecount; i++) { pdf_obj *pageref = pdf_lookup_page_obj(ctx, doc, i); pdf_obj *pageobj = pdf_resolve_indirect(ctx, pageref); pdf_obj *annots = pdf_dict_get(ctx, pageobj, PDF_NAME_Annots); int len = pdf_array_len(ctx, annots); int j; for (j = 0; j < len; j++) { pdf_obj *o = pdf_array_get(ctx, annots, j); if (!pdf_name_eq(ctx, pdf_dict_get(ctx, o, PDF_NAME_Subtype), PDF_NAME_Link)) continue; if (!dest_is_valid(ctx, o, pagecount, page_object_nums, names_list)) { /* Remove this annotation */ pdf_array_delete(ctx, annots, j); j--; } } } if (strip_outlines(ctx, doc, outlines, pagecount, page_object_nums, names_list) == 0) { pdf_dict_del(ctx, root, PDF_NAME_Outlines); } fz_free(ctx, page_object_nums); pdf_drop_obj(ctx, names_list); pdf_drop_obj(ctx, root); }
/* When resetting or submitting a form, the fields to act upon are defined by an array of either field references or field names, plus a flag determining whether to act upon the fields in the array, or all fields other than those in the array. specified_fields interprets this information and produces the array of fields to be acted upon. */ static pdf_obj *specified_fields(pdf_document *doc, pdf_obj *fields, int exclude) { fz_context *ctx = doc->ctx; pdf_obj *form = pdf_dict_getp(pdf_trailer(doc), "Root/AcroForm/Fields"); int i, n; pdf_obj *result = pdf_new_array(doc, 0); pdf_obj *nil = NULL; fz_var(nil); fz_try(ctx) { /* The 'fields' array not being present signals that all fields * should be acted upon, so handle it using the exclude case - excluding none */ if (exclude || !fields) { /* mark the fields we don't want to act upon */ nil = pdf_new_null(doc); n = pdf_array_len(fields); for (i = 0; i < n; i++) { pdf_obj *field = pdf_array_get(fields, i); if (pdf_is_string(field)) field = pdf_lookup_field(form, pdf_to_str_buf(field)); if (field) pdf_dict_puts(field, "Exclude", nil); } /* Act upon all unmarked fields */ n = pdf_array_len(form); for (i = 0; i < n; i++) add_field_hierarchy_to_array(result, pdf_array_get(form, i)); /* Unmark the marked fields */ n = pdf_array_len(fields); for (i = 0; i < n; i++) { pdf_obj *field = pdf_array_get(fields, i); if (pdf_is_string(field)) field = pdf_lookup_field(form, pdf_to_str_buf(field)); if (field) pdf_dict_dels(field, "Exclude"); } } else { n = pdf_array_len(fields); for (i = 0; i < n; i++) { pdf_obj *field = pdf_array_get(fields, i); if (pdf_is_string(field)) field = pdf_lookup_field(form, pdf_to_str_buf(field)); if (field) add_field_hierarchy_to_array(result, field); } } } fz_always(ctx) { pdf_drop_obj(nil); } fz_catch(ctx) { pdf_drop_obj(result); fz_rethrow(ctx); } return result; }
static void decimatepages(fz_context *ctx, pdf_document *doc) { pdf_obj *oldroot, *root, *pages, *kids, *parent; int num_pages = pdf_count_pages(ctx, doc); int page, kidcount; oldroot = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root); pages = pdf_dict_get(ctx, oldroot, PDF_NAME_Pages); root = pdf_new_dict(ctx, doc, 2); pdf_dict_put(ctx, root, PDF_NAME_Type, pdf_dict_get(ctx, oldroot, PDF_NAME_Type)); pdf_dict_put(ctx, root, PDF_NAME_Pages, pdf_dict_get(ctx, oldroot, PDF_NAME_Pages)); pdf_update_object(ctx, doc, pdf_to_num(ctx, oldroot), root); pdf_drop_obj(ctx, root); /* Create a new kids array with our new pages in */ parent = pdf_new_indirect(ctx, doc, pdf_to_num(ctx, pages), pdf_to_gen(ctx, pages)); kids = pdf_new_array(ctx, doc, 1); kidcount = 0; for (page=0; page < num_pages; page++) { pdf_page *page_details = pdf_load_page(ctx, doc, page); int xf = x_factor, yf = y_factor; int x, y; float w = page_details->mediabox.x1 - page_details->mediabox.x0; float h = page_details->mediabox.y1 - page_details->mediabox.y0; if (xf == 0 && yf == 0) { /* Nothing specified, so split along the long edge */ if (w > h) xf = 2, yf = 1; else xf = 1, yf = 2; } else if (xf == 0) xf = 1; else if (yf == 0) yf = 1; for (y = yf-1; y >= 0; y--) { for (x = 0; x < xf; x++) { pdf_obj *newpageobj, *newpageref, *newmediabox; fz_rect mb; int num; newpageobj = pdf_copy_dict(ctx, pdf_lookup_page_obj(ctx, doc, page)); num = pdf_create_object(ctx, doc); pdf_update_object(ctx, doc, num, newpageobj); newpageref = pdf_new_indirect(ctx, doc, num, 0); newmediabox = pdf_new_array(ctx, doc, 4); mb.x0 = page_details->mediabox.x0 + (w/xf)*x; if (x == xf-1) mb.x1 = page_details->mediabox.x1; else mb.x1 = page_details->mediabox.x0 + (w/xf)*(x+1); mb.y0 = page_details->mediabox.y0 + (h/yf)*y; if (y == yf-1) mb.y1 = page_details->mediabox.y1; else mb.y1 = page_details->mediabox.y0 + (h/yf)*(y+1); pdf_array_push(ctx, newmediabox, pdf_new_real(ctx, doc, mb.x0)); pdf_array_push(ctx, newmediabox, pdf_new_real(ctx, doc, mb.y0)); pdf_array_push(ctx, newmediabox, pdf_new_real(ctx, doc, mb.x1)); pdf_array_push(ctx, newmediabox, pdf_new_real(ctx, doc, mb.y1)); pdf_dict_put(ctx, newpageobj, PDF_NAME_Parent, parent); pdf_dict_put(ctx, newpageobj, PDF_NAME_MediaBox, newmediabox); /* Store page object in new kids array */ pdf_array_push(ctx, kids, newpageref); kidcount++; } } } pdf_drop_obj(ctx, parent); /* Update page count and kids array */ pdf_dict_put(ctx, pages, PDF_NAME_Count, pdf_new_int(ctx, doc, kidcount)); pdf_dict_put(ctx, pages, PDF_NAME_Kids, kids); pdf_drop_obj(ctx, kids); }