1 /* Fetch a value "field" from a hash. */
2
3 #define HASH_FETCH_PV(hash,field) { \
4 SV * field_sv; \
5 SV ** field_sv_ptr = hv_fetch (hash, #field, \
6 strlen (#field), 0); \
7 if (! field_sv_ptr) { \
8 fprintf (stderr, "%s:%d: " \
9 "Field '%s' in '%s' not valid.\n", \
10 __FILE__, __LINE__, \
11 #field, #hash); \
12 return; \
13 } \
14 field_sv = * field_sv_ptr; \
15 field = SvPV (field_sv, field ## _length); \
16 }
17
18
19 typedef struct
20 {
21 SV * png_image;
22 }
23 scalar_as_image_t;
24
25 static void
perl_png_scalar_write(png_structp png,png_bytep bytes_to_write,png_size_t byte_count_to_write)26 perl_png_scalar_write (png_structp png, png_bytep bytes_to_write,
27 png_size_t byte_count_to_write)
28 {
29 scalar_as_image_t * si;
30
31 si = png_get_io_ptr (png);
32 if (si->png_image == 0) {
33 si->png_image = newSVpv ((char *) bytes_to_write, byte_count_to_write);
34 }
35 else {
36 sv_catpvn (si->png_image, (char *) bytes_to_write, byte_count_to_write);
37 }
38 }
39
40
41 void
qrpng_internal(HV * options)42 qrpng_internal (HV * options)
43 {
44 char * text;
45 unsigned text_length;
46 qr_t qr = {0};
47 qrpng_t qrpng = {0};
48 SV ** sv_ptr;
49 qrpng_status_t qrpng_status;
50 SV ** size_ptr;
51
52 /* Get the text. This is assumed to exist. */
53
54 HASH_FETCH_PV (options, text);
55
56 qr.input = text;
57 qr.input_length = text_length;
58
59 qr.level = 1;
60
61 sv_ptr = hv_fetch (options, "level", strlen ("level"), 0);
62 if (sv_ptr) {
63 qr.level = SvUV (* sv_ptr);
64 }
65 if (qr.level < 1 || qr.level > 4) {
66 croak ("Bad level %d; this is between 1 and 4", qr.level);
67 }
68
69 sv_ptr = hv_fetch (options, "version", strlen ("version"), 0);
70 if (sv_ptr) {
71 qr.version = SvUV (* sv_ptr);
72 if (qr.version < 1 || qr.version > 40) {
73 croak ("Bad version %d; this is between 1 and 40", qr.version);
74 }
75 initecc (& qr);
76 }
77 else {
78 initeccsize (& qr);
79 }
80 initframe(& qr);
81
82 qrencode (& qr);
83
84 sv_ptr = hv_fetch (options, "quiet", strlen ("quiet"), 0);
85 if (sv_ptr) {
86 SV * quiet_sv;
87 quiet_sv = * sv_ptr;
88 qrpng.quietzone = SvUV (quiet_sv);
89 }
90 else {
91 qrpng.quietzone = QUIETZONE;
92 }
93
94 sv_ptr = hv_fetch (options, "scale", strlen ("scale"), 0);
95 if (sv_ptr) {
96 SV * scale_sv;
97 scale_sv = * sv_ptr;
98 qrpng.scale = SvUV (scale_sv);
99 }
100 else {
101 qrpng.scale = 3;
102 }
103
104 qrpng_status = qrpng_make_png (& qr, & qrpng);
105
106 if (qrpng_status != qrpng_ok) {
107 croak ("bad status %d from qrpng_make_png", qrpng_status);
108 }
109 sv_ptr = hv_fetch (options, "out_sv", strlen ("out_sv"), 0);
110 if (sv_ptr) {
111
112 /* Write it as a scalar. The code is copied out of
113 Image::PNG::Libpng, but we don't depend on that. */
114
115 scalar_as_image_t si = {0};
116
117 png_set_write_fn (qrpng.png, & si, perl_png_scalar_write,
118 0 /* No flush function */);
119
120 /* Write using our function. */
121
122 png_write_png (qrpng.png, qrpng.info,
123 PNG_TRANSFORM_INVERT_MONO, NULL);
124
125 /* Put the data into %options as $options{png_data}. */
126
127 (void) hv_store (options, "png_data", strlen ("png_data"),
128 si.png_image, 0);
129 }
130 else {
131 char * out;
132 unsigned int out_length;
133 HASH_FETCH_PV (options, out);
134 qrpng.filename = out;
135 qrpng_write (& qrpng);
136 }
137 size_ptr = hv_fetch (options, "size", strlen ("size"), 0);
138 if (size_ptr) {
139 // fprintf (stderr, "%s:%d: OK baby.\n", __FILE__, __LINE__);
140 if (SvROK (* size_ptr) && SvTYPE (SvRV (* size_ptr)) < SVt_PVAV) {
141 SV * sv = SvRV (* size_ptr);
142 // fprintf (stderr, "%s:%d: OK baby.\n", __FILE__, __LINE__);
143 sv_setuv (sv, (UV) qrpng.img_size);
144 }
145 }
146 qrfree (& qr);
147 qrpng_free (& qrpng);
148 }
149