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