From f738daa2a3cba3423273827cd7e58583155956ff Mon Sep 17 00:00:00 2001 From: Andre Renaud Date: Sun, 5 Jul 2026 13:51:24 +1200 Subject: [PATCH 1/2] pdf_add_line_pattern: Added ability to draw non-solid lines --- pdfgen.c | 42 ++++++++++++++++++++++++++++++++++++------ pdfgen.h | 22 ++++++++++++++++++++++ tests/main.c | 25 +++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/pdfgen.c b/pdfgen.c index 1b20485..db4d3de 100644 --- a/pdfgen.c +++ b/pdfgen.c @@ -719,10 +719,8 @@ static inline void *flexarray_get(const struct flexarray *flex, int index) */ #define INIT_DSTR \ - (struct dstr) \ - { \ - .static_data = {0}, .data = NULL, .alloc_len = 0, .used_len = 0 \ - } + (struct dstr){ \ + .static_data = {0}, .data = NULL, .alloc_len = 0, .used_len = 0} static char *dstr_data(struct dstr *str) { @@ -3354,18 +3352,43 @@ int pdf_add_text_wrap(struct pdf_doc *pdf, struct pdf_object *page, return 0; } -int pdf_add_line(struct pdf_doc *pdf, struct pdf_object *page, float x1, - float y1, float x2, float y2, float width, uint32_t colour) +int pdf_add_line_pattern(struct pdf_doc *pdf, struct pdf_object *page, + float x1, float y1, float x2, float y2, float width, + uint32_t colour, const float pattern[], + int pattern_len, float phase) { int ret; struct dstr str = INIT_DSTR; + int nonzero = 0; + + if (pattern_len < 0 || (pattern_len > 0 && !pattern)) + return pdf_set_err(pdf, -EINVAL, "Invalid line pattern"); + for (int i = 0; i < pattern_len; i++) { + if (pattern[i] < 0.0f) + return pdf_set_err(pdf, -EINVAL, + "Line pattern lengths must be >= 0"); + if (pattern[i] > 0.0f) + nonzero = 1; + } + if (pattern_len > 0 && !nonzero) + return pdf_set_err(pdf, -EINVAL, + "Line pattern must have a non-zero length"); + if (pattern_len > 0) { + dstr_append(&str, "["); + for (int i = 0; i < pattern_len; i++) + dstr_printf(&str, "%s%f", i ? " " : "", pattern[i]); + dstr_printf(&str, "] %f d\r\n", phase); + } dstr_printf(&str, "%f w\r\n", width); dstr_printf(&str, "%f %f m\r\n", x1, y1); dstr_printf(&str, "/DeviceRGB CS\r\n"); dstr_printf(&str, "%f %f %f RG\r\n", PDF_RGB_R(colour), PDF_RGB_G(colour), PDF_RGB_B(colour)); dstr_printf(&str, "%f %f l S\r\n", x2, y2); + /* Restore the solid pattern */ + if (pattern_len > 0) + dstr_append(&str, "[] 0 d\r\n"); ret = pdf_add_stream(pdf, page, dstr_data(&str)); dstr_free(&str); @@ -3373,6 +3396,13 @@ int pdf_add_line(struct pdf_doc *pdf, struct pdf_object *page, float x1, return ret; } +int pdf_add_line(struct pdf_doc *pdf, struct pdf_object *page, float x1, + float y1, float x2, float y2, float width, uint32_t colour) +{ + return pdf_add_line_pattern(pdf, page, x1, y1, x2, y2, width, colour, + NULL, 0, 0.0f); +} + int pdf_add_cubic_bezier(struct pdf_doc *pdf, struct pdf_object *page, float x1, float y1, float x2, float y2, float xq1, float yq1, float xq2, float yq2, float width, diff --git a/pdfgen.h b/pdfgen.h index bc2c745..d7976b6 100644 --- a/pdfgen.h +++ b/pdfgen.h @@ -511,6 +511,28 @@ int pdf_add_text_wrap(struct pdf_doc *pdf, struct pdf_object *page, int pdf_add_line(struct pdf_doc *pdf, struct pdf_object *page, float x1, float y1, float x2, float y2, float width, uint32_t colour); +/** + * Add a line with a dash pattern (dashed/dotted etc...) + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x1 X offset of start of line + * @param y1 Y offset of start of line + * @param x2 X offset of end of line + * @param y2 Y offset of end of line + * @param width Width of the line + * @param colour Colour to draw the line + * @param pattern Array of alternating dash & gap lengths describing the + * pattern, e.g. {6, 3} => dashed, {1, 2} => dotted. At least one + * length must be non-zero + * @param pattern_len Number of entries in pattern (0 => solid line) + * @param phase Distance into the pattern at which to start the line + * @return 0 on success, < 0 on failure + */ +int pdf_add_line_pattern(struct pdf_doc *pdf, struct pdf_object *page, + float x1, float y1, float x2, float y2, float width, + uint32_t colour, const float pattern[], + int pattern_len, float phase); + /** * Add a cubic bezier curve to the document * @param pdf PDF document to add to diff --git a/tests/main.c b/tests/main.c index a8b64c5..b116a86 100644 --- a/tests/main.c +++ b/tests/main.c @@ -114,6 +114,31 @@ int main(int argc, char *argv[]) pdf_add_text(pdf, NULL, "Page One", 10, 20, 30, PDF_RGB(0xff, 0, 0)); pdf_add_text(pdf, NULL, "PjGQji", 18, 20, 130, PDF_RGB(0, 0xff, 0xff)); pdf_add_line(pdf, NULL, 10, 24, 100, 24, 4, PDF_RGB(0xff, 0, 0)); + float dashed[] = {6, 3}; + pdf_add_line_pattern(pdf, NULL, 10, 34, 100, 34, 2, PDF_RGB(0, 0x80, 0), + dashed, 2, 0); + float dotted[] = {1, 2}; + pdf_add_line_pattern(pdf, NULL, 10, 40, 100, 40, 2, PDF_RGB(0, 0, 0xff), + dotted, 2, 0); + /* Invalid patterns should be rejected */ + float all_zero[] = {0, 0}; + if (pdf_add_line_pattern(pdf, NULL, 10, 46, 100, 46, 2, PDF_BLACK, + all_zero, 2, 0) >= 0) { + fprintf(stderr, "All-zero line pattern not rejected\n"); + return -1; + } + float negative[] = {3, -1}; + if (pdf_add_line_pattern(pdf, NULL, 10, 46, 100, 46, 2, PDF_BLACK, + negative, 2, 0) >= 0) { + fprintf(stderr, "Negative line pattern not rejected\n"); + return -1; + } + if (pdf_add_line_pattern(pdf, NULL, 10, 46, 100, 46, 2, PDF_BLACK, NULL, + 2, 0) >= 0) { + fprintf(stderr, "NULL line pattern not rejected\n"); + return -1; + } + pdf_clear_err(pdf); pdf_add_cubic_bezier(pdf, NULL, 10, 100, 150, 100, 20, 30, 60, 30, 4, PDF_RGB(0, 0xff, 0)); pdf_add_quadratic_bezier(pdf, NULL, 10, 140, 150, 140, 50, 160, 4, From 5748b27c4bd8af0458835e8275553fa0c981c064 Mon Sep 17 00:00:00 2001 From: Andre Renaud Date: Sun, 5 Jul 2026 13:58:44 +1200 Subject: [PATCH 2/2] reinstate formatting --- pdfgen.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pdfgen.c b/pdfgen.c index db4d3de..800ac13 100644 --- a/pdfgen.c +++ b/pdfgen.c @@ -719,8 +719,10 @@ static inline void *flexarray_get(const struct flexarray *flex, int index) */ #define INIT_DSTR \ - (struct dstr){ \ - .static_data = {0}, .data = NULL, .alloc_len = 0, .used_len = 0} + (struct dstr) \ + { \ + .static_data = {0}, .data = NULL, .alloc_len = 0, .used_len = 0 \ + } static char *dstr_data(struct dstr *str) {