From 1ca90f384d4f2311cbf0abd44d8e4e5b7a4abb37 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 31 Jan 2018 00:03:38 +0000 Subject: start actual page rendering --- include/nspdf/page.h | 2 +- src/cos_content.c | 35 ++++---- src/cos_content.h | 17 +++- src/cos_object.c | 1 + src/cos_object.h | 11 +-- src/page.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++ test/parsepdf.c | 18 ++++ 7 files changed, 292 insertions(+), 30 deletions(-) diff --git a/include/nspdf/page.h b/include/nspdf/page.h index f8c280e..9402a9e 100644 --- a/include/nspdf/page.h +++ b/include/nspdf/page.h @@ -35,7 +35,7 @@ enum nspdf_style_operation { */ typedef struct nspdf_style { enum nspdf_style_operation stroke_type; /**< Stroke plot type */ - int stroke_width; /**< Width of stroke, in pixels */ + float stroke_width; /**< Width of stroke, in pixels */ uint32_t stroke_colour; /**< Colour of stroke XBGR */ enum nspdf_style_operation fill_type; /**< Fill plot type */ diff --git a/src/cos_content.c b/src/cos_content.c index cf5d2e0..0e14f85 100644 --- a/src/cos_content.c +++ b/src/cos_content.c @@ -20,7 +20,8 @@ #include "cos_content.h" #include "pdf_doc.h" -static const char*operator_name(enum content_operator operator) +const char* +nspdf__cos_content_operator_name(enum content_operator operator) { switch(operator) { case CONTENT_OP_b: return "b"; @@ -135,14 +136,14 @@ copy_numbers(unsigned int wanted, } if ((*operand_idx) > index) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), wanted, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), wanted, *operand_idx); while (index < (*operand_idx)) { cos_free_object(*(operands + index)); index++; } } else if ((*operand_idx) < index) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), wanted, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), wanted, *operand_idx); } *operand_idx = 0; /* all operands freed */ @@ -174,14 +175,14 @@ copy_integers(unsigned int wanted, } if ((*operand_idx) > index) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), wanted, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), wanted, *operand_idx); while (index < (*operand_idx)) { cos_free_object(*(operands + index)); index++; } } else if ((*operand_idx) < index) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), wanted, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), wanted, *operand_idx); } *operand_idx = 0; /* all operands freed */ @@ -200,7 +201,7 @@ copy_string(struct cos_object **operands, if ((*operand_idx) == 0) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 1, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 1, *operand_idx); operation_out->u.string.length = 0; return NSPDFERROR_OK; } @@ -232,7 +233,7 @@ copy_string(struct cos_object **operands, if ((*operand_idx) > 1) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 1, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 1, *operand_idx); } /* free all operands */ @@ -254,7 +255,7 @@ copy_array(struct cos_object **operands, if ((*operand_idx) == 0) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 1, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 1, *operand_idx); operation_out->u.array.length = 0; return NSPDFERROR_OK; } @@ -273,7 +274,7 @@ copy_array(struct cos_object **operands, if ((*operand_idx) > 1) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 1, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 1, *operand_idx); } /* free all operands */ @@ -296,7 +297,7 @@ copy_name(struct cos_object **operands, if ((*operand_idx) == 0) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 1, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 1, *operand_idx); operation_out->u.name = NULL; return NSPDFERROR_OK; } @@ -313,7 +314,7 @@ copy_name(struct cos_object **operands, if ((*operand_idx) > 1) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 1, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 1, *operand_idx); } /* free all operands */ @@ -335,7 +336,7 @@ copy_name_number(struct cos_object **operands, if ((*operand_idx) == 0) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 2, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 2, *operand_idx); operation_out->u.namenumber.name = NULL; return NSPDFERROR_OK; } @@ -361,13 +362,13 @@ copy_name_number(struct cos_object **operands, } } else { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 2, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 2, *operand_idx); } } if ((*operand_idx) > 2) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 2, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 2, *operand_idx); } /* free all operands */ @@ -390,7 +391,7 @@ copy_array_int(struct cos_object **operands, if ((*operand_idx) == 0) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 2, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 2, *operand_idx); operation_out->u.namenumber.name = NULL; return NSPDFERROR_OK; } @@ -418,13 +419,13 @@ copy_array_int(struct cos_object **operands, } } else { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 2, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 2, *operand_idx); } } if ((*operand_idx) > 2) { printf("operator %s that takes %d operands passed %d\n", - operator_name(operation_out->operator), 2, *operand_idx); + nspdf__cos_content_operator_name(operation_out->operator), 2, *operand_idx); } /* free all operands */ diff --git a/src/cos_content.h b/src/cos_content.h index e0d2dfb..09700c2 100644 --- a/src/cos_content.h +++ b/src/cos_content.h @@ -193,9 +193,9 @@ enum content_operator { #define content_string_intrnl_lngth ((sizeof(float) * content_number_size) - sizeof(uint8_t *)) -struct content_operation -{ +struct content_operation { enum content_operator operator; + union { float number[content_number_size]; @@ -230,6 +230,19 @@ struct content_operation } u; }; +/** + * Synthetic parsed content object. + */ +struct cos_content { + unsigned int length; /**< number of content operations */ + unsigned int alloc; /**< number of allocated operations */ + struct content_operation *operations; +}; + + +const char* nspdf__cos_content_operator_name(enum content_operator operator); + + /** * convert an operator and operand list into an operation */ diff --git a/src/cos_object.c b/src/cos_object.c index 5d7da19..52731ca 100644 --- a/src/cos_object.c +++ b/src/cos_object.c @@ -17,6 +17,7 @@ #include #include "xref.h" +#include "cos_content.h" #include "cos_object.h" #include "cos_parse.h" #include "pdf_doc.h" diff --git a/src/cos_object.h b/src/cos_object.h index 79a1c8d..632126e 100644 --- a/src/cos_object.h +++ b/src/cos_object.h @@ -19,6 +19,7 @@ struct nspdf_doc; struct content_operation; +struct cos_content; enum cos_type { COS_TYPE_NULL, /* 0 */ @@ -78,16 +79,6 @@ struct cos_reference { }; -/** - * Synthetic parsed content object. - * - */ -struct cos_content { - unsigned int length; /**< number of content operations */ - unsigned int alloc; /**< number of allocated operations */ - struct content_operation *operations; -}; - struct cos_object { enum cos_type type; union { diff --git a/src/page.c b/src/page.c index 5b91416..e4bbae4 100644 --- a/src/page.c +++ b/src/page.c @@ -15,6 +15,7 @@ #include #include +#include "cos_content.h" #include "cos_object.h" #include "pdf_doc.h" @@ -146,6 +147,170 @@ nspdf_page_count(struct nspdf_doc *doc, unsigned int *pages_out) return NSPDFERROR_OK; } +/** + * colourspaces + * \todo extend this with full list from section 4.5.2 + */ +enum graphics_state_colorspace { + GSDeviceGray = 0, /* Default */ + GSDeviceRGB, + GSDeviceCMYK, +}; + +struct graphics_state_color { + enum graphics_state_colorspace space; + union { + float gray; /* default is 0 - black */ + float rgb[3]; + float cmyk[3]; + }; +}; + +struct graphics_state_param { + float ctm[6]; /* current transform matrix */ + /* clipping path */ + struct graphics_state_color stroke_colour; + struct graphics_state_color other_colour; + /* text state */ + float line_width; + unsigned int line_cap; + unsigned int line_join; + float miter_limit; + /* dash pattern */ + /* rendering intent RelativeColorimetric */ + bool stroke_adjustment; + /* blend mode: Normal */ + /* soft mask */ + /* alpha constant */ + /* alpha source */ +}; + +struct graphics_state { + float *path; /* current path */ + unsigned int path_idx; /* current index into path */ + unsigned int path_alloc; /* current number of path elements allocated */ + + struct graphics_state_param *param_stack; /* parameter stack */ + unsigned int param_stack_idx; + unsigned int param_stack_alloc; +}; + +static inline nspdferror +render_operation_m(struct content_operation *operation, struct graphics_state *gs) +{ + gs->path[gs->path_idx++] = NSPDF_PATH_MOVE; + gs->path[gs->path_idx++] = operation->u.number[0]; + gs->path[gs->path_idx++] = operation->u.number[1]; + return NSPDFERROR_OK; +} + +static inline nspdferror +render_operation_l(struct content_operation *operation, struct graphics_state *gs) +{ + gs->path[gs->path_idx++] = NSPDF_PATH_LINE; + gs->path[gs->path_idx++] = operation->u.number[0]; + gs->path[gs->path_idx++] = operation->u.number[1]; + return NSPDFERROR_OK; +} + +static inline nspdferror +render_operation_re(struct content_operation *operation, struct graphics_state *gs) +{ + gs->path[gs->path_idx++] = NSPDF_PATH_MOVE; + gs->path[gs->path_idx++] = operation->u.number[0]; /* x */ + gs->path[gs->path_idx++] = operation->u.number[1]; /* y */ + gs->path[gs->path_idx++] = NSPDF_PATH_LINE; + gs->path[gs->path_idx++] = operation->u.number[0] + operation->u.number[2]; + gs->path[gs->path_idx++] = operation->u.number[1]; + gs->path[gs->path_idx++] = NSPDF_PATH_LINE; + gs->path[gs->path_idx++] = operation->u.number[0] + operation->u.number[2]; + gs->path[gs->path_idx++] = operation->u.number[1] + operation->u.number[3]; + gs->path[gs->path_idx++] = NSPDF_PATH_LINE; + gs->path[gs->path_idx++] = operation->u.number[0]; + gs->path[gs->path_idx++] = operation->u.number[1] + operation->u.number[3]; + gs->path[gs->path_idx++] = NSPDF_PATH_CLOSE; + + return NSPDFERROR_OK; +} + +static inline nspdferror +render_operation_h(struct graphics_state *gs) +{ + gs->path[gs->path_idx++] = NSPDF_PATH_CLOSE; + return NSPDFERROR_OK; +} + +static inline nspdferror +render_operation_f(struct graphics_state *gs, struct nspdf_render_ctx* render_ctx) +{ + struct nspdf_style style; + style.stroke_type = NSPDF_OP_TYPE_NONE; + style.stroke_colour = 0x01000000; + style.fill_type = NSPDF_OP_TYPE_SOLID; + style.fill_colour = 0; + + render_ctx->path(&style, + gs->path, + gs->path_idx, + gs->param_stack[gs->param_stack_idx].ctm, + render_ctx->ctx); + gs->path_idx = 0; + return NSPDFERROR_OK; +} + + +static inline nspdferror +render_operation_S(struct graphics_state *gs, struct nspdf_render_ctx* render_ctx) +{ + struct nspdf_style style; + + style.stroke_type = NSPDF_OP_TYPE_SOLID; + style.stroke_colour = 0; + style.stroke_width = gs->param_stack[gs->param_stack_idx].line_width; + style.fill_type = NSPDF_OP_TYPE_NONE; + style.fill_colour = 0x01000000; + render_ctx->path(&style, + gs->path, + gs->path_idx, + gs->param_stack[gs->param_stack_idx].ctm, + render_ctx->ctx); + gs->path_idx = 0; + return NSPDFERROR_OK; +} + +static inline nspdferror +render_operation_w(struct content_operation *operation, struct graphics_state *gs) +{ + gs->param_stack[gs->param_stack_idx].line_width = operation->u.number[0]; + return NSPDFERROR_OK; +} + +/** + * Initialise the parameter stack + * + * allocates the initial parameter stack and initialises the defaults + */ +static nspdferror +init_param_stack(struct graphics_state *gs, struct nspdf_render_ctx* render_ctx) +{ + gs->param_stack_alloc = 16; /* start with 16 deep parameter stack */ + gs->param_stack_idx = 0; + gs->param_stack = calloc(gs->param_stack_alloc, + sizeof(struct graphics_state_param)); + if (gs->param_stack == NULL) { + return NSPDFERROR_NOMEM; + } + + gs->param_stack[0].ctm[0] = render_ctx->device_space[0]; + gs->param_stack[0].ctm[1] = render_ctx->device_space[1]; + gs->param_stack[0].ctm[2] = render_ctx->device_space[2]; + gs->param_stack[0].ctm[3] = render_ctx->device_space[3]; + gs->param_stack[0].ctm[4] = render_ctx->device_space[4]; + gs->param_stack[0].ctm[5] = render_ctx->device_space[5]; + gs->param_stack[0].line_width = 1.0; + + return NSPDFERROR_OK; +} /* exported interface documented in nspdf/page.h */ nspdferror @@ -156,6 +321,10 @@ nspdf_page_render(struct nspdf_doc *doc, struct page_table_entry *page_entry; struct cos_content *page_content; /* page operations array */ nspdferror res; + struct content_operation *operation; + unsigned int idx; + + struct graphics_state gs; page_entry = doc->page_table + page_number; @@ -166,5 +335,74 @@ nspdf_page_render(struct nspdf_doc *doc, printf("page %d content:%p\n", page_number, page_content); + gs.path_idx = 0; + gs.path_alloc = 8192; + gs.path = malloc(gs.path_alloc * sizeof(float)); + if (gs.path == NULL) { + return NSPDFERROR_NOMEM; + } + + res = init_param_stack(&gs, render_ctx); + if (res != NSPDFERROR_OK) { + free(gs.path); + return res; + } + + /* iterate over operations */ + for (idx = 0, operation = page_content->operations; + idx < page_content->length; + idx++, operation++) { + switch(operation->operator) { + case CONTENT_OP_m: /* move */ + res = render_operation_m(operation, &gs); + break; + + case CONTENT_OP_l: /* line */ + res = render_operation_l(operation, &gs); + break; + + case CONTENT_OP_re: /* rectangle */ + res = render_operation_re(operation, &gs); + break; + + case CONTENT_OP_h: /* close path */ + res = render_operation_h(&gs); + break; + + case CONTENT_OP_f: + case CONTENT_OP_f_: + case CONTENT_OP_B: + case CONTENT_OP_B_: + case CONTENT_OP_b: + case CONTENT_OP_b_: + res = render_operation_f(&gs, render_ctx); + break; + + case CONTENT_OP_s: + render_operation_h(&gs); + res = render_operation_S(&gs, render_ctx); + break; + + case CONTENT_OP_S: + res = render_operation_S(&gs, render_ctx); + break; + + case CONTENT_OP_w: + res = render_operation_w(operation, &gs); + //printf("line width:%f\n", gs.param_stack[gs.param_stack_idx].line_width); + break; + + default: + printf("operator %s\n", + nspdf__cos_content_operator_name(operation->operator)); + break; + + } + + } + + free(gs.param_stack); + free(gs.path); + return res; } diff --git a/test/parsepdf.c b/test/parsepdf.c index 054e96d..f569418 100644 --- a/test/parsepdf.c +++ b/test/parsepdf.c @@ -55,6 +55,16 @@ read_whole_pdf(const char *fname, uint8_t **buffer, uint64_t *buffer_length) return NSPDFERROR_OK; } +static nspdferror +pdf_path(const struct nspdf_style *style, + const float *path, + unsigned int path_length, + const float transform[6], + const void *ctxin) +{ + return NSPDFERROR_OK; +} + static nspdferror render_pages(struct nspdf_doc *doc, unsigned int page_count) { nspdferror res; @@ -62,6 +72,14 @@ static nspdferror render_pages(struct nspdf_doc *doc, unsigned int page_count) unsigned int page_render_list[4] = { 0, 1, 0, 1}; unsigned int page_index; + 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_page_render(doc, page_index, &render_ctx); if (res != NSPDFERROR_OK) { -- cgit v1.2.3