File Coverage

src/pdfmake_render_page.c
Criterion Covered Total %
statement 0 66 0.0
branch 0 46 0.0
condition n/a
subroutine n/a
pod n/a
total 0 112 0.0


line stmt bran cond sub pod time code
1             /* pdfmake_render_page.c
2             *
3             * Page-render utility implementations.
4             *
5             * Currently implemented:
6             * - pdfmake_render_opts_init (real)
7             * - pdfmake_page_get_render_size (real — MediaBox + Rotate + DPI)
8             * - pdfmake_page_render_free (real)
9             *
10             * Stubbed (return PDFMAKE_ERENDER_PAGE until the rasterizer lands):
11             * - pdfmake_render_page_to_pixels
12             * - pdfmake_render_page_region
13             *
14             * These exist so the linker can resolve every symbol referenced from
15             * xs/render_page.xs under PERL_DL_NONLAZY=1 (which `make test` sets).
16             *
17             * NOTE: We intentionally avoid including pdfmake_render_page.h because it
18             * pulls in pdfmake_render.h and pdfmake_interpreter.h, which currently
19             * declare matrix helpers with conflicting signatures. Local type
20             * declarations below mirror the public header (and Make.xs forward
21             * declarations) exactly so the ABI is identical.
22             */
23              
24             #include
25             #include
26             #include
27             #include
28              
29             #include "pdfmake_types.h"
30             #include "pdfmake_reader.h"
31              
32             /*============================================================================
33             * Locally declared types — must match include/pdfmake_render_page.h
34             *==========================================================================*/
35              
36             #define PDFMAKE_ERENDER_PAGE 50
37              
38             typedef enum {
39             PDFMAKE_SCALE_NEAREST = 0,
40             PDFMAKE_SCALE_BILINEAR = 1,
41             PDFMAKE_SCALE_BICUBIC = 2,
42             } pdfmake_scale_mode_t;
43              
44             typedef enum {
45             PDFMAKE_ROTATE_0 = 0,
46             PDFMAKE_ROTATE_90 = 90,
47             PDFMAKE_ROTATE_180 = 180,
48             PDFMAKE_ROTATE_270 = 270,
49             } pdfmake_rotation_t;
50              
51             typedef struct pdfmake_render_opts {
52             double dpi;
53             double scale;
54             pdfmake_scale_mode_t scale_mode;
55             int antialias;
56             double flatness;
57             pdfmake_rotation_t rotation;
58             uint32_t background;
59             double clip_x, clip_y;
60             double clip_width, clip_height;
61             int use_clip;
62             int render_text;
63             int render_images;
64             int render_vectors;
65             int render_annotations;
66             int show_text_bounds;
67             int show_image_bounds;
68             int show_clip_regions;
69             } pdfmake_render_opts_t;
70              
71             typedef struct pdfmake_page_render {
72             uint32_t *pixels;
73             int width;
74             int height;
75             int stride;
76             double page_width;
77             double page_height;
78             double effective_dpi;
79             int text_objects;
80             int path_objects;
81             int image_objects;
82             double render_time_ms;
83             int error_count;
84             char error_msg[256];
85             } pdfmake_page_render_t;
86              
87             /*============================================================================
88             * Options initialization
89             *==========================================================================*/
90              
91 0           void pdfmake_render_opts_init(pdfmake_render_opts_t *opts)
92             {
93 0 0         if (!opts) return;
94 0           memset(opts, 0, sizeof(*opts));
95 0           opts->dpi = 72.0;
96 0           opts->scale = 1.0;
97 0           opts->scale_mode = PDFMAKE_SCALE_BILINEAR;
98 0           opts->antialias = 2;
99 0           opts->flatness = 1.0;
100 0           opts->rotation = PDFMAKE_ROTATE_0;
101 0           opts->background = 0xFFFFFFFFu; /* opaque white (ARGB) */
102 0           opts->render_text = 1;
103 0           opts->render_images = 1;
104 0           opts->render_vectors = 1;
105 0           opts->render_annotations = 0;
106             }
107              
108             /*============================================================================
109             * Page render size — proper implementation
110             *
111             * Computes the on-screen pixel dimensions of a page, taking MediaBox and
112             * /Rotate into account. Page width/height in PDF user space (points) are
113             * converted to pixels via:
114             *
115             * pixels = points * dpi / 72.0
116             *
117             * For 90° / 270° rotations the width and height are swapped, matching the
118             * orientation a renderer would produce.
119             *==========================================================================*/
120              
121 0           void pdfmake_page_get_render_size(
122             pdfmake_reader_t *reader,
123             int page_num,
124             double dpi,
125             int *width, int *height)
126             {
127             pdfmake_reader_page_t *page;
128             double mb[4];
129             double pts_w, pts_h, px_w, px_h;
130             int rot, w, h;
131              
132 0 0         if (width) *width = 0;
133 0 0         if (height) *height = 0;
134 0 0         if (!reader || page_num < 0) return;
    0          
135 0 0         if (dpi <= 0.0) dpi = 72.0;
136              
137 0           page = pdfmake_reader_page_at(reader, (size_t)page_num);
138 0 0         if (!page) return;
139              
140 0           mb[0] = 0; mb[1] = 0; mb[2] = 0; mb[3] = 0;
141 0 0         if (pdfmake_reader_page_media_box(reader, page, mb) != PDFMAKE_OK)
142 0           return;
143              
144 0           pts_w = mb[2] - mb[0];
145 0           pts_h = mb[3] - mb[1];
146 0 0         if (pts_w < 0) pts_w = -pts_w;
147 0 0         if (pts_h < 0) pts_h = -pts_h;
148              
149 0           rot = pdfmake_reader_page_rotation(reader, page);
150             /* Normalize to {0, 90, 180, 270}. */
151 0           rot = ((rot % 360) + 360) % 360;
152 0 0         if (rot == 90 || rot == 270) {
    0          
153 0           double tmp = pts_w;
154 0           pts_w = pts_h;
155 0           pts_h = tmp;
156             }
157              
158 0           px_w = pts_w * dpi / 72.0;
159 0           px_h = pts_h * dpi / 72.0;
160              
161             /* Round to nearest, clamp >= 1 when the page is non-empty. */
162 0           w = (int)floor(px_w + 0.5);
163 0           h = (int)floor(px_h + 0.5);
164 0 0         if (pts_w > 0.0 && w < 1) w = 1;
    0          
165 0 0         if (pts_h > 0.0 && h < 1) h = 1;
    0          
166              
167 0 0         if (width) *width = w;
168 0 0         if (height) *height = h;
169             }
170              
171             /*============================================================================
172             * Page render result lifecycle
173             *==========================================================================*/
174              
175 0           void pdfmake_page_render_free(pdfmake_page_render_t *result)
176             {
177 0 0         if (!result) return;
178 0 0         if (result->pixels) {
179 0           free(result->pixels);
180 0           result->pixels = NULL;
181             }
182 0           result->width = 0;
183 0           result->height = 0;
184 0           result->stride = 0;
185             }
186              
187             /*============================================================================
188             * Page rasterization — not yet implemented
189             *
190             * The full rasterizer (content-stream interpreter wired to the render
191             * context) has not been ported yet. These entry points return a non-OK
192             * status so callers in XS land croak with a clear "error N" rather than
193             * crashing or producing garbage. The bundle still links cleanly under
194             * PERL_DL_NONLAZY=1.
195             *==========================================================================*/
196              
197 0           static void render_result_init_failed(pdfmake_page_render_t *result,
198             const char *msg)
199             {
200 0 0         if (!result) return;
201 0           memset(result, 0, sizeof(*result));
202 0           result->error_count = 1;
203 0 0         if (msg) {
204 0           size_t n = strlen(msg);
205 0 0         if (n >= sizeof(result->error_msg))
206 0           n = sizeof(result->error_msg) - 1;
207 0           memcpy(result->error_msg, msg, n);
208 0           result->error_msg[n] = '\0';
209             }
210             }
211              
212 0           pdfmake_err_t pdfmake_render_page_to_pixels(
213             pdfmake_reader_t *reader,
214             int page_num,
215             const pdfmake_render_opts_t *opts,
216             pdfmake_page_render_t *result)
217             {
218             (void)reader; (void)page_num; (void)opts;
219 0           render_result_init_failed(result,
220             "pdfmake_render_page_to_pixels: rasterizer not implemented");
221 0           return (pdfmake_err_t)PDFMAKE_ERENDER_PAGE;
222             }
223              
224 0           pdfmake_err_t pdfmake_render_page_region(
225             pdfmake_reader_t *reader,
226             int page_num,
227             double region_x, double region_y,
228             double region_w, double region_h,
229             const pdfmake_render_opts_t *opts,
230             pdfmake_page_render_t *result)
231             {
232             (void)reader; (void)page_num;
233             (void)region_x; (void)region_y; (void)region_w; (void)region_h;
234             (void)opts;
235 0           render_result_init_failed(result,
236             "pdfmake_render_page_region: rasterizer not implemented");
237 0           return (pdfmake_err_t)PDFMAKE_ERENDER_PAGE;
238             }