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