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