[rt #73359] un-TODO the test for FT1
[imager.git] / Imager.xs
CommitLineData
b13a3ddb 1#define PERL_NO_GET_CONTEXT
02d1d628
AMH
2#ifdef __cplusplus
3extern "C" {
4#endif
5#include "EXTERN.h"
6#include "perl.h"
7#include "XSUB.h"
7a6cd05b
TC
8#define NEED_newRV_noinc
9#define NEED_sv_2pv_nolen
f35d1231 10#define NEED_sv_2pvbyte
02d1d628
AMH
11#include "ppport.h"
12#ifdef __cplusplus
92bda632 13}
02d1d628
AMH
14#endif
15
a8652edf
TC
16#define i_int_hlines_testing() 1
17
92bda632 18#include "imager.h"
02d1d628
AMH
19#include "feat.h"
20#include "dynaload.h"
21#include "regmach.h"
92bda632 22#include "imextdef.h"
ec6d8908 23#include "imextpltypes.h"
52d990d6 24#include "imperlio.h"
4498c8bd 25#include <float.h>
a8652edf 26
92bda632
TC
27#if i_int_hlines_testing()
28#include "imageri.h"
02d1d628
AMH
29#endif
30
92bda632 31#include "imperl.h"
faa9b3e7 32
31a13473
TC
33/*
34
35Context object management
36
37*/
38
39typedef im_context_t Imager__Context;
40
41#define im_context_DESTROY(ctx) im_context_refdec((ctx), "DESTROY")
42
43#ifdef PERL_IMPLICIT_CONTEXT
44
45#define MY_CXT_KEY "Imager::_context" XS_VERSION
46
47typedef struct {
48 im_context_t ctx;
49} my_cxt_t;
50
51START_MY_CXT
52
53im_context_t fallback_context;
54
55static void
56start_context(pTHX) {
57 dMY_CXT;
58 MY_CXT.ctx = im_context_new();
59 sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
60
61 /* Ideally we'd free this reference, but the error message memory
62 was never released on exit, so the associated memory here is reasonable
63 to keep.
64 With logging enabled we always need at least one context, since
65 objects may be released fairly late and attempt to get the log file.
66 */
67 im_context_refinc(MY_CXT.ctx, "start_context");
68 fallback_context = MY_CXT.ctx;
69}
70
71static im_context_t
72perl_get_context(void) {
73 dTHX;
74 dMY_CXT;
75
76 return MY_CXT.ctx ? MY_CXT.ctx : fallback_context;
77}
78
79#else
80
81static im_context_t perl_context;
82
83static void
84start_context(pTHX) {
85 perl_context = im_context_new();
86 im_context_refinc(perl_context, "start_context");
87}
cf8c77ae
TC
88
89static im_context_t
90perl_get_context(void) {
31a13473 91 return perl_context;
cf8c77ae
TC
92}
93
31a13473
TC
94#endif
95
6a9807e8
TC
96/* used to represent channel lists parameters */
97typedef struct i_channel_list_tag {
98 int *channels;
99 int count;
100} i_channel_list;
101
48b9a7bf
TC
102typedef struct {
103 size_t count;
104 const i_sample_t *samples;
105} i_sample_list;
106
107typedef struct {
108 size_t count;
109 const i_fsample_t *samples;
110} i_fsample_list;
111
ebe9b189
TC
112/*
113
114Allocate memory that will be discarded when mortals are discarded.
115
116*/
117
118static void *
119malloc_temp(pTHX_ size_t size) {
120 SV *sv = sv_2mortal(newSV(size));
121
122 return SvPVX(sv);
123}
124
0aaa8b4d
TC
125static void *
126calloc_temp(pTHX_ size_t size) {
127 void *result = malloc_temp(aTHX_ size);
128 memset(result, 0, size);
129
130 return result;
131}
132
19e9591b 133/* for use with the T_AVARRAY typemap */
0aaa8b4d
TC
134#define doublePtr(size) ((double *)calloc_temp(aTHX_ sizeof(double) * (size)))
135#define SvDouble(sv, pname) (SvNV(sv))
136
137#define intPtr(size) ((int *)calloc_temp(aTHX_ sizeof(int) * (size)))
138#define SvInt(sv, pname) (SvIV(sv))
139
140#define i_img_dimPtr(size) ((i_img_dim *)calloc_temp(aTHX_ sizeof(i_img_dim) * (size)))
141#define SvI_img_dim(sv, pname) (SvIV(sv))
19e9591b 142
0aaa8b4d
TC
143#define i_colorPtr(size) ((i_color *)calloc_temp(aTHX_ sizeof(i_color *) * (size)))
144
145#define SvI_color(sv, pname) S_sv_to_i_color(aTHX_ sv, pname)
146
147static i_color
148S_sv_to_i_color(pTHX_ SV *sv, const char *pname) {
149 if (!sv_derived_from(sv, "Imager::Color")) {
150 croak("%s: not a color object");
151 }
152 return *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
153}
19e9591b 154
b33c08f8
TC
155/* These functions are all shared - then comes platform dependant code */
156static int getstr(void *hv_t,char *key,char **store) {
b13a3ddb 157 dTHX;
b33c08f8
TC
158 SV** svpp;
159 HV* hv=(HV*)hv_t;
160
8d14daab 161 mm_log((1,"getstr(hv_t %p, key %s, store %p)\n",hv_t,key,store));
b33c08f8
TC
162
163 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
164
165 svpp=hv_fetch(hv, key, strlen(key), 0);
166 *store=SvPV(*svpp, PL_na );
167
168 return 1;
169}
170
171static int getint(void *hv_t,char *key,int *store) {
b13a3ddb 172 dTHX;
b33c08f8
TC
173 SV** svpp;
174 HV* hv=(HV*)hv_t;
175
8d14daab 176 mm_log((1,"getint(hv_t %p, key %s, store %p)\n",hv_t,key,store));
b33c08f8
TC
177
178 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
179
180 svpp=hv_fetch(hv, key, strlen(key), 0);
181 *store=(int)SvIV(*svpp);
182 return 1;
183}
184
185static int getdouble(void *hv_t,char* key,double *store) {
b13a3ddb 186 dTHX;
b33c08f8
TC
187 SV** svpp;
188 HV* hv=(HV*)hv_t;
189
8d14daab 190 mm_log((1,"getdouble(hv_t %p, key %s, store %p)\n",hv_t,key,store));
b33c08f8
TC
191
192 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
193 svpp=hv_fetch(hv, key, strlen(key), 0);
8d14daab 194 *store=(double)SvNV(*svpp);
b33c08f8
TC
195 return 1;
196}
197
198static int getvoid(void *hv_t,char* key,void **store) {
b13a3ddb 199 dTHX;
b33c08f8
TC
200 SV** svpp;
201 HV* hv=(HV*)hv_t;
202
8d14daab 203 mm_log((1,"getvoid(hv_t %p, key %s, store %p)\n",hv_t,key,store));
b33c08f8
TC
204
205 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
206
207 svpp=hv_fetch(hv, key, strlen(key), 0);
208 *store = INT2PTR(void*, SvIV(*svpp));
209
210 return 1;
211}
212
213static int getobj(void *hv_t,char *key,char *type,void **store) {
b13a3ddb 214 dTHX;
b33c08f8
TC
215 SV** svpp;
216 HV* hv=(HV*)hv_t;
217
8d14daab 218 mm_log((1,"getobj(hv_t %p, key %s,type %s, store %p)\n",hv_t,key,type,store));
b33c08f8
TC
219
220 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
221
222 svpp=hv_fetch(hv, key, strlen(key), 0);
223
224 if (sv_derived_from(*svpp,type)) {
225 IV tmp = SvIV((SV*)SvRV(*svpp));
226 *store = INT2PTR(void*, tmp);
227 } else {
228 mm_log((1,"getobj: key exists in hash but is not of correct type"));
229 return 0;
230 }
231
232 return 1;
233}
234
235UTIL_table_t i_UTIL_table={getstr,getint,getdouble,getvoid,getobj};
4dfa5522
AMH
236
237void my_SvREFCNT_dec(void *p) {
b13a3ddb 238 dTHX;
4dfa5522
AMH
239 SvREFCNT_dec((SV*)p);
240}
241
7f882a01 242
b33c08f8 243static void
bf1573f9 244i_log_entry(char *string, int level) {
b7506a07 245 mm_log((level, "%s", string));
7f882a01
AMH
246}
247
5e9a7fbd
TC
248static SV *
249make_i_color_sv(pTHX_ const i_color *c) {
250 SV *sv;
251 i_color *col = mymalloc(sizeof(i_color));
252 *col = *c;
253 sv = sv_newmortal();
254 sv_setref_pv(sv, "Imager::Color", (void *)col);
255
256 return sv;
257}
7f882a01 258
10461f9a
TC
259#define CBDATA_BUFSIZE 8192
260
261struct cbdata {
262 /* the SVs we use to call back to Perl */
263 SV *writecb;
264 SV *readcb;
265 SV *seekcb;
266 SV *closecb;
10461f9a
TC
267};
268
6d5c85a2
TC
269static ssize_t
270call_reader(struct cbdata *cbd, void *buf, size_t size,
271 size_t maxread) {
b13a3ddb 272 dTHX;
10461f9a
TC
273 int count;
274 int result;
275 SV *data;
276 dSP;
277
9d5ff8a6
TC
278 if (!SvOK(cbd->readcb)) {
279 mm_log((1, "read callback called but no readcb supplied\n"));
280 i_push_error(0, "read callback called but no readcb supplied");
10461f9a 281 return -1;
9d5ff8a6 282 }
10461f9a
TC
283
284 ENTER;
285 SAVETMPS;
286 EXTEND(SP, 2);
287 PUSHMARK(SP);
288 PUSHs(sv_2mortal(newSViv(size)));
289 PUSHs(sv_2mortal(newSViv(maxread)));
290 PUTBACK;
291
292 count = perl_call_sv(cbd->readcb, G_SCALAR);
293
294 SPAGAIN;
295
296 if (count != 1)
297 croak("Result of perl_call_sv(..., G_SCALAR) != 1");
298
299 data = POPs;
300
301 if (SvOK(data)) {
302 STRLEN len;
6d5c85a2 303 char *ptr = SvPVbyte(data, len);
10461f9a 304 if (len > maxread)
6d5c85a2
TC
305 croak("Too much data returned in reader callback (wanted %d, got %d, expected %d)",
306 (int)size, (int)len, (int)maxread);
10461f9a
TC
307
308 memcpy(buf, ptr, len);
309 result = len;
310 }
311 else {
312 result = -1;
313 }
314
315 PUTBACK;
316 FREETMPS;
317 LEAVE;
318
319 return result;
320}
321
6d5c85a2
TC
322static off_t
323io_seeker(void *p, off_t offset, int whence) {
b13a3ddb 324 dTHX;
10461f9a
TC
325 struct cbdata *cbd = p;
326 int count;
327 off_t result;
328 dSP;
329
9d5ff8a6
TC
330 if (!SvOK(cbd->seekcb)) {
331 mm_log((1, "seek callback called but no seekcb supplied\n"));
332 i_push_error(0, "seek callback called but no seekcb supplied");
10461f9a 333 return -1;
9d5ff8a6 334 }
10461f9a 335
10461f9a
TC
336 ENTER;
337 SAVETMPS;
338 EXTEND(SP, 2);
339 PUSHMARK(SP);
340 PUSHs(sv_2mortal(newSViv(offset)));
341 PUSHs(sv_2mortal(newSViv(whence)));
342 PUTBACK;
343
344 count = perl_call_sv(cbd->seekcb, G_SCALAR);
345
346 SPAGAIN;
347
348 if (count != 1)
349 croak("Result of perl_call_sv(..., G_SCALAR) != 1");
350
351 result = POPi;
352
353 PUTBACK;
354 FREETMPS;
355 LEAVE;
356
357 return result;
358}
359
6d5c85a2
TC
360static ssize_t
361io_writer(void *p, void const *data, size_t size) {
b13a3ddb 362 dTHX;
10461f9a 363 struct cbdata *cbd = p;
6d5c85a2
TC
364 I32 count;
365 SV *sv;
366 dSP;
367 bool success;
10461f9a 368
9d5ff8a6
TC
369 if (!SvOK(cbd->writecb)) {
370 mm_log((1, "write callback called but no writecb supplied\n"));
371 i_push_error(0, "write callback called but no writecb supplied");
6d5c85a2 372 return -1;
9d5ff8a6 373 }
6d5c85a2
TC
374
375 ENTER;
376 SAVETMPS;
377 EXTEND(SP, 1);
378 PUSHMARK(SP);
379 PUSHs(sv_2mortal(newSVpv((char *)data, size)));
380 PUTBACK;
381
382 count = perl_call_sv(cbd->writecb, G_SCALAR);
383
384 SPAGAIN;
385 if (count != 1)
386 croak("Result of perl_call_sv(..., G_SCALAR) != 1");
387
388 sv = POPs;
389 success = SvTRUE(sv);
390
391
392 PUTBACK;
393 FREETMPS;
394 LEAVE;
395
396 return success ? size : -1;
10461f9a
TC
397}
398
1f6c1c10
TC
399static ssize_t
400io_reader(void *p, void *data, size_t size) {
10461f9a 401 struct cbdata *cbd = p;
10461f9a 402
6d5c85a2 403 return call_reader(cbd, data, size, size);
10461f9a
TC
404}
405
2b405c9e 406static int io_closer(void *p) {
b13a3ddb 407 dTHX;
10461f9a 408 struct cbdata *cbd = p;
6d5c85a2 409 int success = 1;
10461f9a
TC
410
411 if (SvOK(cbd->closecb)) {
412 dSP;
6d5c85a2
TC
413 I32 count;
414 SV *sv;
10461f9a
TC
415
416 ENTER;
417 SAVETMPS;
418 PUSHMARK(SP);
419 PUTBACK;
420
6d5c85a2 421 count = perl_call_sv(cbd->closecb, G_SCALAR);
10461f9a
TC
422
423 SPAGAIN;
6d5c85a2
TC
424
425 sv = POPs;
426 success = SvTRUE(sv);
427
10461f9a
TC
428 PUTBACK;
429 FREETMPS;
430 LEAVE;
431 }
2b405c9e 432
6d5c85a2 433 return success ? 0 : -1;
10461f9a
TC
434}
435
436static void io_destroyer(void *p) {
b13a3ddb 437 dTHX;
10461f9a
TC
438 struct cbdata *cbd = p;
439
440 SvREFCNT_dec(cbd->writecb);
441 SvREFCNT_dec(cbd->readcb);
442 SvREFCNT_dec(cbd->seekcb);
443 SvREFCNT_dec(cbd->closecb);
a4168bea 444 myfree(cbd);
10461f9a
TC
445}
446
6d5c85a2
TC
447static i_io_glue_t *
448do_io_new_buffer(pTHX_ SV *data_sv) {
449 const char *data;
450 STRLEN length;
451
452 data = SvPVbyte(data_sv, length);
453 SvREFCNT_inc(data_sv);
454 return io_new_buffer(data, length, my_SvREFCNT_dec, data_sv);
455}
456
9d5ff8a6
TC
457static const char *
458describe_sv(SV *sv) {
459 if (SvOK(sv)) {
460 if (SvROK(sv)) {
461 svtype type = SvTYPE(SvRV(sv));
462 switch (type) {
463 case SVt_PVCV: return "CV";
464 case SVt_PVGV: return "GV";
465 case SVt_PVLV: return "LV";
466 default: return "some reference";
467 }
468 }
469 else {
470 return "non-reference scalar";
471 }
472 }
473 else {
474 return "undef";
475 }
476}
477
6d5c85a2
TC
478static i_io_glue_t *
479do_io_new_cb(pTHX_ SV *writecb, SV *readcb, SV *seekcb, SV *closecb) {
480 struct cbdata *cbd;
481
482 cbd = mymalloc(sizeof(struct cbdata));
483 cbd->writecb = newSVsv(writecb);
484 cbd->readcb = newSVsv(readcb);
485 cbd->seekcb = newSVsv(seekcb);
486 cbd->closecb = newSVsv(closecb);
487
9d5ff8a6
TC
488 mm_log((1, "do_io_new_cb(writecb %p (%s), readcb %p (%s), seekcb %p (%s), closecb %p (%s))\n", writecb, describe_sv(writecb), readcb, describe_sv(readcb), seekcb, describe_sv(seekcb), closecb, describe_sv(closecb)));
489
6d5c85a2
TC
490 return io_new_cb(cbd, io_reader, io_writer, io_seeker, io_closer,
491 io_destroyer);
492}
493
02d1d628
AMH
494struct value_name {
495 char *name;
496 int value;
497};
498static int lookup_name(struct value_name *names, int count, char *name, int def_value)
499{
500 int i;
501 for (i = 0; i < count; ++i)
502 if (strEQ(names[i].name, name))
503 return names[i].value;
504
505 return def_value;
506}
507static struct value_name transp_names[] =
508{
509 { "none", tr_none },
510 { "threshold", tr_threshold },
511 { "errdiff", tr_errdiff },
512 { "ordered", tr_ordered, },
513};
514
515static struct value_name make_color_names[] =
516{
517 { "none", mc_none, },
518 { "webmap", mc_web_map, },
519 { "addi", mc_addi, },
97c4effc 520 { "mediancut", mc_median_cut, },
9c106321
TC
521 { "mono", mc_mono, },
522 { "monochrome", mc_mono, },
5e9a7fbd
TC
523 { "gray", mc_gray, },
524 { "gray4", mc_gray4, },
525 { "gray16", mc_gray16, },
02d1d628
AMH
526};
527
528static struct value_name translate_names[] =
529{
02d1d628 530 { "giflib", pt_giflib, },
02d1d628
AMH
531 { "closest", pt_closest, },
532 { "perturb", pt_perturb, },
533 { "errdiff", pt_errdiff, },
534};
535
536static struct value_name errdiff_names[] =
537{
538 { "floyd", ed_floyd, },
539 { "jarvis", ed_jarvis, },
540 { "stucki", ed_stucki, },
541 { "custom", ed_custom, },
542};
543
544static struct value_name orddith_names[] =
545{
546 { "random", od_random, },
547 { "dot8", od_dot8, },
548 { "dot4", od_dot4, },
549 { "hline", od_hline, },
550 { "vline", od_vline, },
551 { "/line", od_slashline, },
552 { "slashline", od_slashline, },
553 { "\\line", od_backline, },
554 { "backline", od_backline, },
e7d4ea82 555 { "tiny", od_tiny, },
02d1d628
AMH
556 { "custom", od_custom, },
557};
558
559/* look through the hash for quantization options */
ec6d8908
TC
560static void
561ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
02d1d628
AMH
562{
563 /*** POSSIBLY BROKEN: do I need to unref the SV from hv_fetch ***/
564 SV **sv;
565 int i;
566 STRLEN len;
567 char *str;
568
46a04ceb
TC
569 quant->mc_colors = mymalloc(quant->mc_size * sizeof(i_color));
570
02d1d628
AMH
571 sv = hv_fetch(hv, "transp", 6, 0);
572 if (sv && *sv && (str = SvPV(*sv, len))) {
573 quant->transp =
574 lookup_name(transp_names, sizeof(transp_names)/sizeof(*transp_names),
575 str, tr_none);
576 if (quant->transp != tr_none) {
577 quant->tr_threshold = 127;
578 sv = hv_fetch(hv, "tr_threshold", 12, 0);
579 if (sv && *sv)
580 quant->tr_threshold = SvIV(*sv);
581 }
582 if (quant->transp == tr_errdiff) {
583 sv = hv_fetch(hv, "tr_errdiff", 10, 0);
584 if (sv && *sv && (str = SvPV(*sv, len)))
585 quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
586 }
587 if (quant->transp == tr_ordered) {
e7d4ea82 588 quant->tr_orddith = od_tiny;
02d1d628
AMH
589 sv = hv_fetch(hv, "tr_orddith", 10, 0);
590 if (sv && *sv && (str = SvPV(*sv, len)))
591 quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random);
592
593 if (quant->tr_orddith == od_custom) {
594 sv = hv_fetch(hv, "tr_map", 6, 0);
595 if (sv && *sv && SvTYPE(SvRV(*sv)) == SVt_PVAV) {
596 AV *av = (AV*)SvRV(*sv);
597 len = av_len(av) + 1;
598 if (len > sizeof(quant->tr_custom))
599 len = sizeof(quant->tr_custom);
600 for (i = 0; i < len; ++i) {
601 SV **sv2 = av_fetch(av, i, 0);
602 if (sv2 && *sv2) {
603 quant->tr_custom[i] = SvIV(*sv2);
604 }
605 }
606 while (i < sizeof(quant->tr_custom))
607 quant->tr_custom[i++] = 0;
608 }
609 }
610 }
611 }
0348fe07 612 quant->make_colors = mc_median_cut;
02d1d628
AMH
613 sv = hv_fetch(hv, "make_colors", 11, 0);
614 if (sv && *sv && (str = SvPV(*sv, len))) {
615 quant->make_colors =
74de8638 616 lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut);
02d1d628
AMH
617 }
618 sv = hv_fetch(hv, "colors", 6, 0);
619 if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) {
620 /* needs to be an array of Imager::Color
621 note that the caller allocates the mc_color array and sets mc_size
622 to it's size */
623 AV *av = (AV *)SvRV(*sv);
624 quant->mc_count = av_len(av)+1;
625 if (quant->mc_count > quant->mc_size)
626 quant->mc_count = quant->mc_size;
627 for (i = 0; i < quant->mc_count; ++i) {
628 SV **sv1 = av_fetch(av, i, 0);
629 if (sv1 && *sv1 && SvROK(*sv1) && sv_derived_from(*sv1, "Imager::Color")) {
4c4c2ffd 630 i_color *col = INT2PTR(i_color *, SvIV((SV*)SvRV(*sv1)));
02d1d628
AMH
631 quant->mc_colors[i] = *col;
632 }
633 }
634 }
635 sv = hv_fetch(hv, "max_colors", 10, 0);
636 if (sv && *sv) {
637 i = SvIV(*sv);
638 if (i <= quant->mc_size && i >= quant->mc_count)
639 quant->mc_size = i;
640 }
641
642 quant->translate = pt_closest;
643 sv = hv_fetch(hv, "translate", 9, 0);
644 if (sv && *sv && (str = SvPV(*sv, len))) {
645 quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest);
646 }
647 sv = hv_fetch(hv, "errdiff", 7, 0);
648 if (sv && *sv && (str = SvPV(*sv, len))) {
649 quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
650 }
651 if (quant->translate == pt_errdiff && quant->errdiff == ed_custom) {
652 /* get the error diffusion map */
653 sv = hv_fetch(hv, "errdiff_width", 13, 0);
654 if (sv && *sv)
655 quant->ed_width = SvIV(*sv);
656 sv = hv_fetch(hv, "errdiff_height", 14, 0);
657 if (sv && *sv)
658 quant->ed_height = SvIV(*sv);
659 sv = hv_fetch(hv, "errdiff_orig", 12, 0);
660 if (sv && *sv)
661 quant->ed_orig = SvIV(*sv);
662 if (quant->ed_width > 0 && quant->ed_height > 0) {
663 int sum = 0;
664 quant->ed_map = mymalloc(sizeof(int)*quant->ed_width*quant->ed_height);
665 sv = hv_fetch(hv, "errdiff_map", 11, 0);
666 if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) {
667 AV *av = (AV*)SvRV(*sv);
668 len = av_len(av) + 1;
669 if (len > quant->ed_width * quant->ed_height)
670 len = quant->ed_width * quant->ed_height;
671 for (i = 0; i < len; ++i) {
672 SV **sv2 = av_fetch(av, i, 0);
673 if (sv2 && *sv2) {
674 quant->ed_map[i] = SvIV(*sv2);
675 sum += quant->ed_map[i];
676 }
677 }
678 }
679 if (!sum) {
680 /* broken map */
681 myfree(quant->ed_map);
682 quant->ed_map = 0;
683 quant->errdiff = ed_floyd;
684 }
685 }
686 }
687 sv = hv_fetch(hv, "perturb", 7, 0);
688 if (sv && *sv)
689 quant->perturb = SvIV(*sv);
690}
691
ec6d8908
TC
692static void
693ip_cleanup_quant_opts(pTHX_ i_quantize *quant) {
46a04ceb
TC
694 myfree(quant->mc_colors);
695 if (quant->ed_map)
696 myfree(quant->ed_map);
697}
698
02d1d628 699/* copies the color map from the hv into the colors member of the HV */
ec6d8908
TC
700static void
701ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) {
02d1d628
AMH
702 SV **sv;
703 AV *av;
704 int i;
705 SV *work;
706
707 sv = hv_fetch(hv, "colors", 6, 0);
708 if (!sv || !*sv || !SvROK(*sv) || SvTYPE(SvRV(*sv)) != SVt_PVAV) {
5c0d0ddf
TC
709 /* nothing to do */
710 return;
02d1d628 711 }
5c0d0ddf
TC
712
713 av = (AV *)SvRV(*sv);
714 av_clear(av);
02d1d628
AMH
715 av_extend(av, quant->mc_count+1);
716 for (i = 0; i < quant->mc_count; ++i) {
717 i_color *in = quant->mc_colors+i;
718 Imager__Color c = ICL_new_internal(in->rgb.r, in->rgb.g, in->rgb.b, 255);
719 work = sv_newmortal();
720 sv_setref_pv(work, "Imager::Color", (void *)c);
721 SvREFCNT_inc(work);
5c0d0ddf 722 av_push(av, work);
02d1d628
AMH
723 }
724}
725
f1ac5027 726/* loads the segments of a fountain fill into an array */
b33c08f8 727static i_fountain_seg *
b13a3ddb 728load_fount_segs(pTHX_ AV *asegs, int *count) {
f1ac5027
TC
729 /* Each element of segs must contain:
730 [ start, middle, end, c0, c1, segtype, colortrans ]
731 start, middle, end are doubles from 0 to 1
732 c0, c1 are Imager::Color::Float or Imager::Color objects
733 segtype, colortrans are ints
734 */
735 int i, j;
736 AV *aseg;
f1ac5027
TC
737 i_fountain_seg *segs;
738 double work[3];
739 int worki[2];
740
741 *count = av_len(asegs)+1;
742 if (*count < 1)
743 croak("i_fountain must have at least one segment");
744 segs = mymalloc(sizeof(i_fountain_seg) * *count);
745 for(i = 0; i < *count; i++) {
746 SV **sv1 = av_fetch(asegs, i, 0);
747 if (!sv1 || !*sv1 || !SvROK(*sv1)
748 || SvTYPE(SvRV(*sv1)) != SVt_PVAV) {
749 myfree(segs);
750 croak("i_fountain: segs must be an arrayref of arrayrefs");
751 }
752 aseg = (AV *)SvRV(*sv1);
753 if (av_len(aseg) != 7-1) {
754 myfree(segs);
755 croak("i_fountain: a segment must have 7 members");
756 }
757 for (j = 0; j < 3; ++j) {
758 SV **sv2 = av_fetch(aseg, j, 0);
759 if (!sv2 || !*sv2) {
760 myfree(segs);
761 croak("i_fountain: XS error");
762 }
763 work[j] = SvNV(*sv2);
764 }
765 segs[i].start = work[0];
766 segs[i].middle = work[1];
767 segs[i].end = work[2];
768 for (j = 0; j < 2; ++j) {
769 SV **sv3 = av_fetch(aseg, 3+j, 0);
770 if (!sv3 || !*sv3 || !SvROK(*sv3) ||
771 (!sv_derived_from(*sv3, "Imager::Color")
772 && !sv_derived_from(*sv3, "Imager::Color::Float"))) {
773 myfree(segs);
774 croak("i_fountain: segs must contain colors in elements 3 and 4");
775 }
776 if (sv_derived_from(*sv3, "Imager::Color::Float")) {
4c4c2ffd 777 segs[i].c[j] = *INT2PTR(i_fcolor *, SvIV((SV *)SvRV(*sv3)));
f1ac5027
TC
778 }
779 else {
4c4c2ffd 780 i_color c = *INT2PTR(i_color *, SvIV((SV *)SvRV(*sv3)));
f1ac5027
TC
781 int ch;
782 for (ch = 0; ch < MAXCHANNELS; ++ch) {
783 segs[i].c[j].channel[ch] = c.channel[ch] / 255.0;
784 }
785 }
786 }
787 for (j = 0; j < 2; ++j) {
788 SV **sv2 = av_fetch(aseg, j+5, 0);
789 if (!sv2 || !*sv2) {
790 myfree(segs);
791 croak("i_fountain: XS error");
792 }
793 worki[j] = SvIV(*sv2);
794 }
795 segs[i].type = worki[0];
796 segs[i].color = worki[1];
797 }
798
799 return segs;
800}
801
4cda4e76
TC
802/* validates the indexes supplied to i_ppal
803
804i_ppal() doesn't do that for speed, but I'm not comfortable doing that
805for calls from perl.
806
807*/
808static void
809validate_i_ppal(i_img *im, i_palidx const *indexes, int count) {
810 int color_count = i_colorcount(im);
811 int i;
812
813 if (color_count == -1)
814 croak("i_plin() called on direct color image");
815
816 for (i = 0; i < count; ++i) {
817 if (indexes[i] >= color_count) {
818 croak("i_plin() called with out of range color index %d (max %d)",
819 indexes[i], color_count-1);
820 }
821 }
822}
823
faa9b3e7
TC
824/* I don't think ICLF_* names belong at the C interface
825 this makes the XS code think we have them, to let us avoid
826 putting function bodies in the XS code
827*/
828#define ICLF_new_internal(r, g, b, a) i_fcolor_new((r), (g), (b), (a))
829#define ICLF_DESTROY(cl) i_fcolor_destroy(cl)
830
10ea52a3
TC
831#ifdef IMAGER_LOG
832#define i_log_enabled() 1
833#else
834#define i_log_enabled() 0
835#endif
836
a8652edf
TC
837#if i_int_hlines_testing()
838
839typedef i_int_hlines *Imager__Internal__Hlines;
840
841static i_int_hlines *
8d14daab 842i_int_hlines_new(i_img_dim start_y, i_img_dim count_y, i_img_dim start_x, i_img_dim count_x) {
a8652edf
TC
843 i_int_hlines *result = mymalloc(sizeof(i_int_hlines));
844 i_int_init_hlines(result, start_y, count_y, start_x, count_x);
845
846 return result;
847}
848
849static i_int_hlines *
850i_int_hlines_new_img(i_img *im) {
851 i_int_hlines *result = mymalloc(sizeof(i_int_hlines));
852 i_int_init_hlines_img(result, im);
853
854 return result;
855}
856
857static void
858i_int_hlines_DESTROY(i_int_hlines *hlines) {
859 i_int_hlines_destroy(hlines);
860 myfree(hlines);
861}
862
ffddd407
TC
863#define i_int_hlines_CLONE_SKIP(cls) 1
864
a8652edf
TC
865static int seg_compare(const void *vleft, const void *vright) {
866 const i_int_hline_seg *left = vleft;
867 const i_int_hline_seg *right = vright;
868
869 return left->minx - right->minx;
870}
871
872static SV *
873i_int_hlines_dump(i_int_hlines *hlines) {
b13a3ddb 874 dTHX;
8d14daab
TC
875 SV *dump = newSVpvf("start_y: %" i_DF " limit_y: %" i_DF " start_x: %" i_DF " limit_x: %" i_DF"\n",
876 i_DFc(hlines->start_y), i_DFc(hlines->limit_y), i_DFc(hlines->start_x), i_DFc(hlines->limit_x));
877 i_img_dim y;
a8652edf
TC
878
879 for (y = hlines->start_y; y < hlines->limit_y; ++y) {
880 i_int_hline_entry *entry = hlines->entries[y-hlines->start_y];
881 if (entry) {
882 int i;
883 /* sort the segments, if any */
884 if (entry->count)
885 qsort(entry->segs, entry->count, sizeof(i_int_hline_seg), seg_compare);
886
8d14daab 887 sv_catpvf(dump, " %" i_DF " (%" i_DF "):", i_DFc(y), i_DFc(entry->count));
a8652edf 888 for (i = 0; i < entry->count; ++i) {
8d14daab
TC
889 sv_catpvf(dump, " [%" i_DF ", %" i_DF ")", i_DFc(entry->segs[i].minx),
890 i_DFc(entry->segs[i].x_limit));
a8652edf
TC
891 }
892 sv_catpv(dump, "\n");
893 }
894 }
895
896 return dump;
897}
898
899#endif
900
8d14daab
TC
901static off_t
902i_sv_off_t(pTHX_ SV *sv) {
903#if LSEEKSIZE > IVSIZE
904 return (off_t)SvNV(sv);
905#else
906 return (off_t)SvIV(sv);
907#endif
908}
909
910static SV *
911i_new_sv_off_t(pTHX_ off_t off) {
912#if LSEEKSIZE > IVSIZE
913 return newSVnv(off);
914#else
915 return newSViv(off);
916#endif
917}
918
ec6d8908
TC
919static im_pl_ext_funcs im_perl_funcs =
920{
921 IMAGER_PL_API_VERSION,
922 IMAGER_PL_API_LEVEL,
923 ip_handle_quant_opts,
924 ip_cleanup_quant_opts,
925 ip_copy_colors_back
926};
927
928#define PERL_PL_SET_GLOBAL_CALLBACKS \
929 sv_setiv(get_sv(PERL_PL_FUNCTION_TABLE_NAME, 1), PTR2IV(&im_perl_funcs));
930
bdd4c63b
TC
931#define IIM_new i_img_8_new
932#define IIM_DESTROY i_img_destroy
42505e61 933typedef int SysRet;
bdd4c63b 934
f7450478
TC
935#ifdef IMEXIF_ENABLE
936#define i_exif_enabled() 1
937#else
938#define i_exif_enabled() 0
939#endif
940
d16420e9 941/* trying to use more C style names, map them here */
eda1622c 942#define i_io_DESTROY(ig) io_glue_destroy(ig)
d16420e9 943
3b000586
TC
944#define i_img_get_width(im) ((im)->xsize)
945#define i_img_get_height(im) ((im)->ysize)
946
4498c8bd
TC
947#define i_img_epsilonf() (DBL_EPSILON * 4)
948
6d5c85a2
TC
949/* avoid some xsubpp strangeness */
950#define NEWLINE '\n'
951
02d1d628
AMH
952MODULE = Imager PACKAGE = Imager::Color PREFIX = ICL_
953
954Imager::Color
955ICL_new_internal(r,g,b,a)
956 unsigned char r
957 unsigned char g
958 unsigned char b
959 unsigned char a
960
961void
962ICL_DESTROY(cl)
963 Imager::Color cl
964
965
29106a11 966void
02d1d628
AMH
967ICL_set_internal(cl,r,g,b,a)
968 Imager::Color cl
969 unsigned char r
970 unsigned char g
971 unsigned char b
972 unsigned char a
29106a11 973 PPCODE:
46062ab6 974 ICL_set_internal(cl, r, g, b, a);
29106a11
TC
975 EXTEND(SP, 1);
976 PUSHs(ST(0));
02d1d628
AMH
977
978void
979ICL_info(cl)
980 Imager::Color cl
981
982
983void
984ICL_rgba(cl)
985 Imager::Color cl
986 PPCODE:
987 EXTEND(SP, 4);
b482243a
TC
988 PUSHs(sv_2mortal(newSViv(cl->rgba.r)));
989 PUSHs(sv_2mortal(newSViv(cl->rgba.g)));
990 PUSHs(sv_2mortal(newSViv(cl->rgba.b)));
991 PUSHs(sv_2mortal(newSViv(cl->rgba.a)));
02d1d628 992
efdc2568
TC
993Imager::Color
994i_hsv_to_rgb(c)
995 Imager::Color c
996 CODE:
997 RETVAL = mymalloc(sizeof(i_color));
998 *RETVAL = *c;
999 i_hsv_to_rgb(RETVAL);
1000 OUTPUT:
1001 RETVAL
1002
1003Imager::Color
1004i_rgb_to_hsv(c)
1005 Imager::Color c
1006 CODE:
1007 RETVAL = mymalloc(sizeof(i_color));
1008 *RETVAL = *c;
1009 i_rgb_to_hsv(RETVAL);
1010 OUTPUT:
1011 RETVAL
1012
02d1d628
AMH
1013
1014
faa9b3e7 1015MODULE = Imager PACKAGE = Imager::Color::Float PREFIX=ICLF_
02d1d628 1016
faa9b3e7
TC
1017Imager::Color::Float
1018ICLF_new_internal(r, g, b, a)
1019 double r
1020 double g
1021 double b
1022 double a
1023
1024void
1025ICLF_DESTROY(cl)
1026 Imager::Color::Float cl
02d1d628 1027
faa9b3e7
TC
1028void
1029ICLF_rgba(cl)
1030 Imager::Color::Float cl
1031 PREINIT:
1032 int ch;
1033 PPCODE:
1034 EXTEND(SP, MAXCHANNELS);
1035 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1036 /* printf("%d: %g\n", ch, cl->channel[ch]); */
1037 PUSHs(sv_2mortal(newSVnv(cl->channel[ch])));
1038 }
1039
1040void
1041ICLF_set_internal(cl,r,g,b,a)
1042 Imager::Color::Float cl
1043 double r
1044 double g
1045 double b
1046 double a
1047 PPCODE:
1048 cl->rgba.r = r;
1049 cl->rgba.g = g;
1050 cl->rgba.b = b;
1051 cl->rgba.a = a;
1052 EXTEND(SP, 1);
1053 PUSHs(ST(0));
02d1d628 1054
efdc2568
TC
1055Imager::Color::Float
1056i_hsv_to_rgb(c)
1057 Imager::Color::Float c
1058 CODE:
1059 RETVAL = mymalloc(sizeof(i_fcolor));
1060 *RETVAL = *c;
1061 i_hsv_to_rgbf(RETVAL);
1062 OUTPUT:
1063 RETVAL
1064
1065Imager::Color::Float
1066i_rgb_to_hsv(c)
1067 Imager::Color::Float c
1068 CODE:
1069 RETVAL = mymalloc(sizeof(i_fcolor));
1070 *RETVAL = *c;
1071 i_rgb_to_hsvf(RETVAL);
1072 OUTPUT:
1073 RETVAL
efdc2568 1074
02d1d628
AMH
1075MODULE = Imager PACKAGE = Imager::ImgRaw PREFIX = IIM_
1076
1077Imager::ImgRaw
1078IIM_new(x,y,ch)
8d14daab
TC
1079 i_img_dim x
1080 i_img_dim y
02d1d628
AMH
1081 int ch
1082
1083void
1084IIM_DESTROY(im)
1085 Imager::ImgRaw im
1086
1087
1088
1089MODULE = Imager PACKAGE = Imager
1090
1091PROTOTYPES: ENABLE
1092
1093
1094Imager::IO
1095io_new_fd(fd)
1096 int fd
1097
1098Imager::IO
1099io_new_bufchain()
1100
1101
4dfa5522 1102Imager::IO
6d5c85a2
TC
1103io_new_buffer(data_sv)
1104 SV *data_sv
4dfa5522 1105 CODE:
6d5c85a2 1106 RETVAL = do_io_new_buffer(aTHX_ data_sv);
4dfa5522
AMH
1107 OUTPUT:
1108 RETVAL
10461f9a
TC
1109
1110Imager::IO
1111io_new_cb(writecb, readcb, seekcb, closecb, maxwrite = CBDATA_BUFSIZE)
1112 SV *writecb;
1113 SV *readcb;
1114 SV *seekcb;
1115 SV *closecb;
1116 int maxwrite;
10461f9a 1117 CODE:
6d5c85a2 1118 RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb);
10461f9a
TC
1119 OUTPUT:
1120 RETVAL
4dfa5522 1121
6d5c85a2 1122SV *
02d1d628
AMH
1123io_slurp(ig)
1124 Imager::IO ig
1125 PREINIT:
1126 unsigned char* data;
4dfa5522 1127 size_t tlength;
6d5c85a2 1128 CODE:
02d1d628
AMH
1129 data = NULL;
1130 tlength = io_slurp(ig, &data);
6d5c85a2 1131 RETVAL = newSVpv((char *)data,tlength);
02d1d628 1132 myfree(data);
6d5c85a2
TC
1133 OUTPUT:
1134 RETVAL
02d1d628
AMH
1135
1136
77157728
TC
1137undef_int
1138i_set_image_file_limits(width, height, bytes)
8d14daab
TC
1139 i_img_dim width
1140 i_img_dim height
1141 size_t bytes
77157728
TC
1142
1143void
1144i_get_image_file_limits()
1145 PREINIT:
8d14daab
TC
1146 i_img_dim width, height;
1147 size_t bytes;
77157728
TC
1148 PPCODE:
1149 if (i_get_image_file_limits(&width, &height, &bytes)) {
1150 EXTEND(SP, 3);
1151 PUSHs(sv_2mortal(newSViv(width)));
1152 PUSHs(sv_2mortal(newSViv(height)));
8d14daab 1153 PUSHs(sv_2mortal(newSVuv(bytes)));
77157728
TC
1154 }
1155
e1558ffe
TC
1156bool
1157i_int_check_image_file_limits(width, height, channels, sample_size)
1158 i_img_dim width
1159 i_img_dim height
1160 int channels
1161 size_t sample_size
1162 PROTOTYPE: DISABLE
1163
6d5c85a2
TC
1164MODULE = Imager PACKAGE = Imager::IO PREFIX = io_
1165
1166Imager::IO
1167io_new_fd(class, fd)
1168 int fd
1169 CODE:
1170 RETVAL = io_new_fd(fd);
1171 OUTPUT:
1172 RETVAL
1173
1174Imager::IO
1175io_new_buffer(class, data_sv)
1176 SV *data_sv
1177 CODE:
1178 RETVAL = do_io_new_buffer(aTHX_ data_sv);
1179 OUTPUT:
1180 RETVAL
1181
1182Imager::IO
1183io_new_cb(class, writecb, readcb, seekcb, closecb)
1184 SV *writecb;
1185 SV *readcb;
1186 SV *seekcb;
1187 SV *closecb;
1188 CODE:
1189 RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb);
1190 OUTPUT:
1191 RETVAL
1192
1193Imager::IO
1194io_new_bufchain(class)
1195 CODE:
1196 RETVAL = io_new_bufchain();
1197 OUTPUT:
1198 RETVAL
1199
52d990d6
TC
1200Imager::IO
1201io__new_perlio(class, io)
1202 PerlIO *io
1203 CODE:
1204 RETVAL = im_io_new_perlio(aTHX_ io);
1205 OUTPUT:
1206 RETVAL
1207
6d5c85a2
TC
1208SV *
1209io_slurp(class, ig)
1210 Imager::IO ig
1211 PREINIT:
1212 unsigned char* data;
1213 size_t tlength;
1214 CODE:
1215 data = NULL;
1216 tlength = io_slurp(ig, &data);
1217 RETVAL = newSVpv((char *)data,tlength);
1218 myfree(data);
1219 OUTPUT:
1220 RETVAL
1221
eda1622c
TC
1222MODULE = Imager PACKAGE = Imager::IO PREFIX = i_io_
1223
6d5c85a2
TC
1224IV
1225i_io_raw_write(ig, data_sv)
eda1622c
TC
1226 Imager::IO ig
1227 SV *data_sv
1228 PREINIT:
1229 void *data;
1230 STRLEN size;
1231 CODE:
40a88898 1232 data = SvPVbyte(data_sv, size);
6d5c85a2 1233 RETVAL = i_io_raw_write(ig, data, size);
eda1622c
TC
1234 OUTPUT:
1235 RETVAL
1236
1f6c1c10 1237void
6d5c85a2 1238i_io_raw_read(ig, buffer_sv, size)
eda1622c
TC
1239 Imager::IO ig
1240 SV *buffer_sv
8d14daab 1241 IV size
eda1622c
TC
1242 PREINIT:
1243 void *buffer;
8d14daab 1244 ssize_t result;
1f6c1c10
TC
1245 PPCODE:
1246 if (size <= 0)
6d5c85a2 1247 croak("size negative in call to i_io_raw_read()");
eda1622c
TC
1248 /* prevent an undefined value warning if they supplied an
1249 undef buffer.
1250 Orginally conditional on !SvOK(), but this will prevent the
1251 downgrade from croaking */
1252 sv_setpvn(buffer_sv, "", 0);
1253#ifdef SvUTF8
1254 if (SvUTF8(buffer_sv))
1255 sv_utf8_downgrade(buffer_sv, FALSE);
1256#endif
1257 buffer = SvGROW(buffer_sv, size+1);
6d5c85a2 1258 result = i_io_raw_read(ig, buffer, size);
1f6c1c10
TC
1259 if (result >= 0) {
1260 SvCUR_set(buffer_sv, result);
1261 *SvEND(buffer_sv) = '\0';
1262 SvPOK_only(buffer_sv);
1263 EXTEND(SP, 1);
1264 PUSHs(sv_2mortal(newSViv(result)));
eda1622c 1265 }
1f6c1c10
TC
1266 ST(1) = buffer_sv;
1267 SvSETMAGIC(ST(1));
1268
1269void
6d5c85a2 1270i_io_raw_read2(ig, size)
1f6c1c10 1271 Imager::IO ig
8d14daab 1272 IV size
1f6c1c10
TC
1273 PREINIT:
1274 SV *buffer_sv;
1275 void *buffer;
8d14daab 1276 ssize_t result;
1f6c1c10
TC
1277 PPCODE:
1278 if (size <= 0)
1279 croak("size negative in call to i_io_read2()");
1280 buffer_sv = newSV(size);
1281 buffer = SvGROW(buffer_sv, size+1);
6d5c85a2 1282 result = i_io_raw_read(ig, buffer, size);
1f6c1c10 1283 if (result >= 0) {
eda1622c
TC
1284 SvCUR_set(buffer_sv, result);
1285 *SvEND(buffer_sv) = '\0';
1286 SvPOK_only(buffer_sv);
1f6c1c10
TC
1287 EXTEND(SP, 1);
1288 PUSHs(sv_2mortal(buffer_sv));
eda1622c 1289 }
1f6c1c10
TC
1290 else {
1291 /* discard it */
1292 SvREFCNT_dec(buffer_sv);
1293 }
eda1622c 1294
8d14daab 1295off_t
6d5c85a2 1296i_io_raw_seek(ig, position, whence)
eda1622c 1297 Imager::IO ig
8d14daab 1298 off_t position
eda1622c 1299 int whence
c3cc977e 1300
1f6c1c10 1301int
6d5c85a2 1302i_io_raw_close(ig)
eda1622c
TC
1303 Imager::IO ig
1304
1305void
1306i_io_DESTROY(ig)
c3cc977e
AMH
1307 Imager::IO ig
1308
ffddd407
TC
1309int
1310i_io_CLONE_SKIP(...)
1311 CODE:
8d14daab 1312 (void)items; /* avoid unused warning for XS variable */
ffddd407
TC
1313 RETVAL = 1;
1314 OUTPUT:
1315 RETVAL
1316
6d5c85a2
TC
1317int
1318i_io_getc(ig)
1319 Imager::IO ig
1320
1321int
1322i_io_putc(ig, c)
1323 Imager::IO ig
1324 int c
1325
1326int
1327i_io_close(ig)
1328 Imager::IO ig
1329
1330int
1331i_io_flush(ig)
1332 Imager::IO ig
1333
1334int
1335i_io_peekc(ig)
1336 Imager::IO ig
1337
1338int
1339i_io_seek(ig, off, whence)
1340 Imager::IO ig
1341 off_t off
1342 int whence
1343
1344void
1345i_io_peekn(ig, size)
1346 Imager::IO ig
1347 STRLEN size
1348 PREINIT:
1349 SV *buffer_sv;
1350 void *buffer;
1351 ssize_t result;
1352 PPCODE:
1353 buffer_sv = newSV(size+1);
1354 buffer = SvGROW(buffer_sv, size+1);
1355 result = i_io_peekn(ig, buffer, size);
1356 if (result >= 0) {
1357 SvCUR_set(buffer_sv, result);
1358 *SvEND(buffer_sv) = '\0';
1359 SvPOK_only(buffer_sv);
1360 EXTEND(SP, 1);
1361 PUSHs(sv_2mortal(buffer_sv));
1362 }
1363 else {
1364 /* discard it */
1365 SvREFCNT_dec(buffer_sv);
1366 }
1367
1368void
1369i_io_read(ig, buffer_sv, size)
1370 Imager::IO ig
1371 SV *buffer_sv
1372 IV size
1373 PREINIT:
1374 void *buffer;
1375 ssize_t result;
1376 PPCODE:
1377 if (size <= 0)
1378 croak("size negative in call to i_io_read()");
1379 /* prevent an undefined value warning if they supplied an
1380 undef buffer.
1381 Orginally conditional on !SvOK(), but this will prevent the
1382 downgrade from croaking */
1383 sv_setpvn(buffer_sv, "", 0);
1384#ifdef SvUTF8
1385 if (SvUTF8(buffer_sv))
1386 sv_utf8_downgrade(buffer_sv, FALSE);
1387#endif
1388 buffer = SvGROW(buffer_sv, size+1);
1389 result = i_io_read(ig, buffer, size);
1390 if (result >= 0) {
1391 SvCUR_set(buffer_sv, result);
1392 *SvEND(buffer_sv) = '\0';
1393 SvPOK_only(buffer_sv);
1394 EXTEND(SP, 1);
1395 PUSHs(sv_2mortal(newSViv(result)));
1396 }
1397 ST(1) = buffer_sv;
1398 SvSETMAGIC(ST(1));
1399
1400void
1401i_io_read2(ig, size)
1402 Imager::IO ig
1403 STRLEN size
1404 PREINIT:
1405 SV *buffer_sv;
1406 void *buffer;
1407 ssize_t result;
1408 PPCODE:
1409 if (size == 0)
1410 croak("size zero in call to read2()");
1411 buffer_sv = newSV(size);
1412 buffer = SvGROW(buffer_sv, size+1);
1413 result = i_io_read(ig, buffer, size);
1414 if (result > 0) {
1415 SvCUR_set(buffer_sv, result);
1416 *SvEND(buffer_sv) = '\0';
1417 SvPOK_only(buffer_sv);
1418 EXTEND(SP, 1);
1419 PUSHs(sv_2mortal(buffer_sv));
1420 }
1421 else {
1422 /* discard it */
1423 SvREFCNT_dec(buffer_sv);
1424 }
1425
1426void
1427i_io_gets(ig, size = 8192, eol = NEWLINE)
1428 Imager::IO ig
1429 STRLEN size
1430 int eol
1431 PREINIT:
1432 SV *buffer_sv;
1433 void *buffer;
1434 ssize_t result;
1435 PPCODE:
1436 if (size < 2)
1437 croak("size too small in call to gets()");
1438 buffer_sv = sv_2mortal(newSV(size+1));
1439 buffer = SvPVX(buffer_sv);
1440 result = i_io_gets(ig, buffer, size+1, eol);
1441 if (result > 0) {
1442 SvCUR_set(buffer_sv, result);
1443 *SvEND(buffer_sv) = '\0';
1444 SvPOK_only(buffer_sv);
1445 EXTEND(SP, 1);
1446 PUSHs(buffer_sv);
1447 }
1448
1449IV
1450i_io_write(ig, data_sv)
1451 Imager::IO ig
1452 SV *data_sv
1453 PREINIT:
1454 void *data;
1455 STRLEN size;
1456 CODE:
40a88898 1457 data = SvPVbyte(data_sv, size);
6d5c85a2
TC
1458 RETVAL = i_io_write(ig, data, size);
1459 OUTPUT:
1460 RETVAL
1461
1462void
1463i_io_dump(ig, flags = I_IO_DUMP_DEFAULT)
1464 Imager::IO ig
1465 int flags
1466
1467bool
1468i_io_set_buffered(ig, flag = 1)
1469 Imager::IO ig
1470 int flag
1471
1472bool
1473i_io_is_buffered(ig)
1474 Imager::IO ig
1475
1476bool
1477i_io_eof(ig)
1478 Imager::IO ig
1479
1480bool
1481i_io_error(ig)
1482 Imager::IO ig
1483
c3cc977e
AMH
1484MODULE = Imager PACKAGE = Imager
1485
1486PROTOTYPES: ENABLE
1487
02d1d628
AMH
1488void
1489i_list_formats()
1490 PREINIT:
1491 char* item;
1492 int i;
1493 PPCODE:
1494 i=0;
1495 while( (item=i_format_list[i++]) != NULL ) {
1496 EXTEND(SP, 1);
1497 PUSHs(sv_2mortal(newSVpv(item,0)));
1498 }
1499
ec76939c
TC
1500Imager::ImgRaw
1501i_sametype(im, x, y)
1502 Imager::ImgRaw im
8d14daab
TC
1503 i_img_dim x
1504 i_img_dim y
ec76939c
TC
1505
1506Imager::ImgRaw
1507i_sametype_chans(im, x, y, channels)
1508 Imager::ImgRaw im
8d14daab
TC
1509 i_img_dim x
1510 i_img_dim y
ec76939c
TC
1511 int channels
1512
10ea52a3 1513int
bd8052a6
TC
1514i_init_log(name_sv,level)
1515 SV* name_sv
02d1d628 1516 int level
bd8052a6
TC
1517 PREINIT:
1518 const char *name = SvOK(name_sv) ? SvPV_nolen(name_sv) : NULL;
1519 CODE:
10ea52a3
TC
1520 RETVAL = i_init_log(name, level);
1521 OUTPUT:
1522 RETVAL
02d1d628 1523
7f882a01 1524void
bf1573f9 1525i_log_entry(string,level)
7f882a01
AMH
1526 char* string
1527 int level
1528
10ea52a3
TC
1529int
1530i_log_enabled()
7f882a01 1531
02d1d628
AMH
1532void
1533i_img_info(im)
1534 Imager::ImgRaw im
1535 PREINIT:
8d14daab 1536 i_img_dim info[4];
02d1d628
AMH
1537 PPCODE:
1538 i_img_info(im,info);
1539 EXTEND(SP, 4);
1540 PUSHs(sv_2mortal(newSViv(info[0])));
1541 PUSHs(sv_2mortal(newSViv(info[1])));
1542 PUSHs(sv_2mortal(newSViv(info[2])));
1543 PUSHs(sv_2mortal(newSViv(info[3])));
1544
1545
1546
1547
1548void
1549i_img_setmask(im,ch_mask)
1550 Imager::ImgRaw im
1551 int ch_mask
1552
1553int
1554i_img_getmask(im)
1555 Imager::ImgRaw im
1556
1557int
1558i_img_getchannels(im)
1559 Imager::ImgRaw im
1560
1561void
1562i_img_getdata(im)
1563 Imager::ImgRaw im
1564 PPCODE:
1565 EXTEND(SP, 1);
26fd367b
TC
1566 PUSHs(im->idata ?
1567 sv_2mortal(newSVpv((char *)im->idata, im->bytes))
faa9b3e7 1568 : &PL_sv_undef);
02d1d628 1569
3b000586
TC
1570IV
1571i_img_get_width(im)
1572 Imager::ImgRaw im
1573
1574IV
1575i_img_get_height(im)
1576 Imager::ImgRaw im
1577
1578
bd8052a6
TC
1579void
1580i_img_is_monochrome(im)
1581 Imager::ImgRaw im
1582 PREINIT:
1583 int zero_is_white;
1584 int result;
1585 PPCODE:
1586 result = i_img_is_monochrome(im, &zero_is_white);
1587 if (result) {
1588 if (GIMME_V == G_ARRAY) {
1589 EXTEND(SP, 2);
1590 PUSHs(&PL_sv_yes);
1591 PUSHs(sv_2mortal(newSViv(zero_is_white)));
1592 }
1593 else {
1594 EXTEND(SP, 1);
1595 PUSHs(&PL_sv_yes);
1596 }
1597 }
02d1d628
AMH
1598
1599void
aa833c97 1600i_line(im,x1,y1,x2,y2,val,endp)
02d1d628 1601 Imager::ImgRaw im
8d14daab
TC
1602 i_img_dim x1
1603 i_img_dim y1
1604 i_img_dim x2
1605 i_img_dim y2
02d1d628 1606 Imager::Color val
aa833c97 1607 int endp
02d1d628
AMH
1608
1609void
b437ce0a 1610i_line_aa(im,x1,y1,x2,y2,val,endp)
02d1d628 1611 Imager::ImgRaw im
8d14daab
TC
1612 i_img_dim x1
1613 i_img_dim y1
1614 i_img_dim x2
1615 i_img_dim y2
02d1d628 1616 Imager::Color val
b437ce0a 1617 int endp
02d1d628
AMH
1618
1619void
1620i_box(im,x1,y1,x2,y2,val)
1621 Imager::ImgRaw im
8d14daab
TC
1622 i_img_dim x1
1623 i_img_dim y1
1624 i_img_dim x2
1625 i_img_dim y2
02d1d628
AMH
1626 Imager::Color val
1627
1628void
1629i_box_filled(im,x1,y1,x2,y2,val)
1630 Imager::ImgRaw im
8d14daab
TC
1631 i_img_dim x1
1632 i_img_dim y1
1633 i_img_dim x2
1634 i_img_dim y2
02d1d628
AMH
1635 Imager::Color val
1636
7477ff14
TC
1637int
1638i_box_filledf(im,x1,y1,x2,y2,val)
1639 Imager::ImgRaw im
8d14daab
TC
1640 i_img_dim x1
1641 i_img_dim y1
1642 i_img_dim x2
1643 i_img_dim y2
7477ff14
TC
1644 Imager::Color::Float val
1645
f1ac5027
TC
1646void
1647i_box_cfill(im,x1,y1,x2,y2,fill)
1648 Imager::ImgRaw im
8d14daab
TC
1649 i_img_dim x1
1650 i_img_dim y1
1651 i_img_dim x2
1652 i_img_dim y2
f1ac5027
TC
1653 Imager::FillHandle fill
1654
02d1d628
AMH
1655void
1656i_arc(im,x,y,rad,d1,d2,val)
1657 Imager::ImgRaw im
8d14daab
TC
1658 i_img_dim x
1659 i_img_dim y
1660 double rad
1661 double d1
1662 double d2
02d1d628
AMH
1663 Imager::Color val
1664
a8652edf
TC
1665void
1666i_arc_aa(im,x,y,rad,d1,d2,val)
1667 Imager::ImgRaw im
1668 double x
1669 double y
1670 double rad
1671 double d1
1672 double d2
1673 Imager::Color val
1674
f1ac5027
TC
1675void
1676i_arc_cfill(im,x,y,rad,d1,d2,fill)
1677 Imager::ImgRaw im
8d14daab
TC
1678 i_img_dim x
1679 i_img_dim y
1680 double rad
1681 double d1
1682 double d2
f1ac5027
TC
1683 Imager::FillHandle fill
1684
a8652edf
TC
1685void
1686i_arc_aa_cfill(im,x,y,rad,d1,d2,fill)
1687 Imager::ImgRaw im
1688 double x
1689 double y
1690 double rad
1691 double d1
1692 double d2
1693 Imager::FillHandle fill
02d1d628
AMH
1694
1695
6af18d2b
AMH
1696void
1697i_circle_aa(im,x,y,rad,val)
1698 Imager::ImgRaw im
8d14daab
TC
1699 double x
1700 double y
1701 double rad
6af18d2b
AMH
1702 Imager::Color val
1703
40068b33
TC
1704int
1705i_circle_out(im,x,y,rad,val)
1706 Imager::ImgRaw im
1707 i_img_dim x
1708 i_img_dim y
1709 i_img_dim rad
1710 Imager::Color val
1711
1712int
1713i_circle_out_aa(im,x,y,rad,val)
1714 Imager::ImgRaw im
1715 i_img_dim x
1716 i_img_dim y
1717 i_img_dim rad
1718 Imager::Color val
1719
1720int
1721i_arc_out(im,x,y,rad,d1,d2,val)
1722 Imager::ImgRaw im
1723 i_img_dim x
1724 i_img_dim y
1725 i_img_dim rad
8d14daab
TC
1726 double d1
1727 double d2
40068b33
TC
1728 Imager::Color val
1729
1730int
1731i_arc_out_aa(im,x,y,rad,d1,d2,val)
1732 Imager::ImgRaw im
1733 i_img_dim x
1734 i_img_dim y
1735 i_img_dim rad
8d14daab
TC
1736 double d1
1737 double d2
40068b33 1738 Imager::Color val
6af18d2b
AMH
1739
1740
02d1d628 1741void
987245e2 1742i_bezier_multi(im,x,y,val)
02d1d628 1743 Imager::ImgRaw im
987245e2
TC
1744 double *x
1745 double *y
1746 Imager::Color val
1747 PREINIT:
1748 STRLEN size_x;
1749 STRLEN size_y;
1750 PPCODE:
1751 if (size_x != size_y)
1752 croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
1753 i_bezier_multi(im,size_x,x,y,val);
02d1d628 1754
1c5252ed 1755int
19e9591b 1756i_poly_aa(im,x,y,val)
02d1d628 1757 Imager::ImgRaw im
19e9591b
TC
1758 double *x
1759 double *y
a54e32ba
TC
1760 Imager::Color val
1761 PREINIT:
19e9591b
TC
1762 STRLEN size_x;
1763 STRLEN size_y;
a54e32ba 1764 CODE:
19e9591b 1765 if (size_x != size_y)
a54e32ba 1766 croak("Imager: x and y arrays to i_poly_aa must be equal length\n");
19e9591b 1767 RETVAL = i_poly_aa(im, size_x, x, y, val);
a54e32ba
TC
1768 OUTPUT:
1769 RETVAL
02d1d628 1770
1c5252ed 1771int
19e9591b 1772i_poly_aa_cfill(im, x, y, fill)
43c5dacb 1773 Imager::ImgRaw im
19e9591b
TC
1774 double *x
1775 double *y
a54e32ba
TC
1776 Imager::FillHandle fill
1777 PREINIT:
19e9591b
TC
1778 STRLEN size_x;
1779 STRLEN size_y;
a54e32ba 1780 CODE:
19e9591b 1781 if (size_x != size_y)
a54e32ba 1782 croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n");
19e9591b 1783 RETVAL = i_poly_aa_cfill(im, size_x, x, y, fill);
a54e32ba
TC
1784 OUTPUT:
1785 RETVAL
02d1d628 1786
a321d497 1787undef_int
02d1d628
AMH
1788i_flood_fill(im,seedx,seedy,dcol)
1789 Imager::ImgRaw im
8d14daab
TC
1790 i_img_dim seedx
1791 i_img_dim seedy
02d1d628
AMH
1792 Imager::Color dcol
1793
a321d497 1794undef_int
cc6483e0
TC
1795i_flood_cfill(im,seedx,seedy,fill)
1796 Imager::ImgRaw im
8d14daab
TC
1797 i_img_dim seedx
1798 i_img_dim seedy
cc6483e0
TC
1799 Imager::FillHandle fill
1800
3efb0915
TC
1801undef_int
1802i_flood_fill_border(im,seedx,seedy,dcol, border)
1803 Imager::ImgRaw im
8d14daab
TC
1804 i_img_dim seedx
1805 i_img_dim seedy
3efb0915
TC
1806 Imager::Color dcol
1807 Imager::Color border
1808
1809undef_int
1810i_flood_cfill_border(im,seedx,seedy,fill, border)
1811 Imager::ImgRaw im
8d14daab
TC
1812 i_img_dim seedx
1813 i_img_dim seedy
3efb0915
TC
1814 Imager::FillHandle fill
1815 Imager::Color border
1816
02d1d628
AMH
1817
1818void
1819i_copyto(im,src,x1,y1,x2,y2,tx,ty)
1820 Imager::ImgRaw im
1821 Imager::ImgRaw src
8d14daab
TC
1822 i_img_dim x1
1823 i_img_dim y1
1824 i_img_dim x2
1825 i_img_dim y2
1826 i_img_dim tx
1827 i_img_dim ty
02d1d628
AMH
1828
1829
1830void
1831i_copyto_trans(im,src,x1,y1,x2,y2,tx,ty,trans)
1832 Imager::ImgRaw im
1833 Imager::ImgRaw src
8d14daab
TC
1834 i_img_dim x1
1835 i_img_dim y1
1836 i_img_dim x2
1837 i_img_dim y2
1838 i_img_dim tx
1839 i_img_dim ty
02d1d628
AMH
1840 Imager::Color trans
1841
92bda632
TC
1842Imager::ImgRaw
1843i_copy(src)
02d1d628
AMH
1844 Imager::ImgRaw src
1845
1846
faa9b3e7 1847undef_int
71dc4a83 1848i_rubthru(im,src,tx,ty,src_minx,src_miny,src_maxx,src_maxy)
02d1d628
AMH
1849 Imager::ImgRaw im
1850 Imager::ImgRaw src
8d14daab
TC
1851 i_img_dim tx
1852 i_img_dim ty
1853 i_img_dim src_minx
1854 i_img_dim src_miny
1855 i_img_dim src_maxx
1856 i_img_dim src_maxy
71dc4a83 1857
9b1ec2b8
TC
1858undef_int
1859i_compose(out, src, out_left, out_top, src_left, src_top, width, height, combine = ic_normal, opacity = 0.0)
1860 Imager::ImgRaw out
1861 Imager::ImgRaw src
8d14daab
TC
1862 i_img_dim out_left
1863 i_img_dim out_top
1864 i_img_dim src_left
1865 i_img_dim src_top
1866 i_img_dim width
1867 i_img_dim height
9b1ec2b8
TC
1868 int combine
1869 double opacity
1870
1871undef_int
1872i_compose_mask(out, src, mask, out_left, out_top, src_left, src_top, mask_left, mask_top, width, height, combine = ic_normal, opacity = 0.0)
1873 Imager::ImgRaw out
1874 Imager::ImgRaw src
1875 Imager::ImgRaw mask
8d14daab
TC
1876 i_img_dim out_left
1877 i_img_dim out_top
1878 i_img_dim src_left
1879 i_img_dim src_top
1880 i_img_dim mask_left
1881 i_img_dim mask_top
1882 i_img_dim width
1883 i_img_dim height
9b1ec2b8
TC
1884 int combine
1885 double opacity
02d1d628 1886
b47464c1
TC
1887Imager::ImgRaw
1888i_combine(src_av, channels_av = NULL)
1889 AV *src_av
1890 AV *channels_av
1891 PREINIT:
1892 i_img **imgs = NULL;
1893 STRLEN in_count;
1894 int *channels = NULL;
1895 int i;
1896 SV **psv;
1897 IV tmp;
1898 CODE:
1899 in_count = av_len(src_av) + 1;
1900 if (in_count > 0) {
1901 imgs = mymalloc(sizeof(i_img*) * in_count);
1902 channels = mymalloc(sizeof(int) * in_count);
1903 for (i = 0; i < in_count; ++i) {
1904 psv = av_fetch(src_av, i, 0);
1905 if (!psv || !*psv || !sv_derived_from(*psv, "Imager::ImgRaw")) {
1906 myfree(imgs);
1907 myfree(channels);
1908 croak("imgs must contain only images");
1909 }
1910 tmp = SvIV((SV*)SvRV(*psv));
1911 imgs[i] = INT2PTR(i_img*, tmp);
1912 if (channels_av &&
1913 (psv = av_fetch(channels_av, i, 0)) != NULL &&
1914 *psv) {
1915 channels[i] = SvIV(*psv);
1916 }
1917 else {
1918 channels[i] = 0;
1919 }
1920 }
1921 }
1922 RETVAL = i_combine(imgs, channels, in_count);
1923 myfree(imgs);
1924 myfree(channels);
1925 OUTPUT:
1926 RETVAL
1927
142c26ff
AMH
1928undef_int
1929i_flipxy(im, direction)
1930 Imager::ImgRaw im
1931 int direction
1932
faa9b3e7
TC
1933Imager::ImgRaw
1934i_rotate90(im, degrees)
1935 Imager::ImgRaw im
1936 int degrees
1937
1938Imager::ImgRaw
0d3b936e 1939i_rotate_exact(im, amount, ...)
faa9b3e7
TC
1940 Imager::ImgRaw im
1941 double amount
0d3b936e
TC
1942 PREINIT:
1943 i_color *backp = NULL;
1944 i_fcolor *fbackp = NULL;
1945 int i;
1946 SV * sv1;
1947 CODE:
1948 /* extract the bg colors if any */
1949 /* yes, this is kind of strange */
1950 for (i = 2; i < items; ++i) {
1951 sv1 = ST(i);
1952 if (sv_derived_from(sv1, "Imager::Color")) {
1953 IV tmp = SvIV((SV*)SvRV(sv1));
1954 backp = INT2PTR(i_color *, tmp);
1955 }
1956 else if (sv_derived_from(sv1, "Imager::Color::Float")) {
1957 IV tmp = SvIV((SV*)SvRV(sv1));
1958 fbackp = INT2PTR(i_fcolor *, tmp);
1959 }
1960 }
1961 RETVAL = i_rotate_exact_bg(im, amount, backp, fbackp);
1962 OUTPUT:
1963 RETVAL
faa9b3e7
TC
1964
1965Imager::ImgRaw
87b3f212 1966i_matrix_transform(im, xsize, ysize, matrix_av, ...)
faa9b3e7 1967 Imager::ImgRaw im
487ec752
TC
1968 i_img_dim xsize
1969 i_img_dim ysize
87b3f212 1970 AV *matrix_av
487ec752
TC
1971 PREINIT:
1972 double matrix[9];
1973 STRLEN len;
1974 SV *sv1;
1975 int i;
1976 i_color *backp = NULL;
1977 i_fcolor *fbackp = NULL;
1978 CODE:
1979 len=av_len(matrix_av)+1;
1980 if (len > 9)
1981 len = 9;
1982 for (i = 0; i < len; ++i) {
1983 sv1=(*(av_fetch(matrix_av,i,0)));
1984 matrix[i] = SvNV(sv1);
1985 }
1986 for (; i < 9; ++i)
1987 matrix[i] = 0;
1988 /* extract the bg colors if any */
1989 /* yes, this is kind of strange */
1990 for (i = 4; i < items; ++i) {
1991 sv1 = ST(i);
1992 if (sv_derived_from(sv1, "Imager::Color")) {
1993 IV tmp = SvIV((SV*)SvRV(sv1));
1994 backp = INT2PTR(i_color *, tmp);
1995 }
1996 else if (sv_derived_from(sv1, "Imager::Color::Float")) {
1997 IV tmp = SvIV((SV*)SvRV(sv1));
1998 fbackp = INT2PTR(i_fcolor *, tmp);
1999 }
2000 }
2001 RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp);
2002 OUTPUT:
2003 RETVAL
02d1d628 2004
167660cd 2005undef_int
02d1d628
AMH
2006i_gaussian(im,stdev)
2007 Imager::ImgRaw im
167660cd 2008 double stdev
02d1d628 2009
b6381851
TC
2010void
2011i_unsharp_mask(im,stdev,scale)
2012 Imager::ImgRaw im
8d14daab 2013 double stdev
b6381851
TC
2014 double scale
2015
6a3cbaef
TC
2016int
2017i_conv(im,coef)
2018 Imager::ImgRaw im
2019 AV *coef
2020 PREINIT:
2021 double* c_coef;
2022 int len;
2023 SV* sv1;
2024 int i;
2025 CODE:
2026 len = av_len(coef) + 1;
2027 c_coef=mymalloc( len * sizeof(double) );
2028 for(i = 0; i < len; i++) {
2029 sv1 = (*(av_fetch(coef, i, 0)));
2030 c_coef[i] = (double)SvNV(sv1);
2031 }
2032 RETVAL = i_conv(im, c_coef, len);
2033 myfree(c_coef);
2034 OUTPUT:
2035 RETVAL
02d1d628 2036
d5477d3d
TC
2037Imager::ImgRaw
2038i_convert(src, avmain)
f5991c03 2039 Imager::ImgRaw src
d5477d3d 2040 AV *avmain
f5991c03 2041 PREINIT:
62869327 2042 double *coeff;
f5991c03
TC
2043 int outchan;
2044 int inchan;
f5991c03 2045 SV **temp;
f5991c03
TC
2046 AV *avsub;
2047 int len;
2048 int i, j;
2049 CODE:
f5991c03
TC
2050 outchan = av_len(avmain)+1;
2051 /* find the biggest */
2052 inchan = 0;
2053 for (j=0; j < outchan; ++j) {
2054 temp = av_fetch(avmain, j, 0);
2055 if (temp && SvROK(*temp) && SvTYPE(SvRV(*temp)) == SVt_PVAV) {
2056 avsub = (AV*)SvRV(*temp);
2057 len = av_len(avsub)+1;
2058 if (len > inchan)
2059 inchan = len;
2060 }
26eb06dd
TC
2061 else {
2062 i_push_errorf(0, "invalid matrix: element %d is not an array ref", j);
2063 XSRETURN(0);
2064 }
f5991c03 2065 }
62869327 2066 coeff = mymalloc(sizeof(double) * outchan * inchan);
f5991c03
TC
2067 for (j = 0; j < outchan; ++j) {
2068 avsub = (AV*)SvRV(*av_fetch(avmain, j, 0));
2069 len = av_len(avsub)+1;
2070 for (i = 0; i < len; ++i) {
2071 temp = av_fetch(avsub, i, 0);
2072 if (temp)
2073 coeff[i+j*inchan] = SvNV(*temp);
2074 else
2075 coeff[i+j*inchan] = 0;
2076 }
2077 while (i < inchan)
2078 coeff[i++ + j*inchan] = 0;
2079 }
d5477d3d 2080 RETVAL = i_convert(src, coeff, outchan, inchan);
f5991c03 2081 myfree(coeff);
f5991c03
TC
2082 OUTPUT:
2083 RETVAL
40eba1ea
AMH
2084
2085
1136f089 2086undef_int
85f38e13 2087i_map(im, pmaps_av)
40eba1ea 2088 Imager::ImgRaw im
85f38e13 2089 AV *pmaps_av
64655904
TC
2090 PREINIT:
2091 unsigned int mask = 0;
2092 AV *avmain;
2093 AV *avsub;
2094 SV **temp;
2095 int len;
2096 int i, j;
2097 unsigned char (*maps)[256];
2098 CODE:
2099 len = av_len(pmaps_av)+1;
2100 if (im->channels < len)
2101 len = im->channels;
2102 maps = mymalloc( len * sizeof(unsigned char [256]) );
2103 for (j=0; j<len ; j++) {
2104 temp = av_fetch(pmaps_av, j, 0);
2105 if (temp && SvROK(*temp) && (SvTYPE(SvRV(*temp)) == SVt_PVAV) ) {
2106 avsub = (AV*)SvRV(*temp);
2107 if(av_len(avsub) != 255)
2108 continue;
2109 mask |= 1<<j;
2110 for (i=0; i<256 ; i++) {
2111 int val;
2112 temp = av_fetch(avsub, i, 0);
2113 val = temp ? SvIV(*temp) : 0;
2114 if (val<0) val = 0;
2115 if (val>255) val = 255;
2116 maps[j][i] = val;
2117 }
2118 }
2119 }
2120 i_map(im, maps, mask);
2121 myfree(maps);
2122 RETVAL = 1;
2123 OUTPUT:
2124 RETVAL
40eba1ea 2125
02d1d628
AMH
2126float
2127i_img_diff(im1,im2)
2128 Imager::ImgRaw im1
2129 Imager::ImgRaw im2
2130
e41cfe8f
TC
2131double
2132i_img_diffd(im1,im2)
2133 Imager::ImgRaw im1
2134 Imager::ImgRaw im2
02d1d628 2135
4498c8bd
TC
2136int
2137i_img_samef(im1, im2, epsilon = i_img_epsilonf(), what=NULL)
2138 Imager::ImgRaw im1
2139 Imager::ImgRaw im2
2140 double epsilon
2141 const char *what
2142
2143double
2144i_img_epsilonf()
2145
813d4d0a
TC
2146bool
2147_is_color_object(sv)
2148 SV* sv
2149 CODE:
2150 SvGETMAGIC(sv);
2151 RETVAL = SvOK(sv) && SvROK(sv) &&
2152 (sv_derived_from(sv, "Imager::Color")
2153 || sv_derived_from(sv, "Imager::Color::Float"));
2154 OUTPUT:
2155 RETVAL
2156
02d1d628
AMH
2157#ifdef HAVE_LIBTT
2158
2159
4b19f77a 2160Imager::Font::TT
02d1d628
AMH
2161i_tt_new(fontname)
2162 char* fontname
2163
4b19f77a
AMH
2164
2165MODULE = Imager PACKAGE = Imager::Font::TT PREFIX=TT_
2166
2167#define TT_DESTROY(handle) i_tt_destroy(handle)
2168
02d1d628 2169void
4b19f77a
AMH
2170TT_DESTROY(handle)
2171 Imager::Font::TT handle
2172
ffddd407
TC
2173int
2174TT_CLONE_SKIP(...)
2175 CODE:
8d14daab 2176 (void)items; /* avoid unused warning */
ffddd407
TC
2177 RETVAL = 1;
2178 OUTPUT:
2179 RETVAL
2180
02d1d628 2181
4b19f77a 2182MODULE = Imager PACKAGE = Imager
02d1d628
AMH
2183
2184
2185undef_int
e3b4d6c3 2186i_tt_text(handle,im,xb,yb,cl,points,str_sv,smooth,utf8,align=1)
4b19f77a 2187 Imager::Font::TT handle
02d1d628 2188 Imager::ImgRaw im
8d14daab
TC
2189 i_img_dim xb
2190 i_img_dim yb
02d1d628 2191 Imager::Color cl
8d14daab 2192 double points
4f68b48f 2193 SV * str_sv
02d1d628 2194 int smooth
4f68b48f 2195 int utf8
9ab6338b 2196 int align
4f68b48f
TC
2197 PREINIT:
2198 char *str;
2199 STRLEN len;
2200 CODE:
e3b4d6c3 2201 str = SvPV(str_sv, len);
4f68b48f
TC
2202#ifdef SvUTF8
2203 if (SvUTF8(str_sv))
2204 utf8 = 1;
2205#endif
4f68b48f 2206 RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str,
9ab6338b 2207 len, smooth, utf8, align);
4f68b48f
TC
2208 OUTPUT:
2209 RETVAL
02d1d628
AMH
2210
2211
2212undef_int
e3b4d6c3 2213i_tt_cp(handle,im,xb,yb,channel,points,str_sv,smooth,utf8,align=1)
4b19f77a 2214 Imager::Font::TT handle
02d1d628 2215 Imager::ImgRaw im
8d14daab
TC
2216 i_img_dim xb
2217 i_img_dim yb
02d1d628 2218 int channel
8d14daab 2219 double points
4f68b48f 2220 SV * str_sv
02d1d628 2221 int smooth
4f68b48f 2222 int utf8
9ab6338b 2223 int align
4f68b48f
TC
2224 PREINIT:
2225 char *str;
2226 STRLEN len;
2227 CODE:
e3b4d6c3 2228 str = SvPV(str_sv, len);
4f68b48f
TC
2229#ifdef SvUTF8
2230 if (SvUTF8(str_sv))
2231 utf8 = 1;
2232#endif
4f68b48f 2233 RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len,
9ab6338b 2234 smooth, utf8, align);
4f68b48f
TC
2235 OUTPUT:
2236 RETVAL
02d1d628
AMH
2237
2238
a659442a 2239void
7e3298ec 2240i_tt_bbox(handle,point,str_sv,utf8)
4b19f77a 2241 Imager::Font::TT handle
8d14daab 2242 double point
4f68b48f 2243 SV* str_sv
4f68b48f 2244 int utf8
02d1d628 2245 PREINIT:
8d14daab
TC
2246 i_img_dim cords[BOUNDING_BOX_COUNT];
2247 int rc;
4f68b48f
TC
2248 char * str;
2249 STRLEN len;
3799c4d1 2250 int i;
02d1d628 2251 PPCODE:
7e3298ec 2252 str = SvPV(str_sv, len);
4f68b48f
TC
2253#ifdef SvUTF8
2254 if (SvUTF8(ST(2)))
2255 utf8 = 1;
2256#endif
4f68b48f 2257 if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) {
3799c4d1
TC
2258 EXTEND(SP, rc);
2259 for (i = 0; i < rc; ++i) {
2260 PUSHs(sv_2mortal(newSViv(cords[i])));
2261 }
02d1d628
AMH
2262 }
2263
eeaa33fd
TC
2264void
2265i_tt_has_chars(handle, text_sv, utf8)
2266 Imager::Font::TT handle
2267 SV *text_sv
2268 int utf8
2269 PREINIT:
2270 char const *text;
2271 STRLEN len;
2272 char *work;
8d14daab
TC
2273 size_t count;
2274 size_t i;
eeaa33fd 2275 PPCODE:
7e3298ec
TC
2276 i_clear_error();
2277 text = SvPV(text_sv, len);
eeaa33fd
TC
2278#ifdef SvUTF8
2279 if (SvUTF8(text_sv))
2280 utf8 = 1;
2281#endif
eeaa33fd
TC
2282 work = mymalloc(len);
2283 count = i_tt_has_chars(handle, text, len, utf8, work);
2284 if (GIMME_V == G_ARRAY) {
2285 EXTEND(SP, count);
2286 for (i = 0; i < count; ++i) {
6e938c74 2287 PUSHs(boolSV(work[i]));
eeaa33fd
TC
2288 }
2289 }
2290 else {
2291 EXTEND(SP, 1);
2292 PUSHs(sv_2mortal(newSVpv(work, count)));
2293 }
2294 myfree(work);
02d1d628 2295
3799c4d1
TC
2296void
2297i_tt_dump_names(handle)
2298 Imager::Font::TT handle
02d1d628 2299
3799c4d1
TC
2300void
2301i_tt_face_name(handle)
2302 Imager::Font::TT handle
2303 PREINIT:
2304 char name[255];
8d14daab 2305 size_t len;
3799c4d1
TC
2306 PPCODE:
2307 len = i_tt_face_name(handle, name, sizeof(name));
2308 if (len) {
2309 EXTEND(SP, 1);
8d14daab 2310 PUSHs(sv_2mortal(newSVpv(name, len-1)));
3799c4d1 2311 }
02d1d628 2312
19fa4baf
AMH
2313void
2314i_tt_glyph_name(handle, text_sv, utf8 = 0)
3799c4d1
TC
2315 Imager::Font::TT handle
2316 SV *text_sv
2317 int utf8
2318 PREINIT:
2319 char const *text;
2320 STRLEN work_len;
718b8c97 2321 size_t len;
8d14daab 2322 size_t outsize;
3799c4d1 2323 char name[255];
7e3298ec 2324 SSize_t count = 0;
3799c4d1 2325 PPCODE:
7e3298ec
TC
2326 i_clear_error();
2327 text = SvPV(text_sv, work_len);
3799c4d1
TC
2328#ifdef SvUTF8
2329 if (SvUTF8(text_sv))
2330 utf8 = 1;
2331#endif
3799c4d1
TC
2332 len = work_len;
2333 while (len) {
17892255 2334 unsigned long ch;
3799c4d1
TC
2335 if (utf8) {
2336 ch = i_utf8_advance(&text, &len);
2337 if (ch == ~0UL) {
2338 i_push_error(0, "invalid UTF8 character");
7e3298ec 2339 XSRETURN_EMPTY;
3799c4d1
TC
2340 }
2341 }
2342 else {
2343 ch = *text++;
2344 --len;
2345 }
086b32d6 2346 EXTEND(SP, count+1);
af070d99 2347 if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
7e3298ec 2348 ST(count) = sv_2mortal(newSVpv(name, 0));
3799c4d1
TC
2349 }
2350 else {
7e3298ec
TC
2351 ST(count) = &PL_sv_undef;
2352 }
2353 ++count;
3799c4d1 2354 }
7e3298ec 2355 XSRETURN(count);
3799c4d1
TC
2356
2357#endif
02d1d628 2358
53a6bbd4 2359const char *
e10bf46e
AMH
2360i_test_format_probe(ig, length)
2361 Imager::IO ig
2362 int length
2363
02d1d628 2364Imager::ImgRaw
d87dc9a4 2365i_readpnm_wiol(ig, allow_incomplete)
02d1d628 2366 Imager::IO ig
d87dc9a4 2367 int allow_incomplete
02d1d628
AMH
2368
2369
2086be61
TC
2370void
2371i_readpnm_multi_wiol(ig, allow_incomplete)
2372 Imager::IO ig
2373 int allow_incomplete
2374 PREINIT:
2375 i_img **imgs;
2376 int count=0;
2377 int i;
2378 PPCODE:
2379 imgs = i_readpnm_multi_wiol(ig, &count, allow_incomplete);
2380 if (imgs) {
2381 EXTEND(SP, count);
2382 for (i = 0; i < count; ++i) {
2383 SV *sv = sv_newmortal();
2384 sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2385 PUSHs(sv);
2386 }
2387 myfree(imgs);
2388 }
2389
067d6bdc
AMH
2390undef_int
2391i_writeppm_wiol(im, ig)
2392 Imager::ImgRaw im
2393 Imager::IO ig
2394
2395
2086be61
TC
2396
2397
2398
02d1d628 2399Imager::ImgRaw
895dbd34
AMH
2400i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
2401 Imager::IO ig
8d14daab
TC
2402 i_img_dim x
2403 i_img_dim y
02d1d628
AMH
2404 int datachannels
2405 int storechannels
2406 int intrl
2407
2408undef_int
895dbd34 2409i_writeraw_wiol(im,ig)
02d1d628 2410 Imager::ImgRaw im
895dbd34
AMH
2411 Imager::IO ig
2412
261f91c5
TC
2413undef_int
2414i_writebmp_wiol(im,ig)
2415 Imager::ImgRaw im
2416 Imager::IO ig
02d1d628 2417
705fd961 2418Imager::ImgRaw
d87dc9a4 2419i_readbmp_wiol(ig, allow_incomplete=0)
705fd961 2420 Imager::IO ig
d87dc9a4 2421 int allow_incomplete
705fd961 2422
1ec86afa
AMH
2423
2424undef_int
febba01f 2425i_writetga_wiol(im,ig, wierdpack, compress, idstring)
1ec86afa
AMH
2426 Imager::ImgRaw im
2427 Imager::IO ig
febba01f
AMH
2428 int wierdpack
2429 int compress
2430 char* idstring
2431 PREINIT:
febba01f
AMH
2432 int idlen;
2433 CODE:
2434 idlen = SvCUR(ST(4));
2435 RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
2436 OUTPUT:
2437 RETVAL
2438
1ec86afa
AMH
2439
2440Imager::ImgRaw
2441i_readtga_wiol(ig, length)
2442 Imager::IO ig
2443 int length
2444
2445
737a830c
AMH
2446
2447
02d1d628
AMH
2448Imager::ImgRaw
2449i_scaleaxis(im,Value,Axis)
2450 Imager::ImgRaw im
8d14daab 2451 double Value
02d1d628
AMH
2452 int Axis
2453
2454Imager::ImgRaw
2455i_scale_nn(im,scx,scy)
2456 Imager::ImgRaw im
8d14daab
TC
2457 double scx
2458 double scy
02d1d628 2459
658f724e
TC
2460Imager::ImgRaw
2461i_scale_mixing(im, width, height)
2462 Imager::ImgRaw im
8d14daab
TC
2463 i_img_dim width
2464 i_img_dim height
658f724e 2465
02d1d628
AMH
2466Imager::ImgRaw
2467i_haar(im)
2468 Imager::ImgRaw im
2469
2470int
2471i_count_colors(im,maxc)
2472 Imager::ImgRaw im
2473 int maxc
2474
fe622da1 2475void
a60905e4
TC
2476i_get_anonymous_color_histo(im, maxc = 0x40000000)
2477 Imager::ImgRaw im
2478 int maxc
4c99febf 2479 PREINIT:
fe622da1 2480 int i;
a60905e4 2481 unsigned int * col_usage = NULL;
4c99febf
TC
2482 int col_cnt;
2483 PPCODE:
2484 col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc);
fe622da1 2485 EXTEND(SP, col_cnt);
a60905e4
TC
2486 for (i = 0; i < col_cnt; i++) {
2487 PUSHs(sv_2mortal(newSViv( col_usage[i])));
fe622da1 2488 }
fe622da1
TC
2489 myfree(col_usage);
2490 XSRETURN(col_cnt);
2491
02d1d628 2492
fb9cb3f9 2493void
19e9591b 2494i_transform(im, opx, opy, parm)
02d1d628 2495 Imager::ImgRaw im
19e9591b
TC
2496 int *opx
2497 int *opy
2498 double *parm
02d1d628 2499 PREINIT:
19e9591b 2500 STRLEN size_opx, size_opy, size_parm;
fb9cb3f9
TC
2501 i_img *result;
2502 PPCODE:
19e9591b 2503 result=i_transform(im,opx,size_opx,opy,size_opy,parm,size_parm);
fb9cb3f9
TC
2504 if (result) {
2505 SV *result_sv = sv_newmortal();
2506 EXTEND(SP, 1);
2507 sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result);
2508 PUSHs(result_sv);
2509 }
02d1d628 2510
fb9cb3f9 2511void
e5744e01
TC
2512i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
2513 SV *sv_width
2514 SV *sv_height
2515 SV *sv_ops
2516 AV *av_n_regs
2517 AV *av_c_regs
2518 AV *av_in_imgs
2519 int channels
02d1d628 2520 PREINIT:
8d14daab
TC
2521 i_img_dim width;
2522 i_img_dim height;
02d1d628 2523 struct rm_op *ops;
953209f8 2524 STRLEN ops_len;
02d1d628
AMH
2525 int ops_count;
2526 double *n_regs;
2527 int n_regs_count;
2528 i_color *c_regs;
2529 int c_regs_count;
2530 int in_imgs_count;
2531 i_img **in_imgs;
ea9e6c3f 2532 SV *sv1;
02d1d628
AMH
2533 IV tmp;
2534 int i;
fb9cb3f9
TC
2535 i_img *result;
2536 PPCODE:
e5744e01
TC
2537
2538 in_imgs_count = av_len(av_in_imgs)+1;
2539 for (i = 0; i < in_imgs_count; ++i) {
2540 sv1 = *av_fetch(av_in_imgs, i, 0);
2541 if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2542 croak("sv_in_img must contain only images");
02d1d628
AMH
2543 }
2544 }
b8c2033e 2545 if (in_imgs_count > 0) {
02d1d628
AMH
2546 in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2547 for (i = 0; i < in_imgs_count; ++i) {
e5744e01 2548 sv1 = *av_fetch(av_in_imgs,i,0);
02d1d628
AMH
2549 if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2550 croak("Parameter 5 must contain only images");
2551 }
2552 tmp = SvIV((SV*)SvRV(sv1));
e375fbd8 2553 in_imgs[i] = INT2PTR(i_img*, tmp);
02d1d628
AMH
2554 }
2555 }
2556 else {
2557 /* no input images */
2558 in_imgs = NULL;
2559 }
2560 /* default the output size from the first input if possible */
e5744e01
TC
2561 if (SvOK(sv_width))
2562 width = SvIV(sv_width);
02d1d628
AMH
2563 else if (in_imgs_count)
2564 width = in_imgs[0]->xsize;
2565 else
2566 croak("No output image width supplied");
2567
e5744e01
TC
2568 if (SvOK(sv_height))
2569 height = SvIV(sv_height);
02d1d628
AMH
2570 else if (in_imgs_count)
2571 height = in_imgs[0]->ysize;
2572 else
2573 croak("No output image height supplied");
2574
e5744e01 2575 ops = (struct rm_op *)SvPV(sv_ops, ops_len);
02d1d628
AMH
2576 if (ops_len % sizeof(struct rm_op))
2577 croak("Imager: Parameter 3 must be a bitmap of regops\n");
2578 ops_count = ops_len / sizeof(struct rm_op);
e5744e01
TC
2579
2580 n_regs_count = av_len(av_n_regs)+1;
02d1d628
AMH
2581 n_regs = mymalloc(n_regs_count * sizeof(double));
2582 for (i = 0; i < n_regs_count; ++i) {
e5744e01 2583 sv1 = *av_fetch(av_n_regs,i,0);
02d1d628
AMH
2584 if (SvOK(sv1))
2585 n_regs[i] = SvNV(sv1);
2586 }
e5744e01 2587 c_regs_count = av_len(av_c_regs)+1;
02d1d628
AMH
2588 c_regs = mymalloc(c_regs_count * sizeof(i_color));
2589 /* I don't bother initializing the colou?r registers */
2590
fb9cb3f9 2591 result=i_transform2(width, height, channels, ops, ops_count,
02d1d628
AMH
2592 n_regs, n_regs_count,
2593 c_regs, c_regs_count, in_imgs, in_imgs_count);
2594 if (in_imgs)
2595 myfree(in_imgs);
2596 myfree(n_regs);
2597 myfree(c_regs);
fb9cb3f9
TC
2598 if (result) {
2599 SV *result_sv = sv_newmortal();
2600 EXTEND(SP, 1);
2601 sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result);
2602 PUSHs(result_sv);
2603 }
02d1d628
AMH
2604
2605
2606void
2607i_contrast(im,intensity)
2608 Imager::ImgRaw im
2609 float intensity
2610
2611void
2612i_hardinvert(im)
2613 Imager::ImgRaw im
2614
5558f899
TC
2615void
2616i_hardinvertall(im)
2617 Imager::ImgRaw im
2618
02d1d628
AMH
2619void
2620i_noise(im,amount,type)
2621 Imager::ImgRaw im
2622 float amount
2623 unsigned char type
2624
2625void
2626i_bumpmap(im,bump,channel,light_x,light_y,strength)
2627 Imager::ImgRaw im
2628 Imager::ImgRaw bump
2629 int channel
8d14daab
TC
2630 i_img_dim light_x
2631 i_img_dim light_y
2632 i_img_dim strength
02d1d628 2633
b2778574
AMH
2634
2635void
2636i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
2637 Imager::ImgRaw im
2638 Imager::ImgRaw bump
2639 int channel
8d14daab
TC
2640 i_img_dim tx
2641 i_img_dim ty
2642 double Lx
2643 double Ly
2644 double Lz
b2778574
AMH
2645 float cd
2646 float cs
2647 float n
2648 Imager::Color Ia
2649 Imager::Color Il
2650 Imager::Color Is
2651
2652
2653
02d1d628
AMH
2654void
2655i_postlevels(im,levels)
2656 Imager::ImgRaw im
2657 int levels
2658
2659void
2660i_mosaic(im,size)
2661 Imager::ImgRaw im
8d14daab 2662 i_img_dim size
02d1d628
AMH
2663
2664void
2665i_watermark(im,wmark,tx,ty,pixdiff)
2666 Imager::ImgRaw im
2667 Imager::ImgRaw wmark
8d14daab
TC
2668 i_img_dim tx
2669 i_img_dim ty
02d1d628
AMH
2670 int pixdiff
2671
2672
2673void
2674i_autolevels(im,lsat,usat,skew)
2675 Imager::ImgRaw im
2676 float lsat
2677 float usat
2678 float skew
2679
2680void
2681i_radnoise(im,xo,yo,rscale,ascale)
2682 Imager::ImgRaw im
2683 float xo
2684 float yo
2685 float rscale
2686 float ascale
2687
2688void
2689i_turbnoise(im, xo, yo, scale)
2690 Imager::ImgRaw im
2691 float xo
2692 float yo
2693 float scale
2694
2695
2696void
0aaa8b4d 2697i_gradgen(im, xo, yo, ac, dmeasure)
02d1d628 2698 Imager::ImgRaw im
0aaa8b4d
TC
2699 i_img_dim *xo
2700 i_img_dim *yo
2701 i_color *ac
2702 int dmeasure
02d1d628 2703 PREINIT:
0aaa8b4d
TC
2704 STRLEN size_xo;
2705 STRLEN size_yo;
2706 STRLEN size_ac;
02d1d628 2707 CODE:
0aaa8b4d
TC
2708 if (size_xo != size_yo || size_xo != size_ac)
2709 croak("i_gradgen: x, y and color arrays must be the same size");
2710 if (size_xo < 2)
2711 croak("Usage: i_gradgen array refs must have more than 1 entry each");
2712 i_gradgen(im, size_xo, xo, yo, ac, dmeasure);
a73aeb5f 2713
dff75dee
TC
2714Imager::ImgRaw
2715i_diff_image(im, im2, mindist=0)
2716 Imager::ImgRaw im
2717 Imager::ImgRaw im2
01b84320 2718 double mindist
02d1d628 2719
e310e5f9 2720undef_int
6607600c
TC
2721i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2722 Imager::ImgRaw im
2723 double xa
2724 double ya
2725 double xb
2726 double yb
2727 int type
2728 int repeat
2729 int combine
2730 int super_sample
2731 double ssample_param
2732 PREINIT:
6607600c 2733 AV *asegs;
6607600c
TC
2734 int count;
2735 i_fountain_seg *segs;
6607600c 2736 CODE:
6607600c
TC
2737 if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
2738 croak("i_fountain: argument 11 must be an array ref");
2739
2740 asegs = (AV *)SvRV(ST(10));
b13a3ddb 2741 segs = load_fount_segs(aTHX_ asegs, &count);
e310e5f9
TC
2742 RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine,
2743 super_sample, ssample_param, count, segs);
6607600c 2744 myfree(segs);
e310e5f9
TC
2745 OUTPUT:
2746 RETVAL
02d1d628 2747
f1ac5027
TC
2748Imager::FillHandle
2749i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2750 double xa
2751 double ya
2752 double xb
2753 double yb
2754 int type
2755 int repeat
2756 int combine
2757 int super_sample
2758 double ssample_param
2759 PREINIT:
2760 AV *asegs;
2761 int count;
2762 i_fountain_seg *segs;
2763 CODE:
2764 if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
2765 croak("i_fountain: argument 11 must be an array ref");
2766
2767 asegs = (AV *)SvRV(ST(9));
b13a3ddb 2768 segs = load_fount_segs(aTHX_ asegs, &count);
f1ac5027
TC
2769 RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine,
2770 super_sample, ssample_param, count, segs);
2771 myfree(segs);
2772 OUTPUT:
2773 RETVAL
2774
52f2b10a
TC
2775Imager::FillHandle
2776i_new_fill_opacity(other_fill, alpha_mult)
2777 Imager::FillHandle other_fill
2778 double alpha_mult
2779
4f4f776a
TC
2780void
2781i_errors()
2782 PREINIT:
2783 i_errmsg *errors;
2784 int i;
4f4f776a 2785 AV *av;
4f4f776a
TC
2786 SV *sv;
2787 PPCODE:
2788 errors = i_errors();
2789 i = 0;
2790 while (errors[i].msg) {
2791 av = newAV();
2792 sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
2793 if (!av_store(av, 0, sv)) {
2794 SvREFCNT_dec(sv);
2795 }
2796 sv = newSViv(errors[i].code);
2797 if (!av_store(av, 1, sv)) {
2798 SvREFCNT_dec(sv);
2799 }
2800 PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
2801 ++i;
2802 }
02d1d628 2803
2b405c9e
TC
2804void
2805i_clear_error()
2806
2807void
2808i_push_error(code, msg)
2809 int code
2810 const char *msg
2811
e310e5f9 2812undef_int
02d1d628
AMH
2813i_nearest_color(im, ...)
2814 Imager::ImgRaw im
2815 PREINIT:
2816 int num;
8d14daab
TC
2817 i_img_dim *xo;
2818 i_img_dim *yo;
02d1d628
AMH
2819 i_color *ival;
2820 int dmeasure;
2821 int i;
2822 SV *sv;
2823 AV *axx;
2824 AV *ayy;
2825 AV *ac;
2826 CODE:
2827 if (items != 5)
2828 croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
2829 if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2830 croak("i_nearest_color: Second argument must be an array ref");
2831 if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2832 croak("i_nearest_color: Third argument must be an array ref");
2833 if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2834 croak("i_nearest_color: Fourth argument must be an array ref");
2835 axx = (AV *)SvRV(ST(1));
2836 ayy = (AV *)SvRV(ST(2));
2837 ac = (AV *)SvRV(ST(3));
2838 dmeasure = (int)SvIV(ST(4));
2839
2840 num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2841 num = num <= av_len(ac) ? num : av_len(ac);
2842 num++;
2843 if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
8d14daab
TC
2844 xo = mymalloc( sizeof(i_img_dim) * num );
2845 yo = mymalloc( sizeof(i_img_dim) * num );
02d1d628
AMH
2846 ival = mymalloc( sizeof(i_color) * num );
2847 for(i = 0; i<num; i++) {
8d14daab
TC
2848 xo[i] = (i_img_dim)SvIV(* av_fetch(axx, i, 0));
2849 yo[i] = (i_img_dim)SvIV(* av_fetch(ayy, i, 0));
02d1d628
AMH
2850 sv = *av_fetch(ac, i, 0);
2851 if ( !sv_derived_from(sv, "Imager::Color") ) {
2852 free(axx); free(ayy); free(ac);
2853 croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
2854 }
4c4c2ffd 2855 ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
02d1d628 2856 }
e310e5f9
TC
2857 RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
2858 OUTPUT:
2859 RETVAL
02d1d628
AMH
2860
2861void
2862malloc_state()
2863
02d1d628
AMH
2864void
2865DSO_open(filename)
2866 char* filename
2867 PREINIT:
2868 void *rc;
2869 char *evstr;
2870 PPCODE:
2871 rc=DSO_open(filename,&evstr);
2872 if (rc!=NULL) {
2873 if (evstr!=NULL) {
2874 EXTEND(SP,2);
e375fbd8 2875 PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
02d1d628
AMH
2876 PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
2877 } else {
2878 EXTEND(SP,1);
e375fbd8 2879 PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
02d1d628
AMH
2880 }
2881 }
2882
2883
2884undef_int
2885DSO_close(dso_handle)
2886 void* dso_handle
2887
2888void
2889DSO_funclist(dso_handle_v)
2890 void* dso_handle_v
2891 PREINIT:
2892 int i;
2893 DSO_handle *dso_handle;
d8e0c3ba 2894 func_ptr *functions;
02d1d628
AMH
2895 PPCODE:
2896 dso_handle=(DSO_handle*)dso_handle_v;
d8e0c3ba 2897 functions = DSO_funclist(dso_handle);
02d1d628 2898 i=0;
d8e0c3ba 2899 while( functions[i].name != NULL) {
02d1d628 2900 EXTEND(SP,1);
d8e0c3ba 2901 PUSHs(sv_2mortal(newSVpv(functions[i].name,0)));
02d1d628 2902 EXTEND(SP,1);
d8e0c3ba 2903 PUSHs(sv_2mortal(newSVpv(functions[i++].pcode,0)));
02d1d628
AMH
2904 }
2905
02d1d628
AMH
2906void
2907DSO_call(handle,func_index,hv)
2908 void* handle
2909 int func_index
75cebca8 2910 HV *hv
02d1d628 2911 PPCODE:
02d1d628
AMH
2912 DSO_call( (DSO_handle *)handle,func_index,hv);
2913
befd4be1 2914Imager::Color
f5991c03
TC
2915i_get_pixel(im, x, y)
2916 Imager::ImgRaw im
8d14daab
TC
2917 i_img_dim x
2918 i_img_dim y;
faa9b3e7 2919 CODE:
befd4be1
TC
2920 RETVAL = (i_color *)mymalloc(sizeof(i_color));
2921 if (i_gpix(im, x, y, RETVAL) != 0) {
2922 myfree(RETVAL);
2923 XSRETURN_UNDEF;
faa9b3e7 2924 }
a659442a
TC
2925 OUTPUT:
2926 RETVAL
faa9b3e7
TC
2927
2928
2929int
2930i_ppix(im, x, y, cl)
2931 Imager::ImgRaw im
8d14daab
TC
2932 i_img_dim x
2933 i_img_dim y
faa9b3e7
TC
2934 Imager::Color cl
2935
2936Imager::ImgRaw
2937i_img_pal_new(x, y, channels, maxpal)
8d14daab
TC
2938 i_img_dim x
2939 i_img_dim y
faa9b3e7
TC
2940 int channels
2941 int maxpal
2942
2943Imager::ImgRaw
2944i_img_to_pal(src, quant)
2945 Imager::ImgRaw src
2946 PREINIT:
2947 HV *hv;
2948 i_quantize quant;
2949 CODE:
2950 if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2951 croak("i_img_to_pal: second argument must be a hash ref");
2952 hv = (HV *)SvRV(ST(1));
2953 memset(&quant, 0, sizeof(quant));
ec6d8908 2954 quant.version = 1;
faa9b3e7 2955 quant.mc_size = 256;
ec6d8908 2956 ip_handle_quant_opts(aTHX_ &quant, hv);
faa9b3e7
TC
2957 RETVAL = i_img_to_pal(src, &quant);
2958 if (RETVAL) {
ec6d8908 2959 ip_copy_colors_back(aTHX_ hv, &quant);
faa9b3e7 2960 }
ec6d8908 2961 ip_cleanup_quant_opts(aTHX_ &quant);
faa9b3e7
TC
2962 OUTPUT:
2963 RETVAL
2964
2965Imager::ImgRaw
2966i_img_to_rgb(src)
2967 Imager::ImgRaw src
2968
5e9a7fbd
TC
2969void
2970i_img_make_palette(HV *quant_hv, ...)
2971 PREINIT:
2972 size_t count = items - 1;
2973 i_quantize quant;
2974 i_img **imgs = NULL;
2975 ssize_t i;
2976 PPCODE:
2977 if (count <= 0)
2978 croak("Please supply at least one image (%d)", (int)count);
2979 imgs = mymalloc(sizeof(i_img *) * count);
2980 for (i = 0; i < count; ++i) {
2981 SV *img_sv = ST(i + 1);
2982 if (SvROK(img_sv) && sv_derived_from(img_sv, "Imager::ImgRaw")) {
2983 imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(img_sv)));
2984 }
2985 else {
2986 myfree(imgs);
ec2f6280 2987 croak("Image %d is not an image object", (int)i+1);
5e9a7fbd
TC
2988 }
2989 }
2990 memset(&quant, 0, sizeof(quant));
2991 quant.version = 1;
2992 quant.mc_size = 256;
2993 ip_handle_quant_opts(aTHX_ &quant, quant_hv);
2994 i_quant_makemap(&quant, imgs, count);
2995 EXTEND(SP, quant.mc_count);
2996 for (i = 0; i < quant.mc_count; ++i) {
2997 SV *sv_c = make_i_color_sv(aTHX_ quant.mc_colors + i);
2998 PUSHs(sv_c);
2999 }
3000 ip_cleanup_quant_opts(aTHX_ &quant);
3001
3002
faa9b3e7
TC
3003void
3004i_gpal(im, l, r, y)
3005 Imager::ImgRaw im
8d14daab
TC
3006 i_img_dim l
3007 i_img_dim r
3008 i_img_dim y
faa9b3e7
TC
3009 PREINIT:
3010 i_palidx *work;
3011 int count, i;
3012 PPCODE:
3013 if (l < r) {
3014 work = mymalloc((r-l) * sizeof(i_palidx));
3015 count = i_gpal(im, l, r, y, work);
3016 if (GIMME_V == G_ARRAY) {
3017 EXTEND(SP, count);
3018 for (i = 0; i < count; ++i) {
3019 PUSHs(sv_2mortal(newSViv(work[i])));
3020 }
3021 }
3022 else {
3023 EXTEND(SP, 1);
26fd367b 3024 PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
faa9b3e7
TC
3025 }
3026 myfree(work);
3027 }
3028 else {
3029 if (GIMME_V != G_ARRAY) {
3030 EXTEND(SP, 1);
3031 PUSHs(&PL_sv_undef);
3032 }
3033 }
3034
3035int
3036i_ppal(im, l, y, ...)
3037 Imager::ImgRaw im
8d14daab
TC
3038 i_img_dim l
3039 i_img_dim y
faa9b3e7
TC
3040 PREINIT:
3041 i_palidx *work;
ebe9b189 3042 i_img_dim i;
faa9b3e7
TC
3043 CODE:
3044 if (items > 3) {
ebe9b189 3045 work = malloc_temp(aTHX_ sizeof(i_palidx) * (items-3));
faa9b3e7
TC
3046 for (i=0; i < items-3; ++i) {
3047 work[i] = SvIV(ST(i+3));
3048 }
4cda4e76 3049 validate_i_ppal(im, work, items - 3);
faa9b3e7 3050 RETVAL = i_ppal(im, l, l+items-3, y, work);
faa9b3e7
TC
3051 }
3052 else {
3053 RETVAL = 0;
3054 }
3055 OUTPUT:
3056 RETVAL
3057
4cda4e76
TC
3058int
3059i_ppal_p(im, l, y, data)
3060 Imager::ImgRaw im
8d14daab
TC
3061 i_img_dim l
3062 i_img_dim y
4cda4e76
TC
3063 SV *data
3064 PREINIT:
3065 i_palidx const *work;
4cda4e76 3066 STRLEN len;
4cda4e76
TC
3067 CODE:
3068 work = (i_palidx const *)SvPV(data, len);
3069 len /= sizeof(i_palidx);
3070 if (len > 0) {
3071 validate_i_ppal(im, work, len);
3072 RETVAL = i_ppal(im, l, l+len, y, work);
3073 }
3074 else {
3075 RETVAL = 0;
3076 }
3077 OUTPUT:
3078 RETVAL
3079
42505e61 3080SysRet
faa9b3e7
TC
3081i_addcolors(im, ...)
3082 Imager::ImgRaw im
3083 PREINIT:
faa9b3e7
TC
3084 i_color *colors;
3085 int i;
3086 CODE:
3087 if (items < 2)
3088 croak("i_addcolors: no colors to add");
3089 colors = mymalloc((items-1) * sizeof(i_color));
3090 for (i=0; i < items-1; ++i) {
3091 if (sv_isobject(ST(i+1))
3092 && sv_derived_from(ST(i+1), "Imager::Color")) {
3093 IV tmp = SvIV((SV *)SvRV(ST(i+1)));
4c4c2ffd 3094 colors[i] = *INT2PTR(i_color *, tmp);
faa9b3e7
TC
3095 }
3096 else {
3097 myfree(colors);
ca4d914e 3098 croak("i_addcolor: pixels must be Imager::Color objects");
faa9b3e7
TC
3099 }
3100 }
42505e61 3101 RETVAL = i_addcolors(im, colors, items-1);
a659442a
TC
3102 OUTPUT:
3103 RETVAL
faa9b3e7 3104
1501d9b3 3105undef_int
faa9b3e7
TC
3106i_setcolors(im, index, ...)
3107 Imager::ImgRaw im
3108 int index
3109 PREINIT:
3110 i_color *colors;
3111 int i;
3112 CODE:
3113 if (items < 3)
3114 croak("i_setcolors: no colors to add");
3115 colors = mymalloc((items-2) * sizeof(i_color));
3116 for (i=0; i < items-2; ++i) {
3117 if (sv_isobject(ST(i+2))
3118 && sv_derived_from(ST(i+2), "Imager::Color")) {
3119 IV tmp = SvIV((SV *)SvRV(ST(i+2)));
4c4c2ffd 3120 colors[i] = *INT2PTR(i_color *, tmp);
faa9b3e7
TC
3121 }
3122 else {
3123 myfree(colors);
3124 croak("i_setcolors: pixels must be Imager::Color objects");
3125 }
3126 }
3127 RETVAL = i_setcolors(im, index, colors, items-2);
3128 myfree(colors);
1501d9b3
TC
3129 OUTPUT:
3130 RETVAL
faa9b3e7
TC
3131
3132void
1592522f 3133i_getcolors(im, index, count=1)
faa9b3e7
TC
3134 Imager::ImgRaw im
3135 int index
1592522f 3136 int count
faa9b3e7
TC
3137 PREINIT:
3138 i_color *colors;
faa9b3e7
TC
3139 int i;
3140 PPCODE:
faa9b3e7
TC
3141 if (count < 1)
3142 croak("i_getcolors: count must be positive");
1592522f 3143 colors = malloc_temp(aTHX_ sizeof(i_color) * count);
faa9b3e7 3144 if (i_getcolors(im, index, colors, count)) {
1592522f 3145 EXTEND(SP, count);
faa9b3e7 3146 for (i = 0; i < count; ++i) {
5e9a7fbd 3147 SV *sv = make_i_color_sv(aTHX_ colors+i);
faa9b3e7
TC
3148 PUSHs(sv);
3149 }
3150 }
faa9b3e7 3151
a659442a 3152undef_neg_int
faa9b3e7
TC
3153i_colorcount(im)
3154 Imager::ImgRaw im
faa9b3e7 3155
a659442a 3156undef_neg_int
faa9b3e7
TC
3157i_maxcolors(im)
3158 Imager::ImgRaw im
faa9b3e7 3159
0862f397 3160i_palidx
faa9b3e7
TC
3161i_findcolor(im, color)
3162 Imager::ImgRaw im
3163 Imager::Color color
faa9b3e7 3164 CODE:
0862f397
TC
3165 if (!i_findcolor(im, color, &RETVAL)) {
3166 XSRETURN_UNDEF;
faa9b3e7 3167 }
a659442a
TC
3168 OUTPUT:
3169 RETVAL
faa9b3e7
TC
3170
3171int
3172i_img_bits(im)
3173 Imager::ImgRaw im
3174
3175int
3176i_img_type(im)
3177 Imager::ImgRaw im
3178
3179int
3180i_img_virtual(im)
3181 Imager::ImgRaw im
3182
3183void
6a9807e8 3184i_gsamp(im, l, r, y, channels)
faa9b3e7 3185 Imager::ImgRaw im
8d14daab
TC
3186 i_img_dim l
3187 i_img_dim r
3188 i_img_dim y
6a9807e8 3189 i_channel_list channels
faa9b3e7 3190 PREINIT:
faa9b3e7 3191 i_sample_t *data;
8d14daab 3192 i_img_dim count, i;
faa9b3e7 3193 PPCODE:
faa9b3e7 3194 if (l < r) {
f37708ce 3195 data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count);
6a9807e8 3196 count = i_gsamp(im, l, r, y, data, channels.channels, channels.count);
faa9b3e7
TC
3197 if (GIMME_V == G_ARRAY) {
3198 EXTEND(SP, count);
3199 for (i = 0; i < count; ++i)
3200 PUSHs(sv_2mortal(newSViv(data[i])));
3201 }
3202 else {
3203 EXTEND(SP, 1);
26fd367b 3204 PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
faa9b3e7 3205 }
a73aeb5f 3206 myfree(data);
faa9b3e7
TC
3207 }
3208 else {
3209 if (GIMME_V != G_ARRAY) {
f37708ce 3210 XSRETURN_UNDEF;
faa9b3e7
TC
3211 }
3212 }
3213
bd8052a6 3214undef_neg_int
6a9807e8 3215i_gsamp_bits(im, l, r, y, bits, target, offset, channels)
bd8052a6 3216 Imager::ImgRaw im
8d14daab
TC
3217 i_img_dim l
3218 i_img_dim r
3219 i_img_dim y
bd8052a6
TC
3220 int bits
3221 AV *target
8d14daab 3222 STRLEN offset
6a9807e8 3223 i_channel_list channels
bd8052a6 3224 PREINIT:
bd8052a6 3225 unsigned *data;
8d14daab 3226 i_img_dim count, i;
bd8052a6
TC
3227 CODE:
3228 i_clear_error();
3229 if (items < 8)
3230 croak("No channel numbers supplied to g_samp()");
3231 if (l < r) {
6a9807e8
TC
3232 data = mymalloc(sizeof(unsigned) * (r-l) * channels.count);
3233 count = i_gsamp_bits(im, l, r, y, data, channels.channels, channels.count, bits);
bd8052a6
TC
3234 for (i = 0; i < count; ++i) {
3235 av_store(target, i+offset, newSVuv(data[i]));
3236 }
3237 myfree(data);
3238 RETVAL = count;
3239 }
3240 else {
3241 RETVAL = 0;
3242 }
3243 OUTPUT:
3244 RETVAL
3245
3246undef_neg_int
6a9807e8 3247i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -1)
bd8052a6 3248 Imager::ImgRaw im
8d14daab
TC
3249 i_img_dim l
3250 i_img_dim y
bd8052a6 3251 int bits
6a9807e8 3252 i_channel_list channels
bd8052a6 3253 AV *data_av
848b7f32
TC
3254 i_img_dim data_offset
3255 i_img_dim pixel_count
bd8052a6 3256 PREINIT:
8d14daab
TC
3257 STRLEN data_count;
3258 size_t data_used;
bd8052a6 3259 unsigned *data;
8d14daab 3260 ptrdiff_t i;
bd8052a6
TC
3261 CODE:
3262 i_clear_error();
bd8052a6
TC
3263
3264 data_count = av_len(data_av) + 1;
3265 if (data_offset < 0) {
848b7f32 3266 croak("data_offset must be non-negative");
bd8052a6
TC
3267 }
3268 if (data_offset > data_count) {
3269 croak("data_offset greater than number of samples supplied");
3270 }
3271 if (pixel_count == -1 ||
6a9807e8
TC
3272 data_offset + pixel_count * channels.count > data_count) {
3273 pixel_count = (data_count - data_offset) / channels.count;
bd8052a6
TC
3274 }
3275
6a9807e8 3276 data_used = pixel_count * channels.count;
bd8052a6
TC
3277 data = mymalloc(sizeof(unsigned) * data_count);
3278 for (i = 0; i < data_used; ++i)
3279 data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0));
3280
6a9807e8
TC
3281 RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels.channels,
3282 channels.count, bits);
bd8052a6
TC
3283
3284 if (data)
3285 myfree(data);
bd8052a6
TC
3286 OUTPUT:
3287 RETVAL
a73aeb5f 3288
48b9a7bf 3289undef_neg_int
848b7f32 3290i_psamp(im, x, y, channels, data, offset = 0, width = -1)
48b9a7bf
TC
3291 Imager::ImgRaw im
3292 i_img_dim x
3293 i_img_dim y
3294 i_channel_list channels
3295 i_sample_list data
848b7f32
TC
3296 i_img_dim offset
3297 i_img_dim width
48b9a7bf
TC
3298 PREINIT:
3299 i_img_dim r;
3300 CODE:
48b9a7bf 3301 i_clear_error();
848b7f32
TC
3302 if (offset < 0) {
3303 i_push_error(0, "offset must be non-negative");
3304 XSRETURN_UNDEF;
3305 }
3306 if (offset > 0) {
3307 if (offset > data.count) {
3308 i_push_error(0, "offset greater than number of samples supplied");
3309 XSRETURN_UNDEF;
3310 }
3311 data.samples += offset;
3312 data.count -= offset;
3313 }
3314 if (width == -1 ||
3315 width * channels.count > data.count) {
3316 width = data.count / channels.count;
3317 }
3318 r = x + width;
48b9a7bf
TC
3319 RETVAL = i_psamp(im, x, r, y, data.samples, channels.channels, channels.count);
3320 OUTPUT:
3321 RETVAL
3322
3323undef_neg_int
848b7f32 3324i_psampf(im, x, y, channels, data, offset = 0, width = -1)
48b9a7bf
TC
3325 Imager::ImgRaw im
3326 i_img_dim x
3327 i_img_dim y
3328 i_channel_list channels
3329 i_fsample_list data
848b7f32
TC
3330 i_img_dim offset
3331 i_img_dim width
48b9a7bf
TC
3332 PREINIT:
3333 i_img_dim r;
3334 CODE:
48b9a7bf 3335 i_clear_error();
848b7f32
TC
3336 if (offset < 0) {
3337 i_push_error(0, "offset must be non-negative");
3338 XSRETURN_UNDEF;
3339 }
3340 if (offset > 0) {
3341 if (offset > data.count) {
3342 i_push_error(0, "offset greater than number of samples supplied");
3343 XSRETURN_UNDEF;
3344 }
3345 data.samples += offset;
3346 data.count -= offset;
3347 }
3348 if (width == -1 ||
3349 width * channels.count > data.count) {
3350 width = data.count / channels.count;
3351 }
3352 r = x + width;
48b9a7bf
TC
3353 RETVAL = i_psampf(im, x, r, y, data.samples, channels.channels, channels.count);
3354 OUTPUT:
3355 RETVAL
3356
faa9b3e7
TC
3357Imager::ImgRaw
3358i_img_masked_new(targ, mask, x, y, w, h)
3359 Imager::ImgRaw targ
8d14daab
TC
3360 i_img_dim x
3361 i_img_dim y
3362 i_img_dim w
3363 i_img_dim h
faa9b3e7
TC
3364 PREINIT:
3365 i_img *mask;
3366 CODE:
3367 if (SvOK(ST(1))) {
3368 if (!sv_isobject(ST(1))
3369 || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3370 croak("i_img_masked_new: parameter 2 must undef or an image");
3371 }
4c4c2ffd 3372 mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
faa9b3e7
TC
3373 }
3374 else
3375 mask = NULL;
3376 RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3377 OUTPUT:
3378 RETVAL
3379
3380int
3381i_plin(im, l, y, ...)
3382 Imager::ImgRaw im
8d14daab
TC
3383 i_img_dim l
3384 i_img_dim y
faa9b3e7
TC
3385 PREINIT:
3386 i_color *work;
8d14daab 3387 STRLEN i;
ca4d914e 3388 STRLEN len;
8d14daab 3389 size_t count;
faa9b3e7
TC
3390 CODE:
3391 if (items > 3) {
ca4d914e
TC
3392 if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3393 /* supplied as a byte string */
3394 work = (i_color *)SvPV(ST(3), len);
3395 count = len / sizeof(i_color);
3396 if (count * sizeof(i_color) != len) {
3397 croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
faa9b3e7 3398 }
ca4d914e
TC
3399 RETVAL = i_plin(im, l, l+count, y, work);
3400 }
3401 else {
3402 work = mymalloc(sizeof(i_color) * (items-3));
3403 for (i=0; i < items-3; ++i) {
3404 if (sv_isobject(ST(i+3))
3405 && sv_derived_from(ST(i+3), "Imager::Color")) {
3406 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3407 work[i] = *INT2PTR(i_color *, tmp);
3408 }
3409 else {
3410 myfree(work);
3411 croak("i_plin: pixels must be Imager::Color objects");
3412 }
faa9b3e7 3413 }
ca4d914e
TC
3414 RETVAL = i_plin(im, l, l+items-3, y, work);
3415 myfree(work);
faa9b3e7 3416 }
faa9b3e7
TC
3417 }
3418 else {
3419 RETVAL = 0;
3420 }
3421 OUTPUT:
3422 RETVAL
3423
3424int
3425i_ppixf(im, x, y, cl)
3426 Imager::ImgRaw im
8d14daab
TC
3427 i_img_dim x
3428 i_img_dim y
faa9b3e7
TC
3429 Imager::Color::Float cl
3430
3431void
6a9807e8 3432i_gsampf(im, l, r, y, channels)
faa9b3e7 3433 Imager::ImgRaw im
8d14daab
TC
3434 i_img_dim l
3435 i_img_dim r
3436 i_img_dim y
6a9807e8 3437 i_channel_list channels
faa9b3e7 3438 PREINIT:
faa9b3e7 3439 i_fsample_t *data;
8d14daab 3440 i_img_dim count, i;
faa9b3e7 3441 PPCODE:
faa9b3e7 3442 if (l < r) {
6a9807e8
TC
3443 data = mymalloc(sizeof(i_fsample_t) * (r-l) * channels.count);
3444 count = i_gsampf(im, l, r, y, data, channels.channels, channels.count);
faa9b3e7
TC
3445 if (GIMME_V == G_ARRAY) {
3446 EXTEND(SP, count);
3447 for (i = 0; i < count; ++i)
3448 PUSHs(sv_2mortal(newSVnv(data[i])));
3449 }
3450 else {
3451 EXTEND(SP, 1);
3452 PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3453 }
3631271b 3454 myfree(data);
faa9b3e7
TC
3455 }
3456 else {
3457 if (GIMME_V != G_ARRAY) {
5736f588 3458 XSRETURN_UNDEF;
faa9b3e7
TC
3459 }
3460 }
3461
3462int
3463i_plinf(im, l, y, ...)
3464 Imager::ImgRaw im
8d14daab
TC
3465 i_img_dim l
3466 i_img_dim y
faa9b3e7
TC
3467 PREINIT:
3468 i_fcolor *work;
8d14daab 3469 i_img_dim i;
ca4d914e 3470 STRLEN len;
8d14daab 3471 size_t count;
faa9b3e7
TC
3472 CODE:
3473 if (items > 3) {
ca4d914e
TC
3474 if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3475 /* supplied as a byte string */
3476 work = (i_fcolor *)SvPV(ST(3), len);
3477 count = len / sizeof(i_fcolor);
3478 if (count * sizeof(i_fcolor) != len) {
3479 croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
faa9b3e7 3480 }
ca4d914e
TC
3481 RETVAL = i_plinf(im, l, l+count, y, work);
3482 }
3483 else {
3484 work = mymalloc(sizeof(i_fcolor) * (items-3));
3485 for (i=0; i < items-3; ++i) {
3486 if (sv_isobject(ST(i+3))
3487 && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3488 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3489 work[i] = *INT2PTR(i_fcolor *, tmp);
3490 }
3491 else {
3492 myfree(work);
3493 croak("i_plinf: pixels must be Imager::Color::Float objects");
3494 }
faa9b3e7 3495 }
ca4d914e
TC
3496 /**(char *)0 = 1;*/
3497 RETVAL = i_plinf(im, l, l+items-3, y, work);
3498 myfree(work);
faa9b3e7 3499 }
faa9b3e7
TC
3500 }
3501 else {
3502 RETVAL = 0;
3503 }
3504 OUTPUT:
3505 RETVAL
3506
73d80423 3507Imager::Color::Float
faa9b3e7
TC
3508i_gpixf(im, x, y)
3509 Imager::ImgRaw im
8d14daab
TC
3510 i_img_dim x
3511 i_img_dim y;
faa9b3e7 3512 CODE:
73d80423
TC
3513 RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3514 if (i_gpixf(im, x, y, RETVAL) != 0) {
3515 myfree(RETVAL);
3516 XSRETURN_UNDEF;
faa9b3e7 3517 }
a659442a
TC
3518 OUTPUT:
3519 RETVAL
3520
faa9b3e7
TC
3521void
3522i_glin(im, l, r, y)
3523 Imager::ImgRaw im
8d14daab
TC
3524 i_img_dim l
3525 i_img_dim r
3526 i_img_dim y
faa9b3e7
TC
3527 PREINIT:
3528 i_color *vals;
8d14daab 3529 i_img_dim count, i;
faa9b3e7
TC
3530 PPCODE:
3531 if (l < r) {
3532 vals = mymalloc((r-l) * sizeof(i_color));
b3aa972f 3533 memset(vals, 0, (r-l) * sizeof(i_color));
faa9b3e7 3534 count = i_glin(im, l, r, y, vals);
ca4d914e
TC
3535 if (GIMME_V == G_ARRAY) {
3536 EXTEND(SP, count);
3537 for (i = 0; i < count; ++i) {
5e9a7fbd 3538 SV *sv = make_i_color_sv(aTHX_ vals+i);
ca4d914e
TC
3539 PUSHs(sv);
3540 }
3541 }
3542 else if (count) {
3543 EXTEND(SP, 1);
3544 PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
faa9b3e7
TC
3545 }
3546 myfree(vals);
3547 }
3548
3549void
3550i_glinf(im, l, r, y)
3551 Imager::ImgRaw im
8d14daab
TC
3552 i_img_dim l
3553 i_img_dim r
3554 i_img_dim y
faa9b3e7
TC
3555 PREINIT:
3556 i_fcolor *vals;
8d14daab 3557 i_img_dim count, i;
919e0000 3558 i_fcolor zero;
faa9b3e7 3559 PPCODE:
919e0000
TC
3560 for (i = 0; i < MAXCHANNELS; ++i)
3561 zero.channel[i] = 0;
faa9b3e7
TC
3562 if (l < r) {
3563 vals = mymalloc((r-l) * sizeof(i_fcolor));
b3aa972f
TC
3564 for (i = 0; i < r-l; ++i)
3565 vals[i] = zero;
faa9b3e7 3566 count = i_glinf(im, l, r, y, vals);
ca4d914e
TC
3567 if (GIMME_V == G_ARRAY) {
3568 EXTEND(SP, count);
3569 for (i = 0; i < count; ++i) {
3570 SV *sv;
3571 i_fcolor *col = mymalloc(sizeof(i_fcolor));
3572 *col = vals[i];
3573 sv = sv_newmortal();
3574 sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3575 PUSHs(sv);
3576 }
3577 }
3578 else if (count) {
3579 EXTEND(SP, 1);
3580 PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
faa9b3e7
TC
3581 }
3582 myfree(vals);
3583 }
3584
bdd4c63b
TC
3585Imager::ImgRaw
3586i_img_8_new(x, y, ch)
3587 i_img_dim x
3588 i_img_dim y
3589 int ch
3590
faa9b3e7
TC
3591Imager::ImgRaw
3592i_img_16_new(x, y, ch)
8d14daab
TC
3593 i_img_dim x
3594 i_img_dim y
faa9b3e7
TC
3595 int ch
3596
167660cd
TC
3597Imager::ImgRaw
3598i_img_to_rgb16(im)
3599 Imager::ImgRaw im
3600
365ea842
TC
3601Imager::ImgRaw
3602i_img_double_new(x, y, ch)
8d14daab
TC
3603 i_img_dim x
3604 i_img_dim y
365ea842
TC
3605 int ch
3606
bfe6ba3f
TC
3607Imager::ImgRaw
3608i_img_to_drgb(im)
3609 Imager::ImgRaw im
3610
faa9b3e7 3611undef_int
b9e2571f 3612i_tags_addn(im, name_sv, code, idata)
faa9b3e7 3613 Imager::ImgRaw im
b9e2571f 3614 SV *name_sv
faa9b3e7
TC
3615 int code
3616 int idata
3617 PREINIT:
3618 char *name;
3619 STRLEN len;
3620 CODE:
b9e2571f
TC
3621 SvGETMAGIC(name_sv);
3622 if (SvOK(name_sv))
3623 name = SvPV_nomg(name_sv, len);
faa9b3e7
TC
3624 else
3625 name = NULL;
3626 RETVAL = i_tags_addn(&im->tags, name, code, idata);
3627 OUTPUT:
3628 RETVAL
3629
3630undef_int
a4da28d7 3631i_tags_add(im, name_sv, code, data_sv, idata)
faa9b3e7 3632 Imager::ImgRaw im
a4da28d7 3633 SV *name_sv
faa9b3e7 3634 int code
a4da28d7 3635 SV *data_sv
faa9b3e7
TC
3636 int idata
3637 PREINIT:
3638 char *name;
3639 char *data;
3640 STRLEN len;
3641 CODE:
a4da28d7
TC
3642 SvGETMAGIC(name_sv);
3643 if (SvOK(name_sv))
3644 name = SvPV_nomg(name_sv, len);
faa9b3e7
TC
3645 else
3646 name = NULL;
a4da28d7
TC
3647 SvGETMAGIC(data_sv);
3648 if (SvOK(data_sv))
3649 data = SvPV(data_sv, len);
faa9b3e7
TC
3650 else {
3651 data = NULL;
3652 len = 0;
3653 }
3654 RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3655 OUTPUT:
3656 RETVAL
3657
f4aca831 3658SysRet
faa9b3e7
TC
3659i_tags_find(im, name, start)
3660 Imager::ImgRaw im
3661 char *name
3662 int start
3663 PREINIT:
3664 int entry;
3665 CODE:
3666 if (i_tags_find(&im->tags, name, start, &entry)) {
f4aca831 3667 RETVAL = entry;
faa9b3e7 3668 } else {
f4aca831 3669 XSRETURN_UNDEF;
faa9b3e7 3670 }
a659442a
TC
3671 OUTPUT:
3672 RETVAL
faa9b3e7 3673
f4aca831 3674SysRet
faa9b3e7
TC
3675i_tags_findn(im, code, start)
3676 Imager::ImgRaw im
3677 int code
3678 int start
3679 PREINIT:
3680 int entry;
3681 CODE:
3682 if (i_tags_findn(&im->tags, code, start, &entry)) {
f4aca831 3683 RETVAL = entry;
faa9b3e7 3684 }
a659442a 3685 else {
f4aca831 3686 XSRETURN_UNDEF;
a659442a
TC
3687 }
3688 OUTPUT:
3689 RETVAL
faa9b3e7
TC
3690
3691int
3692i_tags_delete(im, entry)
3693 Imager::ImgRaw im
3694 int entry
3695 CODE:
3696 RETVAL = i_tags_delete(&im->tags, entry);
3697 OUTPUT:
3698 RETVAL
3699
3700int
3701i_tags_delbyname(im, name)
3702 Imager::ImgRaw im
3703 char * name
3704 CODE:
3705 RETVAL = i_tags_delbyname(&im->tags, name);
3706 OUTPUT:
3707 RETVAL
3708
3709int
3710i_tags_delbycode(im, code)
3711 Imager::ImgRaw im
3712 int code
3713 CODE:
3714 RETVAL = i_tags_delbycode(&im->tags, code);
3715 OUTPUT:
3716 RETVAL
3717
3718void
3719i_tags_get(im, index)
3720 Imager::ImgRaw im
3721 int index
3722 PPCODE:
3723 if (index >= 0 && index < im->tags.count) {
3724 i_img_tag *entry = im->tags.tags + index;
3725 EXTEND(SP, 5);
3726
3727 if (entry->name) {
3728 PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3729 }
3730 else {
3731 PUSHs(sv_2mortal(newSViv(entry->code)));
3732 }
3733 if (entry->data) {
3734 PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3735 }
3736 else {
3737 PUSHs(sv_2mortal(newSViv(entry->idata)));
3738 }
3739 }
3740
241defe8
TC
3741void
3742i_tags_get_string(im, what_sv)
3743 Imager::ImgRaw im
3744 SV *what_sv
3745 PREINIT:
3746 char const *name = NULL;
3747 int code;
3748 char buffer[200];
241defe8
TC
3749 PPCODE:
3750 if (SvIOK(what_sv)) {
3751 code = SvIV(what_sv);
3752 name = NULL;
3753 }
3754 else {
3755 name = SvPV_nolen(what_sv);
3756 code = 0;
3757 }
3758 if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
3759 EXTEND(SP, 1);
3760 PUSHs(sv_2mortal(newSVpv(buffer, 0)));
3761 }
3762
faa9b3e7
TC
3763int
3764i_tags_count(im)
3765 Imager::ImgRaw im
3766 CODE:
3767 RETVAL = im->tags.count;
3768 OUTPUT:
3769 RETVAL
3770
faa9b3e7 3771
faa9b3e7 3772
f1ac5027
TC
3773MODULE = Imager PACKAGE = Imager::FillHandle PREFIX=IFILL_
3774
3775void
3776IFILL_DESTROY(fill)
3777 Imager::FillHandle fill
3778
ffddd407
TC
3779int
3780IFILL_CLONE_SKIP(...)
3781 CODE:
8d14daab 3782 (void)items; /* avoid unused warning for XS variable */
ffddd407
TC
3783 RETVAL = 1;
3784 OUTPUT:
3785 RETVAL
3786
f1ac5027
TC
3787MODULE = Imager PACKAGE = Imager
3788
3789Imager::FillHandle
3790i_new_fill_solid(cl, combine)
3791 Imager::Color cl
3792 int combine
3793
3794Imager::FillHandle
3795i_new_fill_solidf(cl, combine)
3796 Imager::Color::Float cl
3797 int combine
3798
3799Imager::FillHandle
a309fbc6 3800i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
f1ac5027
TC
3801 Imager::Color fg
3802 Imager::Color bg
3803 int combine
3804 int hatch
a309fbc6 3805 SV *cust_hatch_sv
8d14daab
TC
3806 i_img_dim dx
3807 i_img_dim dy
f1ac5027
TC
3808 PREINIT:
3809 unsigned char *cust_hatch;
3810 STRLEN len;
3811 CODE:
a309fbc6
TC
3812 SvGETMAGIC(cust_hatch_sv);
3813 if (SvOK(cust_hatch_sv)) {
3814 cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len);
f1ac5027
TC
3815 }
3816 else
3817 cust_hatch = NULL;
3818 RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
3819 OUTPUT:
3820 RETVAL
3821
efdc2568 3822Imager::FillHandle
a309fbc6 3823i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
efdc2568
TC
3824 Imager::Color::Float fg
3825 Imager::Color::Float bg
3826 int combine
3827 int hatch
a309fbc6 3828 SV *cust_hatch_sv
8d14daab
TC
3829 i_img_dim dx
3830 i_img_dim dy
efdc2568
TC
3831 PREINIT:
3832 unsigned char *cust_hatch;
3833 STRLEN len;
3834 CODE:
a309fbc6
TC
3835 SvGETMAGIC(cust_hatch_sv);
3836 if (SvOK(cust_hatch_sv)) {
3837 cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len);
efdc2568
TC
3838 }
3839 else
3840 cust_hatch = NULL;
3841 RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
3842 OUTPUT:
3843 RETVAL
3844
f576ce7e 3845Imager::FillHandle
c0f38779 3846i_new_fill_image(src, matrix_sv, xoff, yoff, combine)
f576ce7e 3847 Imager::ImgRaw src
c0f38779 3848 SV *matrix_sv
8d14daab
TC
3849 i_img_dim xoff
3850 i_img_dim yoff
f576ce7e
TC
3851 int combine
3852 PREINIT:
3853 double matrix[9];
3854 double *matrixp;
3855 AV *av;
3856 IV len;
3857 SV *sv1;
3858 int i;
3859 CODE:
c0f38779
TC
3860 SvGETMAGIC(matrix_sv);
3861 if (!SvOK(matrix_sv)) {
f576ce7e
TC
3862 matrixp = NULL;
3863 }
3864 else {
c0f38779
TC
3865 if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV)
3866 croak("i_new_fill_image: matrix parameter must be an arrayref or undef");
3867 av=(AV*)SvRV(matrix_sv);
f576ce7e
TC
3868 len=av_len(av)+1;
3869 if (len > 9)
3870 len = 9;
3871 for (i = 0; i < len; ++i) {
3872 sv1=(*(av_fetch(av,i,0)));
3873 matrix[i] = SvNV(sv1);
3874 }
3875 for (; i < 9; ++i)
3876 matrix[i] = 0;
3877 matrixp = matrix;
3878 }
3879 RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
3880 OUTPUT:
3881 RETVAL
042cdaea 3882
a8652edf
TC
3883MODULE = Imager PACKAGE = Imager::Internal::Hlines PREFIX=i_int_hlines_
3884
3885# this class is only exposed for testing
3886
3887int
3888i_int_hlines_testing()
3889
3890#if i_int_hlines_testing()
3891
3892Imager::Internal::Hlines
3893i_int_hlines_new(start_y, count_y, start_x, count_x)
8d14daab 3894 i_img_dim start_y
a8652edf 3895 int count_y
8d14daab 3896 i_img_dim start_x
a8652edf
TC
3897 int count_x
3898
3899Imager::Internal::Hlines
3900i_int_hlines_new_img(im)
3901 Imager::ImgRaw im
3902
3903void
3904i_int_hlines_add(hlines, y, minx, width)
3905 Imager::Internal::Hlines hlines
8d14daab
TC
3906 i_img_dim y
3907 i_img_dim minx
3908 i_img_dim width
a8652edf
TC
3909
3910void
3911i_int_hlines_DESTROY(hlines)
3912 Imager::Internal::Hlines hlines
3913
3914SV *
3915i_int_hlines_dump(hlines)
3916 Imager::Internal::Hlines hlines
3917
ffddd407
TC
3918int
3919i_int_hlines_CLONE_SKIP(cls)
ffddd407 3920
a8652edf 3921#endif
92bda632 3922
31a13473
TC
3923MODULE = Imager PACKAGE = Imager::Context PREFIX=im_context_
3924
3925void
3926im_context_DESTROY(ctx)
3927 Imager::Context ctx
3928
3929#ifdef PERL_IMPLICIT_CONTEXT
3930
3931void
3932im_context_CLONE(...)
3933 CODE:
3934 MY_CXT_CLONE;
39512ead 3935 (void)items;
31a13473
TC
3936 /* the following sv_setref_pv() will free this inc */
3937 im_context_refinc(MY_CXT.ctx, "CLONE");
3938 MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE");
3939 sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
3940
3941#endif
3942
92bda632
TC
3943BOOT:
3944 PERL_SET_GLOBAL_CALLBACKS;
6d5c85a2 3945 PERL_PL_SET_GLOBAL_CALLBACKS;
39512ead 3946#ifdef PERL_IMPLICIT_CONTEXT
54064d2e
TC
3947 {
3948 MY_CXT_INIT;
3949 (void)MY_CXT;
3950 }
39512ead 3951#endif
31a13473 3952 start_context(aTHX);
cf8c77ae 3953 im_get_context = perl_get_context;
eee347a1
TC
3954#ifdef HAVE_LIBTT
3955 i_tt_start();
3956#endif