1 #ifdef _MSC_VER
2 #define NO_XSLOCKS // Needed to avoid PerlProc_setjmp/PerlProc_longjmp unresolved symbols
3 #endif
4
5 // On Debian, pngconf.h might complain about setjmp.h being loaded before PNG
6 // so we have to load png.h first
7 #ifdef HAVE_PNG
8 #include <png.h>
9 #endif
10
11 #include "EXTERN.h"
12 #include "perl.h"
13 #include "XSUB.h"
14
15 #include "ppport.h"
16
17 #include "common.c"
18 #include "image.c"
19
20 MODULE = Image::Scale PACKAGE = Image::Scale
21
22 PROTOTYPES: ENABLE
23
24 void
__init(HV * self)25 __init(HV *self)
26 PPCODE:
27 {
28 SV *pv = NEWSV(0, sizeof(image));
29 image *im = (image *)SvPVX(pv);
30
31 SvPOK_only(pv);
32
33 if ( !image_init(self, im) ) {
34 // Return undef on any errors during header reading
35 SvREFCNT_dec(pv);
36 XSRETURN_UNDEF;
37 }
38
39 XPUSHs( sv_2mortal( sv_bless(
40 newRV_noinc(pv),
41 gv_stashpv("Image::Scale::XS", 1)
42 ) ) );
43 }
44
45 int
width(HV * self)46 width(HV *self)
47 CODE:
48 {
49 image *im = (image *)SvPVX(SvRV(*(my_hv_fetch(self, "_image"))));
50
51 RETVAL = im->width;
52 }
53 OUTPUT:
54 RETVAL
55
56 int
height(HV * self)57 height(HV *self)
58 CODE:
59 {
60 image *im = (image *)SvPVX(SvRV(*(my_hv_fetch(self, "_image"))));
61
62 RETVAL = im->height;
63 }
64 OUTPUT:
65 RETVAL
66
67 int
resized_width(HV * self)68 resized_width(HV *self)
69 CODE:
70 {
71 image *im = (image *)SvPVX(SvRV(*(my_hv_fetch(self, "_image"))));
72
73 RETVAL = im->target_width;
74 }
75 OUTPUT:
76 RETVAL
77
78 int
resized_height(HV * self)79 resized_height(HV *self)
80 CODE:
81 {
82 image *im = (image *)SvPVX(SvRV(*(my_hv_fetch(self, "_image"))));
83
84 RETVAL = im->target_height;
85 }
86 OUTPUT:
87 RETVAL
88
89 int
resize(HV * self,HV * opts)90 resize(HV *self, HV *opts)
91 CODE:
92 {
93 image *im = (image *)SvPVX(SvRV(*(my_hv_fetch(self, "_image"))));
94
95 // Reset options if resize is being called multiple times
96 if (im->target_width) {
97 im->target_width = 0;
98 im->target_height = 0;
99 im->keep_aspect = 0;
100 im->orientation = im->orientation_orig;
101 im->bgcolor = 0;
102 im->memory_limit = 0;
103 im->resize_type = IMAGE_SCALE_TYPE_GD;
104 im->filter = 0;
105 }
106
107 if (my_hv_exists(opts, "width"))
108 im->target_width = SvIV(*(my_hv_fetch(opts, "width")));
109
110 if (my_hv_exists(opts, "height"))
111 im->target_height = SvIV(*(my_hv_fetch(opts, "height")));
112
113 if (!im->target_width && !im->target_height) {
114 croak("Image::Scale->resize requires at least one of height or width");
115 }
116
117 if (my_hv_exists(opts, "keep_aspect"))
118 im->keep_aspect = SvIV(*(my_hv_fetch(opts, "keep_aspect")));
119
120 if (my_hv_exists(opts, "ignore_exif")) {
121 if (SvIV(*(my_hv_fetch(opts, "ignore_exif"))) != 0)
122 im->orientation = ORIENTATION_NORMAL;
123 }
124
125 if (my_hv_exists(opts, "bgcolor"))
126 im->bgcolor = SvIV(*(my_hv_fetch(opts, "bgcolor"))) << 8 | 0xFF;
127
128 if (my_hv_exists(opts, "memory_limit"))
129 im->memory_limit = SvIV(*(my_hv_fetch(opts, "memory_limit")));
130
131 if (my_hv_exists(opts, "type"))
132 im->resize_type = SvIV(*(my_hv_fetch(opts, "type")));
133
134 if (my_hv_exists(opts, "filter")) {
135 char *filterstr = SvPVX(*(my_hv_fetch(opts, "filter")));
136 if (strEQ("Point", filterstr))
137 im->filter = PointFilter;
138 else if (strEQ("Box", filterstr))
139 im->filter = BoxFilter;
140 else if (strEQ("Triangle", filterstr))
141 im->filter = TriangleFilter;
142 else if (strEQ("Hermite", filterstr))
143 im->filter = HermiteFilter;
144 else if (strEQ("Hanning", filterstr))
145 im->filter = HanningFilter;
146 else if (strEQ("Hamming", filterstr))
147 im->filter = HammingFilter;
148 else if (strEQ("Blackman", filterstr))
149 im->filter = BlackmanFilter;
150 else if (strEQ("Gaussian", filterstr))
151 im->filter = GaussianFilter;
152 else if (strEQ("Quadratic", filterstr))
153 im->filter = QuadraticFilter;
154 else if (strEQ("Cubic", filterstr))
155 im->filter = CubicFilter;
156 else if (strEQ("Catrom", filterstr))
157 im->filter = CatromFilter;
158 else if (strEQ("Mitchell", filterstr))
159 im->filter = MitchellFilter;
160 else if (strEQ("Lanczos", filterstr))
161 im->filter = LanczosFilter;
162 else if (strEQ("Bessel", filterstr))
163 im->filter = BesselFilter;
164 else if (strEQ("Sinc", filterstr))
165 im->filter = SincFilter;
166 }
167
168 // If the image will be rotated 90 degrees, swap the target values
169 if (im->orientation >= 5) {
170 if (!im->target_height) {
171 // Only width was specified, but this will actually be the target height
172 im->target_height = im->target_width;
173 im->target_width = 0;
174 }
175 else if (!im->target_width) {
176 // Only height was specified, but this will actually be the target width
177 im->target_width = im->target_height;
178 im->target_height = 0;
179 }
180 }
181
182 if (!im->target_height) {
183 // Only width was specified
184 im->target_height = (int)((float)im->height / im->width * im->target_width);
185 if (im->target_height < 1)
186 im->target_height = 1;
187 }
188 else if (!im->target_width) {
189 // Only height was specified
190 im->target_width = (int)((float)im->width / im->height * im->target_height);
191 if (im->target_width < 1)
192 im->target_width = 1;
193 }
194
195 DEBUG_TRACE("Resizing from %d x %d -> %d x %d\n", im->width, im->height, im->target_width, im->target_height);
196
197 RETVAL = image_resize(im);
198 }
199 OUTPUT:
200 RETVAL
201
202 #ifdef HAVE_JPEG
203 void
save_jpeg(HV * self,SV * path,...)204 save_jpeg(HV *self, SV *path, ...)
205 CODE:
206 {
207 image *im = (image *)SvPVX(SvRV(*(my_hv_fetch(self, "_image"))));
208 int quality = DEFAULT_JPEG_QUALITY;
209
210 if ( !SvPOK(path) ) {
211 croak("Image::Scale->save_jpeg requires a path");
212 }
213
214 if (items == 3 && SvOK(ST(2))) {
215 quality = SvIV(ST(2));
216 }
217
218 image_jpeg_save(im, SvPVX(path), quality);
219 }
220
221 SV *
as_jpeg(HV * self,...)222 as_jpeg(HV *self, ...)
223 CODE:
224 {
225 image *im = (image *)SvPVX(SvRV(*(my_hv_fetch(self, "_image"))));
226 int quality = DEFAULT_JPEG_QUALITY;
227
228 if (items == 2 && SvOK(ST(1))) {
229 quality = SvIV(ST(1));
230 }
231
232 RETVAL = newSVpvn("", 0);
233
234 image_jpeg_to_sv(im, quality, RETVAL);
235 }
236 OUTPUT:
237 RETVAL
238
239 #endif
240
241 #ifdef HAVE_PNG
242 void
save_png(HV * self,SV * path)243 save_png(HV *self, SV *path)
244 CODE:
245 {
246 image *im = (image *)SvPVX(SvRV(*(my_hv_fetch(self, "_image"))));
247
248 if ( !SvPOK(path) ) {
249 croak("Image::Scale->save_jpeg requires a path");
250 }
251
252 image_png_save(im, SvPVX(path));
253 }
254
255 SV *
as_png(HV * self)256 as_png(HV *self)
257 CODE:
258 {
259 image *im = (image *)SvPVX(SvRV(*(my_hv_fetch(self, "_image"))));
260
261 RETVAL = newSVpvn("", 0);
262
263 image_png_to_sv(im, RETVAL);
264 }
265 OUTPUT:
266 RETVAL
267
268 #endif
269
270 void
__cleanup(HV * self,image * im)271 __cleanup(HV *self, image *im)
272 CODE:
273 {
274 image_finish(im);
275 }
276
277 SV *
jpeg_version(void)278 jpeg_version(void)
279 CODE:
280 {
281 #ifdef JPEG_VERSION
282 RETVAL = newSVpv( STRINGIFY(JPEG_VERSION), 0 );
283 #else
284 RETVAL = &PL_sv_undef;
285 #endif
286 }
287 OUTPUT:
288 RETVAL
289
290 SV *
png_version(void)291 png_version(void)
292 CODE:
293 {
294 #ifdef PNG_VERSION
295 RETVAL = newSVpv( STRINGIFY(PNG_VERSION), 0 );
296 #else
297 RETVAL = &PL_sv_undef;
298 #endif
299 }
300 OUTPUT:
301 RETVAL
302
303 SV *
gif_version(void)304 gif_version(void)
305 CODE:
306 {
307 #ifdef GIF_VERSION
308 RETVAL = newSVpv( STRINGIFY(GIF_VERSION), 0 );
309 #else
310 RETVAL = &PL_sv_undef;
311 #endif
312 }
313 OUTPUT:
314 RETVAL
315
316