From e6af9e997df381f053f3f8c85a678ad07677c791 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 3 Feb 2018 22:24:59 +0000 Subject: correctly extract the page boundaries from the page tree --- include/nspdf/page.h | 2 ++ src/cos_object.c | 42 ++++++++++++++++++++++++++- src/cos_object.h | 79 +++++++++++++++++++++++++++++++++++++++++++++----- src/page.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++-- test/parsepdf.c | 29 ++++++++++++++----- 5 files changed, 216 insertions(+), 18 deletions(-) diff --git a/include/nspdf/page.h b/include/nspdf/page.h index 9402a9e..39e6bf6 100644 --- a/include/nspdf/page.h +++ b/include/nspdf/page.h @@ -72,6 +72,8 @@ struct nspdf_render_ctx { nspdferror (*path)(const struct nspdf_style *style, const float *p, unsigned int n, const float transform[6], const void *ctx); }; +nspdferror nspdf_get_page_dimensions(struct nspdf_doc *doc, unsigned int page_number, float *width, float *height); + nspdferror nspdf_page_count(struct nspdf_doc *doc, unsigned int *pages_out); nspdferror nspdf_page_render(struct nspdf_doc *doc, unsigned int page_num, struct nspdf_render_ctx* render_ctx); diff --git a/src/cos_object.c b/src/cos_object.c index 52731ca..12adcc9 100644 --- a/src/cos_object.c +++ b/src/cos_object.c @@ -30,6 +30,10 @@ static nspdferror cos_dump_object(const char *fmt, struct cos_object *cos_obj) printf(" type = COS_TYPE_NAMETREE\n"); break; + case COS_TYPE_NUMBERTREE: + printf(" type = COS_TYPE_NUMBERTREE\n"); + break; + case COS_TYPE_REFERENCE: printf(" type = COS_TYPE_REFERENCE\n" " u.reference->id = %lu\n" @@ -116,7 +120,6 @@ static nspdferror cos_dump_object(const char *fmt, struct cos_object *cos_obj) return NSPDFERROR_OK; - } nspdferror cos_free_object(struct cos_object *cos_obj) @@ -318,6 +321,8 @@ cos_heritable_dictionary_dictionary(struct nspdf_doc *doc, return cos_get_dictionary(doc, dict_value, value_out); } + +/* get an inheritable array object from a dictionary */ nspdferror cos_get_dictionary_array(struct nspdf_doc *doc, struct cos_object *dict, @@ -503,6 +508,41 @@ cos_get_object(struct nspdf_doc *doc, return res; } + +nspdferror +cos_get_rectangle(struct nspdf_doc *doc, + struct cos_object *cobj, + struct cos_rectangle *rect_out) +{ + nspdferror res; + struct cos_rectangle rect; + + res = nspdf__xref_get_referenced(doc, &cobj); + if (res == NSPDFERROR_OK) { + if ((cobj->type != COS_TYPE_ARRAY) || + (cobj->u.array->length != 4)) { + res = NSPDFERROR_TYPE; + } else { + res = cos_get_number(doc, cobj->u.array->values[0], &rect.llx); + if (res == NSPDFERROR_OK) { + res = cos_get_number(doc, cobj->u.array->values[1], &rect.lly); + if (res == NSPDFERROR_OK) { + res = cos_get_number(doc, cobj->u.array->values[2], &rect.urx); + if (res == NSPDFERROR_OK) { + res = cos_get_number(doc, cobj->u.array->values[3], &rect.ury); + if (res == NSPDFERROR_OK) { + *rect_out = rect; + } + } + } + } + } + } + + return res; +} + + /* * exported interface documented in cos_object.h * diff --git a/src/cos_object.h b/src/cos_object.h index 632126e..a1a70ee 100644 --- a/src/cos_object.h +++ b/src/cos_object.h @@ -20,9 +20,13 @@ struct nspdf_doc; struct content_operation; struct cos_content; +struct cos_object; +/** + * The type of cos object in an entry. + */ enum cos_type { - COS_TYPE_NULL, /* 0 */ + COS_TYPE_NULL, /* 0 - NULL object */ COS_TYPE_BOOL, COS_TYPE_INT, COS_TYPE_REAL, @@ -37,8 +41,10 @@ enum cos_type { COS_TYPE_CONTENT, /* 12 - parsed content stream */ }; -struct cos_object; +/** + * list of COS dictionary entries. + */ struct cos_dictionary_entry { /** next key/value in dictionary */ struct cos_dictionary_entry *next; @@ -50,6 +56,7 @@ struct cos_dictionary_entry { struct cos_object *value; }; + /** * array of COS objects */ @@ -64,6 +71,7 @@ struct cos_array { struct cos_object **values; }; + /** * COS string data */ @@ -73,12 +81,29 @@ struct cos_string { uint8_t *data; /**< string data */ }; + +/** + * reference to COS object + */ struct cos_reference { uint64_t id; /**< id of indirect object */ uint64_t generation; /**< generation of indirect object */ }; +/** + * COS rectangle + */ +struct cos_rectangle { + float llx; /**< lower left x */ + float lly; /**< lower left y */ + float urx; /**< upper right x */ + float ury; /**< upper right y */ +}; + +/** + * Carosel object + */ struct cos_object { enum cos_type type; union { @@ -118,10 +143,11 @@ nspdferror cos_free_object(struct cos_object *cos_obj); /** - * extract a value for a key from a dictionary + * extract a value object for a key from a dictionary * - * This retrieves the value of a given key in a dictionary and removes it from - * the dictionary. + * This retrieves the value object of a given key in a dictionary and removes + * the entry from the dictionary. Once extracted the caller owns the returned + * object and must free it. * * \param dict The dictionary * \param key The key to lookup @@ -134,8 +160,13 @@ nspdferror cos_extract_dictionary_value(struct cos_object *dict, const char *key /** - * get a value for a key from a dictionary + * get a value object for a key from a dictionary + * + * Get the value for a key from a dictionary, If the dictionary is an object + * reference it will be dereferenced first which will parse any + * previously unreferenced indirect objects. * + * \param doc The document the cos object belongs to or NULL to supress dereferencing. * \param dict The dictionary * \param key The key to lookup * \param value_out The value object associated with the key @@ -146,7 +177,23 @@ nspdferror cos_extract_dictionary_value(struct cos_object *dict, const char *key nspdferror cos_get_dictionary_value(struct nspdf_doc *doc, struct cos_object *dict, const char *key, struct cos_object **value_out); -nspdferror cos_get_dictionary_int(struct nspdf_doc *doc, struct cos_object *dict, const char *key, int64_t *value_out); +/** + * get an integer value for a key from a dictionary + * + * Get the integer value for a key from a dictionary, If the dictionary is an + * object reference it will be dereferenced first which will parse any + * previously unreferenced indirect objects. + * + * \param doc The document the cos object belongs to or NULL to supress dereferencing. + * \param dict The dictionary + * \param key The key to lookup + * \param in_out The integer value associated with the key. + * \return NSPDFERROR_OK and value_out updated on success. + * NSPDFERROR_TYPE if the object passed in \p dict is not a dictionary + * or the value of the key is not an integer. + * NSPDFERROR_NOTFOUND if the key is not present in the dictionary. + */ +nspdferror cos_get_dictionary_int(struct nspdf_doc *doc, struct cos_object *dict, const char *key, int64_t *int_out); nspdferror cos_get_dictionary_name(struct nspdf_doc *doc, struct cos_object *dict, const char *key, const char **value_out); @@ -190,6 +237,7 @@ nspdferror cos_get_array_dictionary(struct nspdf_doc *doc, struct cos_object *ar */ nspdferror cos_get_int(struct nspdf_doc *doc, struct cos_object *cobj, int64_t *value_out); + /** * get the float value of a cos object. * @@ -205,6 +253,7 @@ nspdferror cos_get_int(struct nspdf_doc *doc, struct cos_object *cobj, int64_t * */ nspdferror cos_get_number(struct nspdf_doc *doc, struct cos_object *cobj, float *value_out); + /** * get the name value of a cos object. * @@ -268,6 +317,7 @@ nspdferror cos_get_dictionary(struct nspdf_doc *doc, struct cos_object *cobj, st */ nspdferror cos_get_array(struct nspdf_doc *doc, struct cos_object *cobj, struct cos_object **value_out); + /** * get the stream value of a cos object. * @@ -283,6 +333,7 @@ nspdferror cos_get_array(struct nspdf_doc *doc, struct cos_object *cobj, struct */ nspdferror cos_get_stream(struct nspdf_doc *doc, struct cos_object *cobj, struct cos_stream **stream_out); + /** * get a direct cos object. * @@ -296,6 +347,7 @@ nspdferror cos_get_stream(struct nspdf_doc *doc, struct cos_object *cobj, struct */ nspdferror cos_get_object(struct nspdf_doc *doc, struct cos_object *cobj, struct cos_object **object_out); + /** * get a parsed content object * @@ -310,4 +362,17 @@ nspdferror cos_get_object(struct nspdf_doc *doc, struct cos_object *cobj, struct */ nspdferror cos_get_content(struct nspdf_doc *doc, struct cos_object *cobj, struct cos_content **content_out); + +/** + * Get a rectangle + * + * Generates a synthetic rectangle object from a array of four numbers + * + * \param doc The document the cos object belongs to. + * \param cobj A cos object. + * \param rect_out The result rectangle. + * \return NSERROR_OK and \p rect_out updated, + */ +nspdferror cos_get_rectangle(struct nspdf_doc *doc, struct cos_object *cobj, struct cos_rectangle *rect_out); + #endif diff --git a/src/page.c b/src/page.c index e4bbae4..d55a92f 100644 --- a/src/page.c +++ b/src/page.c @@ -22,8 +22,13 @@ /** page entry */ struct page_table_entry { struct cos_object *resources; - struct cos_object *mediabox; struct cos_object *contents; + struct cos_rectangle mediabox; /* extent of media - required */ + struct cos_rectangle cropbox; /* default is mediabox */ + struct cos_rectangle bleedbox; /* default is crop box */ + struct cos_rectangle trimbox; /* default is crop box */ + struct cos_rectangle artbox; /* default is crop box */ + }; /** @@ -90,6 +95,7 @@ nspdf__decode_page_tree(struct nspdf_doc *doc, } else if (strcmp(type, "Page") == 0) { struct page_table_entry *page; + struct cos_object *rect_array; page = doc->page_table + (*page_index); @@ -106,11 +112,68 @@ nspdf__decode_page_tree(struct nspdf_doc *doc, res = cos_heritable_dictionary_array(doc, page_tree_node, "MediaBox", - &(page->mediabox)); + &rect_array); + if (res != NSPDFERROR_OK) { + return res; + } + + res = cos_get_rectangle(doc, rect_array, &page->mediabox); if (res != NSPDFERROR_OK) { return res; } + /* optional heritable crop box */ + res = cos_heritable_dictionary_array(doc, + page_tree_node, + "CropBox", + &rect_array); + if (res == NSPDFERROR_OK) { + res = cos_get_rectangle(doc, rect_array, &page->cropbox); + } + if (res != NSPDFERROR_OK) { + /* default is mediabox */ + page->cropbox = page->mediabox; + } + + /* optional bleed box */ + res = cos_get_dictionary_array(doc, + page_tree_node, + "BleedBox", + &rect_array); + if (res == NSPDFERROR_OK) { + res = cos_get_rectangle(doc, rect_array, &page->bleedbox); + } + if (res != NSPDFERROR_OK) { + /* default is cropbox */ + page->bleedbox = page->cropbox; + } + + /* optional trim box */ + res = cos_get_dictionary_array(doc, + page_tree_node, + "TrimBox", + &rect_array); + if (res == NSPDFERROR_OK) { + res = cos_get_rectangle(doc, rect_array, &page->trimbox); + } + if (res != NSPDFERROR_OK) { + /* default is cropbox */ + page->trimbox = page->cropbox; + } + + /* optional art box */ + res = cos_get_dictionary_array(doc, + page_tree_node, + "ArtBox", + &rect_array); + if (res == NSPDFERROR_OK) { + res = cos_get_rectangle(doc, rect_array, &page->artbox); + } + if (res != NSPDFERROR_OK) { + /* default is cropbox */ + page->artbox = page->cropbox; + } + /* optional page contents */ res = cos_get_dictionary_value(doc, page_tree_node, @@ -323,7 +386,6 @@ nspdf_page_render(struct nspdf_doc *doc, nspdferror res; struct content_operation *operation; unsigned int idx; - struct graphics_state gs; page_entry = doc->page_table + page_number; @@ -406,3 +468,17 @@ nspdf_page_render(struct nspdf_doc *doc, return res; } + + +nspdferror +nspdf_get_page_dimensions(struct nspdf_doc *doc, + unsigned int page_number, + float *width, + float *height) +{ + struct page_table_entry *page_entry; + page_entry = doc->page_table + page_number; + *width = page_entry->cropbox.urx - page_entry->cropbox.llx; + *height = page_entry->cropbox.ury - page_entry->cropbox.lly; + return NSPDFERROR_OK; +} diff --git a/test/parsepdf.c b/test/parsepdf.c index f569418..ae910b7 100644 --- a/test/parsepdf.c +++ b/test/parsepdf.c @@ -71,16 +71,24 @@ static nspdferror render_pages(struct nspdf_doc *doc, unsigned int page_count) struct nspdf_render_ctx render_ctx; unsigned int page_render_list[4] = { 0, 1, 0, 1}; unsigned int page_index; + float page_width; + float page_height; - render_ctx.device_space[0] = 1; - render_ctx.device_space[1] = 0; - render_ctx.device_space[2] = 0; - render_ctx.device_space[3] = -1; /* y scale */ - render_ctx.device_space[4] = 0; /* x offset */ - render_ctx.device_space[5] = 800; /* y offset */ - render_ctx.path = pdf_path; + render_ctx.device_space[0] = 1; + render_ctx.device_space[1] = 0; + render_ctx.device_space[2] = 0; + render_ctx.device_space[3] = -1; /* y scale */ + render_ctx.device_space[4] = 0; /* x offset */ + render_ctx.device_space[5] = 800; /* y offset */ + render_ctx.path = pdf_path; for (page_index = 0; page_index < page_count; page_index++) { + res = nspdf_get_page_dimensions(doc, + page_index, + &page_width, + &page_height); + printf("page w:%f h:%f\n", page_width, page_height); + res = nspdf_page_render(doc, page_index, &render_ctx); if (res != NSPDFERROR_OK) { break; @@ -88,11 +96,18 @@ static nspdferror render_pages(struct nspdf_doc *doc, unsigned int page_count) } for (page_index = 0; page_index < 4; page_index++) { + res = nspdf_get_page_dimensions(doc, + page_index, + &page_width, + &page_height); + printf("page w:%f h:%f\n", page_width, page_height); + res = nspdf_page_render(doc, page_render_list[page_index], &render_ctx); if (res != NSPDFERROR_OK) { break; } } + return res; } -- cgit v1.2.3