File Coverage

xs/image_render.xs
Criterion Covered Total %
statement 14 156 8.9
branch 13 154 8.4
condition n/a
subroutine n/a
pod n/a
total 27 310 8.7


line stmt bran cond sub pod time code
1             MODULE = PDF::Make PACKAGE = PDF::Make::ImageRender
2             PROTOTYPES: ENABLE
3              
4             #
5             # Decoded Image Management
6             #
7              
8             SV *
9             decode_jpeg(class, bytes_sv)
10             char *class
11             SV *bytes_sv
12             PREINIT:
13             STRLEN len;
14             const uint8_t *buf;
15 0           pdfmake_decoded_image_t *img = NULL;
16             pdfmake_imgr_err_t err;
17             CODE:
18             PERL_UNUSED_VAR(class);
19 0           buf = (const uint8_t *)SvPV(bytes_sv, len);
20            
21 0           err = pdfmake_decode_jpeg_to_image(buf, (size_t)len, &img, NULL);
22 0 0         if (err != PDFMAKE_IMGR_OK || !img) {
    0          
23 0           croak("PDF::Make::ImageRender: failed to decode JPEG (error %d)", err);
24             }
25            
26 0           RETVAL = sv_newmortal();
27 0           sv_setref_pv(RETVAL, "PDF::Make::DecodedImage", (void *)img);
28 0           SvREFCNT_inc(RETVAL);
29             OUTPUT:
30             RETVAL
31              
32             SV *
33             from_raw(class, bytes_sv, width, height, colorspace, bits_per_component=8)
34             char *class
35             SV *bytes_sv
36             int width
37             int height
38             int colorspace
39             int bits_per_component
40             PREINIT:
41             STRLEN len;
42             const uint8_t *buf;
43             pdfmake_decoded_image_t *img;
44             int components;
45             CODE:
46             PERL_UNUSED_VAR(class);
47 0           buf = (const uint8_t *)SvPV(bytes_sv, len);
48            
49             /* Determine components from colorspace */
50 0           switch (colorspace) {
51 0           case PDFMAKE_RCS_GRAY: components = 1; break;
52 0           case PDFMAKE_RCS_RGB: components = 3; break;
53 0           case PDFMAKE_RCS_CMYK: components = 4; break;
54 0           case PDFMAKE_RCS_INDEXED: components = 1; break;
55 0           case PDFMAKE_RCS_LAB: components = 3; break;
56 0           default: components = 3; break;
57             }
58            
59             /* Validate data size */
60 0           size_t expected = (size_t)width * height * components;
61 0 0         if (len < expected) {
62 0           croak("PDF::Make::ImageRender: buffer too small (got %lu, need %lu)",
63             (unsigned long)len, (unsigned long)expected);
64             }
65            
66 0           img = pdfmake_decoded_image_create(NULL);
67 0 0         if (!img) {
68 0           croak("PDF::Make::ImageRender: failed to allocate image");
69             }
70            
71 0           img->width = width;
72 0           img->height = height;
73 0           img->bits_per_component = bits_per_component;
74 0           img->components = components;
75 0           img->colorspace = (pdfmake_render_cs_t)colorspace;
76 0           img->row_stride = width * components;
77 0           img->pixels_len = expected;
78            
79             /* Copy pixel data */
80 0           img->pixels = malloc(expected);
81 0 0         if (!img->pixels) {
82 0           free(img);
83 0           croak("PDF::Make::ImageRender: failed to allocate pixels");
84             }
85 0           Copy(buf, img->pixels, expected, uint8_t);
86 0           img->owns_data = 1;
87            
88 0           RETVAL = sv_newmortal();
89 0           sv_setref_pv(RETVAL, "PDF::Make::DecodedImage", (void *)img);
90 0           SvREFCNT_inc(RETVAL);
91             OUTPUT:
92             RETVAL
93              
94             void
95             DESTROY(img)
96             pdfmake_decoded_image_t *img
97             CODE:
98 0           pdfmake_decoded_image_free(img);
99              
100             MODULE = PDF::Make PACKAGE = PDF::Make::DecodedImage
101             PROTOTYPES: ENABLE
102              
103             #
104             # Decoded Image Properties
105             #
106              
107             int
108             width(self)
109             pdfmake_decoded_image_t *self
110             CODE:
111 0 0         RETVAL = self->width;
112             OUTPUT:
113             RETVAL
114              
115             int
116             height(self)
117             pdfmake_decoded_image_t *self
118             CODE:
119 0 0         RETVAL = self->height;
120             OUTPUT:
121             RETVAL
122              
123             int
124             components(self)
125             pdfmake_decoded_image_t *self
126             CODE:
127 0 0         RETVAL = self->components;
128             OUTPUT:
129             RETVAL
130              
131             int
132             colorspace(self)
133             pdfmake_decoded_image_t *self
134             CODE:
135 0 0         RETVAL = (int)self->colorspace;
136             OUTPUT:
137             RETVAL
138              
139             int
140             bits_per_component(self)
141             pdfmake_decoded_image_t *self
142             CODE:
143 0 0         RETVAL = self->bits_per_component;
144             OUTPUT:
145             RETVAL
146              
147             int
148             has_alpha(self)
149             pdfmake_decoded_image_t *self
150             CODE:
151 0 0         RETVAL = self->has_alpha;
152             OUTPUT:
153             RETVAL
154              
155             #
156             # Pixel Access
157             #
158              
159             SV *
160             get_pixel(self, x, y)
161             pdfmake_decoded_image_t *self
162             int x
163             int y
164             PREINIT:
165             uint8_t comp[4];
166             AV *av;
167             int i;
168             CODE:
169 0 0         if (x < 0 || x >= self->width || y < 0 || y >= self->height) {
    0          
    0          
    0          
170 0           XSRETURN_UNDEF;
171             }
172            
173 0           pdfmake_decoded_image_get_pixel(self, x, y, comp);
174            
175 0           av = newAV();
176 0 0         for (i = 0; i < self->components; i++) {
177 0           av_push(av, newSViv(comp[i]));
178             }
179            
180 0           RETVAL = newRV_noinc((SV *)av);
181             OUTPUT:
182             RETVAL
183              
184             UV
185             get_rgba(self, x, y)
186             pdfmake_decoded_image_t *self
187             int x
188             int y
189             CODE:
190 0 0         if (x < 0 || x >= self->width || y < 0 || y >= self->height) {
    0          
    0          
    0          
191 0           RETVAL = 0;
192             } else {
193 0           RETVAL = pdfmake_decoded_image_get_rgba(self, x, y);
194             }
195             OUTPUT:
196             RETVAL
197              
198             UV
199             get_alpha(self, x, y)
200             pdfmake_decoded_image_t *self
201             int x
202             int y
203             CODE:
204 0 0         RETVAL = pdfmake_decoded_image_get_alpha(self, x, y);
205             OUTPUT:
206             RETVAL
207              
208             #
209             # Color Space Conversion
210             #
211              
212             void
213             to_rgba(self)
214             pdfmake_decoded_image_t *self
215             PREINIT:
216             pdfmake_imgr_err_t err;
217             CODE:
218 0           err = pdfmake_decoded_image_to_rgba(self, NULL);
219 0 0         if (err != PDFMAKE_IMGR_OK) {
220 0           croak("PDF::Make::DecodedImage: to_rgba failed (error %d)", err);
221             }
222              
223             void
224             expand_indexed(self)
225             pdfmake_decoded_image_t *self
226             PREINIT:
227             pdfmake_imgr_err_t err;
228             CODE:
229 0           err = pdfmake_decoded_image_expand_indexed(self, NULL);
230 0 0         if (err != PDFMAKE_IMGR_OK) {
231 0           croak("PDF::Make::DecodedImage: expand_indexed failed (error %d)", err);
232             }
233              
234             void
235             apply_decode(self, decode_av)
236             pdfmake_decoded_image_t *self
237             AV *decode_av
238             PREINIT:
239             SSize_t i, len;
240             CODE:
241 0           len = av_len(decode_av) + 1;
242 0 0         if (len > 0) {
243 0           self->decode = malloc(len * sizeof(double));
244 0 0         if (!self->decode) {
245 0           croak("PDF::Make::DecodedImage: malloc failed");
246             }
247 0 0         for (i = 0; i < len; i++) {
248 0           SV **sv = av_fetch(decode_av, i, 0);
249 0 0         self->decode[i] = sv ? SvNV(*sv) : 0.0;
250             }
251 0           self->decode_len = len;
252 0           pdfmake_decoded_image_apply_decode(self);
253             }
254              
255             #
256             # Scaling
257             #
258              
259             SV *
260             scale(self, new_width, new_height, mode=PDFMAKE_INTERP_BILINEAR)
261             pdfmake_decoded_image_t *self
262             int new_width
263             int new_height
264             int mode
265             PREINIT:
266 0           pdfmake_decoded_image_t *scaled = NULL;
267             pdfmake_imgr_err_t err;
268             CODE:
269 0           err = pdfmake_decoded_image_scale(self, new_width, new_height,
270             (pdfmake_interp_mode_t)mode, &scaled, NULL);
271 0 0         if (err != PDFMAKE_IMGR_OK || !scaled) {
    0          
272 0           croak("PDF::Make::DecodedImage: scale failed (error %d)", err);
273             }
274            
275 0           RETVAL = sv_newmortal();
276 0           sv_setref_pv(RETVAL, "PDF::Make::DecodedImage", (void *)scaled);
277 0           SvREFCNT_inc(RETVAL);
278             OUTPUT:
279             RETVAL
280              
281             void
282             resize(self, new_width, new_height, mode=PDFMAKE_INTERP_BILINEAR)
283             pdfmake_decoded_image_t *self
284             int new_width
285             int new_height
286             int mode
287             PREINIT:
288             pdfmake_imgr_err_t err;
289             CODE:
290 0           err = pdfmake_decoded_image_resize(self, new_width, new_height,
291             (pdfmake_interp_mode_t)mode, NULL);
292 0 0         if (err != PDFMAKE_IMGR_OK) {
293 0           croak("PDF::Make::DecodedImage: resize failed (error %d)", err);
294             }
295              
296             #
297             # Palette for indexed images
298             #
299              
300             void
301             set_palette(self, palette_sv)
302             pdfmake_decoded_image_t *self
303             SV *palette_sv
304             PREINIT:
305             STRLEN len;
306             const uint8_t *buf;
307             CODE:
308 0           buf = (const uint8_t *)SvPV(palette_sv, len);
309 0 0         if (len % 3 != 0) {
310 0           croak("PDF::Make::DecodedImage: palette must be RGB triplets");
311             }
312            
313 0           self->palette_entries = len / 3;
314 0           self->palette = malloc(len);
315 0 0         if (!self->palette) {
316 0           croak("PDF::Make::DecodedImage: malloc failed");
317             }
318 0           Copy(buf, self->palette, len, uint8_t);
319              
320             #
321             # Alpha channel
322             #
323              
324             void
325             set_alpha(self, alpha_sv)
326             pdfmake_decoded_image_t *self
327             SV *alpha_sv
328             PREINIT:
329             STRLEN len;
330             const uint8_t *buf;
331             size_t expected;
332             CODE:
333 0           buf = (const uint8_t *)SvPV(alpha_sv, len);
334 0           expected = (size_t)self->width * self->height;
335            
336 0 0         if (len < expected) {
337 0           croak("PDF::Make::DecodedImage: alpha buffer too small");
338             }
339            
340 0 0         if (self->alpha && self->owns_data) {
    0          
341 0           free(self->alpha);
342             }
343            
344 0           self->alpha = malloc(expected);
345 0 0         if (!self->alpha) {
346 0           croak("PDF::Make::DecodedImage: malloc failed");
347             }
348 0           Copy(buf, self->alpha, expected, uint8_t);
349 0           self->alpha_len = expected;
350 0           self->has_alpha = 1;
351              
352             #
353             # Get RGBA buffer as bytes
354             #
355              
356             SV *
357             get_rgba_buffer(self)
358             pdfmake_decoded_image_t *self
359             PREINIT:
360             pdfmake_imgr_err_t err;
361             CODE:
362             /* Ensure RGBA is generated */
363 0 0         if (!self->rgba) {
364 0           err = pdfmake_decoded_image_to_rgba(self, NULL);
365 0 0         if (err != PDFMAKE_IMGR_OK) {
366 0           croak("PDF::Make::DecodedImage: to_rgba failed");
367             }
368             }
369            
370 0           RETVAL = newSVpvn((char *)self->rgba, self->rgba_len * sizeof(uint32_t));
371             OUTPUT:
372             RETVAL
373              
374             #
375             # Clone
376             #
377              
378             SV *
379             clone(self)
380             pdfmake_decoded_image_t *self
381             PREINIT:
382             pdfmake_decoded_image_t *cloned;
383             CODE:
384 0           cloned = pdfmake_decoded_image_clone(self, NULL);
385 0 0         if (!cloned) {
386 0           croak("PDF::Make::DecodedImage: clone failed");
387             }
388            
389 0           RETVAL = sv_newmortal();
390 0           sv_setref_pv(RETVAL, "PDF::Make::DecodedImage", (void *)cloned);
391 0           SvREFCNT_inc(RETVAL);
392             OUTPUT:
393             RETVAL
394              
395             void
396             DESTROY(self)
397             pdfmake_decoded_image_t *self
398             CODE:
399 0           pdfmake_decoded_image_free(self);
400              
401             MODULE = PDF::Make PACKAGE = PDF::Make::Render
402             PROTOTYPES: ENABLE
403              
404             #
405             # Render decoded image to context
406             #
407              
408             void
409             render_image(ctx, img)
410             pdfmake_render_ctx_t *ctx
411             pdfmake_decoded_image_t *img
412             PREINIT:
413             pdfmake_imgr_err_t err;
414             CODE:
415 0           err = pdfmake_render_decoded_image(ctx, img);
416 0 0         if (err != PDFMAKE_IMGR_OK) {
417 0           croak("PDF::Make::Render: render_image failed (error %d)", err);
418             }
419              
420             void
421             render_image_at(ctx, img, x, y, width, height)
422             pdfmake_render_ctx_t *ctx
423             pdfmake_decoded_image_t *img
424             double x
425             double y
426             double width
427             double height
428             PREINIT:
429             pdfmake_imgr_err_t err;
430             CODE:
431 0           err = pdfmake_render_decoded_image_at(ctx, img, x, y, width, height);
432 0 0         if (err != PDFMAKE_IMGR_OK) {
433 0           croak("PDF::Make::Render: render_image_at failed (error %d)", err);
434             }
435              
436             void
437             blit_rgba(ctx, rgba_sv, img_w, img_h, dst_x, dst_y)
438             pdfmake_render_ctx_t *ctx
439             SV *rgba_sv
440             int img_w
441             int img_h
442             int dst_x
443             int dst_y
444             PREINIT:
445             STRLEN len;
446             const uint32_t *rgba;
447             CODE:
448 0           rgba = (const uint32_t *)SvPV(rgba_sv, len);
449 0           pdfmake_render_blit_rgba(ctx, rgba, img_w, img_h, dst_x, dst_y);
450              
451             void
452             blit_scaled(ctx, rgba_sv, img_w, img_h, dst_x, dst_y, dst_w, dst_h, mode=PDFMAKE_INTERP_BILINEAR)
453             pdfmake_render_ctx_t *ctx
454             SV *rgba_sv
455             int img_w
456             int img_h
457             int dst_x
458             int dst_y
459             int dst_w
460             int dst_h
461             int mode
462             PREINIT:
463             STRLEN len;
464             const uint32_t *rgba;
465             CODE:
466 0           rgba = (const uint32_t *)SvPV(rgba_sv, len);
467 0           pdfmake_render_blit_scaled(ctx, rgba, img_w, img_h, dst_x, dst_y,
468             dst_w, dst_h, (pdfmake_interp_mode_t)mode);
469              
470             MODULE = PDF::Make PACKAGE = PDF::Make::ColorConvert
471             PROTOTYPES: ENABLE
472              
473             #
474             # Standalone color conversion utilities
475             #
476              
477             void
478             cmyk_to_rgb(c, m, y, k)
479             int c
480             int m
481             int y
482             int k
483             PREINIT:
484             uint8_t r, g, b;
485             PPCODE:
486 0           pdfmake_cmyk_to_rgb8(c, m, y, k, &r, &g, &b);
487 0 0         EXTEND(SP, 3);
488 0           PUSHs(sv_2mortal(newSViv(r)));
489 0           PUSHs(sv_2mortal(newSViv(g)));
490 0           PUSHs(sv_2mortal(newSViv(b)));
491              
492             void
493             lab_to_rgb(L, a, b_val)
494             double L
495             double a
496             double b_val
497             PREINIT:
498             uint8_t r, g, b;
499             PPCODE:
500 0           pdfmake_lab_to_rgb8(L, a, b_val, &r, &g, &b);
501 0 0         EXTEND(SP, 3);
502 0           PUSHs(sv_2mortal(newSViv(r)));
503 0           PUSHs(sv_2mortal(newSViv(g)));
504 0           PUSHs(sv_2mortal(newSViv(b)));
505              
506             #
507             # Interpolation mode constants
508             #
509              
510             int
511             INTERP_NEAREST()
512             CODE:
513 0 0         RETVAL = PDFMAKE_INTERP_NEAREST;
514             OUTPUT:
515             RETVAL
516              
517             int
518             INTERP_BILINEAR()
519             CODE:
520 0 0         RETVAL = PDFMAKE_INTERP_BILINEAR;
521             OUTPUT:
522             RETVAL
523              
524             int
525             INTERP_BICUBIC()
526             CODE:
527 0 0         RETVAL = PDFMAKE_INTERP_BICUBIC;
528             OUTPUT:
529             RETVAL
530              
531             #
532             # Colorspace constants
533             #
534              
535             int
536             CS_GRAY()
537             CODE:
538 0 0         RETVAL = PDFMAKE_RCS_GRAY;
539             OUTPUT:
540             RETVAL
541              
542             int
543             CS_RGB()
544             CODE:
545 0 0         RETVAL = PDFMAKE_RCS_RGB;
546             OUTPUT:
547             RETVAL
548              
549             int
550             CS_CMYK()
551             CODE:
552 0 0         RETVAL = PDFMAKE_RCS_CMYK;
553             OUTPUT:
554             RETVAL
555              
556             int
557             CS_INDEXED()
558             CODE:
559 0 0         RETVAL = PDFMAKE_RCS_INDEXED;
560             OUTPUT:
561             RETVAL
562              
563             int
564             CS_LAB()
565             CODE:
566 0 0         RETVAL = PDFMAKE_RCS_LAB;
567             OUTPUT:
568             RETVAL
569              
570             BOOT:
571             {
572 90           HV *stash = gv_stashpv("PDF::Make::ImageRender", GV_ADD);
573 90 50         PDFMAKE_REGISTER_GETTER(stash, "width", pdfmake_decoded_image_t, width, PDFMAKE_FIELD_INT);
    0          
574 90 50         PDFMAKE_REGISTER_GETTER(stash, "height", pdfmake_decoded_image_t, height, PDFMAKE_FIELD_INT);
    0          
575 90 50         PDFMAKE_REGISTER_GETTER(stash, "components", pdfmake_decoded_image_t, components, PDFMAKE_FIELD_INT);
    0          
576 90 50         PDFMAKE_REGISTER_GETTER(stash, "bits_per_component", pdfmake_decoded_image_t, bits_per_component, PDFMAKE_FIELD_INT);
    0          
577 90 50         PDFMAKE_REGISTER_GETTER(stash, "has_alpha", pdfmake_decoded_image_t, has_alpha, PDFMAKE_FIELD_INT);
    0          
578 90 50         PDFMAKE_REGISTER_CONST(stash, "INTERP_NEAREST", PDFMAKE_INTERP_NEAREST);
    0          
579 90 50         PDFMAKE_REGISTER_CONST(stash, "INTERP_BILINEAR", PDFMAKE_INTERP_BILINEAR);
    0          
580 90 50         PDFMAKE_REGISTER_CONST(stash, "INTERP_BICUBIC", PDFMAKE_INTERP_BICUBIC);
    0          
581 90 50         PDFMAKE_REGISTER_CONST(stash, "RCS_GRAY", PDFMAKE_RCS_GRAY);
    0          
582 90 50         PDFMAKE_REGISTER_CONST(stash, "RCS_RGB", PDFMAKE_RCS_RGB);
    0          
583 90 50         PDFMAKE_REGISTER_CONST(stash, "RCS_CMYK", PDFMAKE_RCS_CMYK);
    0          
584 90 50         PDFMAKE_REGISTER_CONST(stash, "RCS_INDEXED", PDFMAKE_RCS_INDEXED);
    0          
585 90 50         PDFMAKE_REGISTER_CONST(stash, "RCS_LAB", PDFMAKE_RCS_LAB);
    0          
586             }