add colorchannels(), alphachannel() and colormodel() methods
[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         EXTEND(SP, col_cnt);
2678         for (i = 0; i < col_cnt; i++)  {
2679             PUSHs(sv_2mortal(newSViv( col_usage[i])));
2680         }
2681         myfree(col_usage);
2682         XSRETURN(col_cnt);
2683
2684
2685 void
2686 i_transform(im, opx, opy, parm)
2687     Imager::ImgRaw     im
2688     int *opx
2689     int *opy
2690     double *parm
2691              PREINIT:
2692              STRLEN size_opx, size_opy, size_parm;
2693              i_img *result;
2694              PPCODE:
2695              result=i_transform(im,opx,size_opx,opy,size_opy,parm,size_parm);
2696              if (result) {
2697                SV *result_sv = sv_newmortal();
2698                EXTEND(SP, 1);
2699                sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result);
2700                PUSHs(result_sv);
2701              }
2702
2703 void
2704 i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
2705         SV *sv_width
2706         SV *sv_height
2707         SV *sv_ops
2708         AV *av_n_regs
2709         AV *av_c_regs
2710         AV *av_in_imgs
2711         int channels
2712              PREINIT:
2713              i_img_dim width;
2714              i_img_dim height;
2715              struct rm_op *ops;
2716              STRLEN ops_len;
2717              int ops_count;
2718              double *n_regs;
2719              int n_regs_count;
2720              i_color *c_regs;
2721              int c_regs_count;
2722              int in_imgs_count;
2723              i_img **in_imgs;
2724              SV *sv1;
2725              IV tmp;
2726              int i;
2727              i_img *result;
2728              PPCODE:
2729
2730              in_imgs_count = av_len(av_in_imgs)+1;
2731              for (i = 0; i < in_imgs_count; ++i) {
2732                sv1 = *av_fetch(av_in_imgs, i, 0);
2733                if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2734                  croak("sv_in_img must contain only images");
2735                }
2736              }
2737              if (in_imgs_count > 0) {
2738                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2739                for (i = 0; i < in_imgs_count; ++i) {              
2740                  sv1 = *av_fetch(av_in_imgs,i,0);
2741                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2742                    croak("Parameter 5 must contain only images");
2743                  }
2744                  tmp = SvIV((SV*)SvRV(sv1));
2745                  in_imgs[i] = INT2PTR(i_img*, tmp);
2746                }
2747              }
2748              else {
2749                /* no input images */
2750                in_imgs = NULL;
2751              }
2752              /* default the output size from the first input if possible */
2753              if (SvOK(sv_width))
2754                width = SvIV(sv_width);
2755              else if (in_imgs_count)
2756                width = in_imgs[0]->xsize;
2757              else
2758                croak("No output image width supplied");
2759
2760              if (SvOK(sv_height))
2761                height = SvIV(sv_height);
2762              else if (in_imgs_count)
2763                height = in_imgs[0]->ysize;
2764              else
2765                croak("No output image height supplied");
2766
2767              ops = (struct rm_op *)SvPV(sv_ops, ops_len);
2768              if (ops_len % sizeof(struct rm_op))
2769                  croak("Imager: Parameter 3 must be a bitmap of regops\n");
2770              ops_count = ops_len / sizeof(struct rm_op);
2771
2772              n_regs_count = av_len(av_n_regs)+1;
2773              n_regs = mymalloc(n_regs_count * sizeof(double));
2774              for (i = 0; i < n_regs_count; ++i) {
2775                sv1 = *av_fetch(av_n_regs,i,0);
2776                if (SvOK(sv1))
2777                  n_regs[i] = SvNV(sv1);
2778              }
2779              c_regs_count = av_len(av_c_regs)+1;
2780              c_regs = mymalloc(c_regs_count * sizeof(i_color));
2781              /* I don't bother initializing the colou?r registers */
2782
2783              result=i_transform2(width, height, channels, ops, ops_count, 
2784                                  n_regs, n_regs_count, 
2785                                  c_regs, c_regs_count, in_imgs, in_imgs_count);
2786              if (in_imgs)
2787                  myfree(in_imgs);
2788              myfree(n_regs);
2789              myfree(c_regs);
2790              if (result) {
2791                SV *result_sv = sv_newmortal();
2792                EXTEND(SP, 1);
2793                sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result);
2794                PUSHs(result_sv);
2795              }
2796
2797
2798 void
2799 i_contrast(im,intensity)
2800     Imager::ImgRaw     im
2801              float     intensity
2802
2803 void
2804 i_hardinvert(im)
2805     Imager::ImgRaw     im
2806
2807 void
2808 i_hardinvertall(im)
2809     Imager::ImgRaw     im
2810
2811 void
2812 i_noise(im,amount,type)
2813     Imager::ImgRaw     im
2814              float     amount
2815      unsigned char     type
2816
2817 void
2818 i_bumpmap(im,bump,channel,light_x,light_y,strength)
2819     Imager::ImgRaw     im
2820     Imager::ImgRaw     bump
2821                int     channel
2822          i_img_dim     light_x
2823          i_img_dim     light_y
2824          i_img_dim     strength
2825
2826
2827 void
2828 i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
2829     Imager::ImgRaw     im
2830     Imager::ImgRaw     bump
2831                int     channel
2832                i_img_dim     tx
2833                i_img_dim     ty
2834              double     Lx
2835              double     Ly
2836              double     Lz
2837              float     cd
2838              float     cs
2839              float     n
2840      Imager::Color     Ia
2841      Imager::Color     Il
2842      Imager::Color     Is
2843
2844
2845
2846 void
2847 i_postlevels(im,levels)
2848     Imager::ImgRaw     im
2849              int       levels
2850
2851 void
2852 i_mosaic(im,size)
2853     Imager::ImgRaw     im
2854          i_img_dim     size
2855
2856 void
2857 i_watermark(im,wmark,tx,ty,pixdiff)
2858     Imager::ImgRaw     im
2859     Imager::ImgRaw     wmark
2860                i_img_dim     tx
2861                i_img_dim     ty
2862                int     pixdiff
2863
2864
2865 void
2866 i_autolevels(im,lsat,usat,skew)
2867     Imager::ImgRaw     im
2868              float     lsat
2869              float     usat
2870              float     skew
2871
2872 void
2873 i_autolevels_mono(im,lsat,usat)
2874     Imager::ImgRaw     im
2875              float     lsat
2876              float     usat
2877
2878 void
2879 i_radnoise(im,xo,yo,rscale,ascale)
2880     Imager::ImgRaw     im
2881              float     xo
2882              float     yo
2883              float     rscale
2884              float     ascale
2885
2886 void
2887 i_turbnoise(im, xo, yo, scale)
2888     Imager::ImgRaw     im
2889              float     xo
2890              float     yo
2891              float     scale
2892
2893
2894 void
2895 i_gradgen(im, xo, yo, ac, dmeasure)
2896     Imager::ImgRaw     im
2897     i_img_dim *xo
2898     i_img_dim *yo
2899     i_color *ac
2900     int dmeasure
2901       PREINIT:
2902         STRLEN size_xo;
2903         STRLEN size_yo;
2904         STRLEN size_ac;
2905       CODE:
2906         if (size_xo != size_yo || size_xo != size_ac)
2907           croak("i_gradgen: x, y and color arrays must be the same size");
2908         if (size_xo < 2)
2909           croak("Usage: i_gradgen array refs must have more than 1 entry each");
2910         i_gradgen(im, size_xo, xo, yo, ac, dmeasure);
2911
2912 Imager::ImgRaw
2913 i_diff_image(im, im2, mindist=0)
2914     Imager::ImgRaw     im
2915     Imager::ImgRaw     im2
2916             double     mindist
2917
2918 undef_int
2919 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2920     Imager::ImgRaw     im
2921             double     xa
2922             double     ya
2923             double     xb
2924             double     yb
2925                int     type
2926                int     repeat
2927                int     combine
2928                int     super_sample
2929             double     ssample_param
2930       PREINIT:
2931         AV *asegs;
2932         int count;
2933         i_fountain_seg *segs;
2934       CODE:
2935         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
2936             croak("i_fountain: argument 11 must be an array ref");
2937         
2938         asegs = (AV *)SvRV(ST(10));
2939         segs = load_fount_segs(aTHX_ asegs, &count);
2940         RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, 
2941                             super_sample, ssample_param, count, segs);
2942         myfree(segs);
2943       OUTPUT:
2944         RETVAL
2945
2946 Imager::FillHandle
2947 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2948             double     xa
2949             double     ya
2950             double     xb
2951             double     yb
2952                int     type
2953                int     repeat
2954                int     combine
2955                int     super_sample
2956             double     ssample_param
2957       PREINIT:
2958         AV *asegs;
2959         int count;
2960         i_fountain_seg *segs;
2961       CODE:
2962         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
2963             croak("i_fountain: argument 11 must be an array ref");
2964         
2965         asegs = (AV *)SvRV(ST(9));
2966         segs = load_fount_segs(aTHX_ asegs, &count);
2967         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
2968                                   super_sample, ssample_param, count, segs);
2969         myfree(segs);        
2970       OUTPUT:
2971         RETVAL
2972
2973 Imager::FillHandle
2974 i_new_fill_opacity(other_fill, alpha_mult)
2975     Imager::FillHandle other_fill
2976     double alpha_mult
2977
2978 void
2979 i_errors()
2980       PREINIT:
2981         i_errmsg *errors;
2982         int i;
2983         AV *av;
2984         SV *sv;
2985       PPCODE:
2986         errors = i_errors();
2987         i = 0;
2988         while (errors[i].msg) {
2989           av = newAV();
2990           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
2991           if (!av_store(av, 0, sv)) {
2992             SvREFCNT_dec(sv);
2993           }
2994           sv = newSViv(errors[i].code);
2995           if (!av_store(av, 1, sv)) {
2996             SvREFCNT_dec(sv);
2997           }
2998           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
2999           ++i;
3000         }
3001
3002 void
3003 i_clear_error()
3004
3005 void
3006 i_push_error(code, msg)
3007         int code
3008         const char *msg
3009
3010 undef_int
3011 i_nearest_color(im, ...)
3012     Imager::ImgRaw     im
3013       PREINIT:
3014         int num;
3015         i_img_dim *xo;
3016         i_img_dim *yo;
3017         i_color *ival;
3018         int dmeasure;
3019         int i;
3020         SV *sv;
3021         AV *axx;
3022         AV *ayy;
3023         AV *ac;
3024       CODE:
3025         if (items != 5)
3026             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
3027         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3028             croak("i_nearest_color: Second argument must be an array ref");
3029         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
3030             croak("i_nearest_color: Third argument must be an array ref");
3031         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
3032             croak("i_nearest_color: Fourth argument must be an array ref");
3033         axx = (AV *)SvRV(ST(1));
3034         ayy = (AV *)SvRV(ST(2));
3035         ac  = (AV *)SvRV(ST(3));
3036         dmeasure = (int)SvIV(ST(4));
3037         
3038         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
3039         num = num <= av_len(ac) ? num : av_len(ac);
3040         num++; 
3041         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
3042         xo = mymalloc( sizeof(i_img_dim) * num );
3043         yo = mymalloc( sizeof(i_img_dim) * num );
3044         ival = mymalloc( sizeof(i_color) * num );
3045         for(i = 0; i<num; i++) {
3046           xo[i]   = (i_img_dim)SvIV(* av_fetch(axx, i, 0));
3047           yo[i]   = (i_img_dim)SvIV(* av_fetch(ayy, i, 0));
3048           sv = *av_fetch(ac, i, 0);
3049           if ( !sv_derived_from(sv, "Imager::Color") ) {
3050             free(axx); free(ayy); free(ac);
3051             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
3052           }
3053           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
3054         }
3055         RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
3056       OUTPUT:
3057         RETVAL
3058
3059 void
3060 malloc_state()
3061
3062 void
3063 DSO_open(filename)
3064              char*       filename
3065              PREINIT:
3066                void *rc;
3067                char *evstr;
3068              PPCODE:
3069                rc=DSO_open(filename,&evstr);
3070                if (rc!=NULL) {
3071                  if (evstr!=NULL) {
3072                    EXTEND(SP,2); 
3073                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3074                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
3075                  } else {
3076                    EXTEND(SP,1);
3077                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3078                  }
3079                }
3080
3081
3082 undef_int
3083 DSO_close(dso_handle)
3084              void*       dso_handle
3085
3086 void
3087 DSO_funclist(dso_handle_v)
3088              void*       dso_handle_v
3089              PREINIT:
3090                int i;
3091                DSO_handle *dso_handle;
3092                func_ptr *functions;
3093              PPCODE:
3094                dso_handle=(DSO_handle*)dso_handle_v;
3095                functions = DSO_funclist(dso_handle);
3096                i=0;
3097                while( functions[i].name != NULL) {
3098                  EXTEND(SP,1);
3099                  PUSHs(sv_2mortal(newSVpv(functions[i].name,0)));
3100                  EXTEND(SP,1);
3101                  PUSHs(sv_2mortal(newSVpv(functions[i++].pcode,0)));
3102                }
3103
3104 void
3105 DSO_call(handle,func_index,hv)
3106                void*  handle
3107                int    func_index
3108                HV *hv
3109              PPCODE:
3110                DSO_call( (DSO_handle *)handle,func_index,hv);
3111
3112 Imager::Color
3113 i_get_pixel(im, x, y)
3114         Imager::ImgRaw im
3115         i_img_dim x
3116         i_img_dim y;
3117       CODE:
3118         RETVAL = (i_color *)mymalloc(sizeof(i_color));
3119         memset(RETVAL, 0, sizeof(*RETVAL));
3120         if (i_gpix(im, x, y, RETVAL) != 0) {
3121           myfree(RETVAL);
3122           XSRETURN_UNDEF;
3123         }
3124       OUTPUT:
3125         RETVAL
3126         
3127
3128 int
3129 i_ppix(im, x, y, cl)
3130         Imager::ImgRaw im
3131         i_img_dim x
3132         i_img_dim y
3133         Imager::Color cl
3134
3135 Imager::ImgRaw
3136 i_img_pal_new(x, y, channels, maxpal)
3137         i_img_dim x
3138         i_img_dim y
3139         int     channels
3140         int     maxpal
3141
3142 Imager::ImgRaw
3143 i_img_to_pal(src, quant)
3144         Imager::ImgRaw src
3145       PREINIT:
3146         HV *hv;
3147         i_quantize quant;
3148       CODE:
3149         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3150           croak("i_img_to_pal: second argument must be a hash ref");
3151         hv = (HV *)SvRV(ST(1));
3152         memset(&quant, 0, sizeof(quant));
3153         quant.version = 1;
3154         quant.mc_size = 256;
3155         ip_handle_quant_opts(aTHX_ &quant, hv);
3156         RETVAL = i_img_to_pal(src, &quant);
3157         if (RETVAL) {
3158           ip_copy_colors_back(aTHX_ hv, &quant);
3159         }
3160         ip_cleanup_quant_opts(aTHX_ &quant);
3161       OUTPUT:
3162         RETVAL
3163
3164 Imager::ImgRaw
3165 i_img_to_rgb(src)
3166         Imager::ImgRaw src
3167
3168 void
3169 i_img_make_palette(HV *quant_hv, ...)
3170       PREINIT:
3171         size_t count = items - 1;
3172         i_quantize quant;
3173         i_img **imgs = NULL;
3174         ssize_t i;
3175       PPCODE:
3176         if (count <= 0)
3177           croak("Please supply at least one image (%d)", (int)count);
3178         imgs = mymalloc(sizeof(i_img *) * count);
3179         for (i = 0; i < count; ++i) {
3180           SV *img_sv = ST(i + 1);
3181           if (SvROK(img_sv) && sv_derived_from(img_sv, "Imager::ImgRaw")) {
3182             imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(img_sv)));
3183           }
3184           else {
3185             myfree(imgs);
3186             croak("Image %d is not an image object", (int)i+1);
3187           }
3188         }
3189         memset(&quant, 0, sizeof(quant));
3190         quant.version = 1;
3191         quant.mc_size = 256;
3192         ip_handle_quant_opts(aTHX_ &quant, quant_hv);
3193         i_quant_makemap(&quant, imgs, count);
3194         EXTEND(SP, quant.mc_count);
3195         for (i = 0; i < quant.mc_count; ++i) {
3196           SV *sv_c = make_i_color_sv(aTHX_ quant.mc_colors + i);
3197           PUSHs(sv_c);
3198         }
3199         ip_cleanup_quant_opts(aTHX_ &quant);
3200         
3201
3202 void
3203 i_gpal(im, l, r, y)
3204         Imager::ImgRaw  im
3205         i_img_dim     l
3206         i_img_dim     r
3207         i_img_dim     y
3208       PREINIT:
3209         i_palidx *work;
3210         int count, i;
3211       PPCODE:
3212         if (l < r) {
3213           work = mymalloc((r-l) * sizeof(i_palidx));
3214           count = i_gpal(im, l, r, y, work);
3215           if (GIMME_V == G_ARRAY) {
3216             EXTEND(SP, count);
3217             for (i = 0; i < count; ++i) {
3218               PUSHs(sv_2mortal(newSViv(work[i])));
3219             }
3220           }
3221           else {
3222             EXTEND(SP, 1);
3223             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3224           }
3225           myfree(work);
3226         }
3227         else {
3228           if (GIMME_V != G_ARRAY) {
3229             EXTEND(SP, 1);
3230             PUSHs(&PL_sv_undef);
3231           }
3232         }
3233
3234 int
3235 i_ppal(im, l, y, ...)
3236         Imager::ImgRaw  im
3237         i_img_dim     l
3238         i_img_dim     y
3239       PREINIT:
3240         i_palidx *work;
3241         i_img_dim i;
3242       CODE:
3243         if (items > 3) {
3244           work = malloc_temp(aTHX_ sizeof(i_palidx) * (items-3));
3245           for (i=0; i < items-3; ++i) {
3246             work[i] = SvIV(ST(i+3));
3247           }
3248           validate_i_ppal(im, work, items - 3);
3249           RETVAL = i_ppal(im, l, l+items-3, y, work);
3250         }
3251         else {
3252           RETVAL = 0;
3253         }
3254       OUTPUT:
3255         RETVAL
3256
3257 int
3258 i_ppal_p(im, l, y, data)
3259         Imager::ImgRaw  im
3260         i_img_dim     l
3261         i_img_dim     y
3262         SV *data
3263       PREINIT:
3264         i_palidx const *work;
3265         STRLEN len;
3266       CODE:
3267         work = (i_palidx const *)SvPV(data, len);
3268         len /= sizeof(i_palidx);
3269         if (len > 0) {
3270           validate_i_ppal(im, work, len);
3271           RETVAL = i_ppal(im, l, l+len, y, work);
3272         }
3273         else {
3274           RETVAL = 0;
3275         }
3276       OUTPUT:
3277         RETVAL
3278
3279 SysRet
3280 i_addcolors(im, ...)
3281         Imager::ImgRaw  im
3282       PREINIT:
3283         i_color *colors;
3284         int i;
3285       CODE:
3286         if (items < 2)
3287           croak("i_addcolors: no colors to add");
3288         colors = mymalloc((items-1) * sizeof(i_color));
3289         for (i=0; i < items-1; ++i) {
3290           if (sv_isobject(ST(i+1)) 
3291               && sv_derived_from(ST(i+1), "Imager::Color")) {
3292             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3293             colors[i] = *INT2PTR(i_color *, tmp);
3294           }
3295           else {
3296             myfree(colors);
3297             croak("i_addcolor: pixels must be Imager::Color objects");
3298           }
3299         }
3300         RETVAL = i_addcolors(im, colors, items-1);
3301       OUTPUT:
3302         RETVAL
3303
3304 undef_int 
3305 i_setcolors(im, index, ...)
3306         Imager::ImgRaw  im
3307         int index
3308       PREINIT:
3309         i_color *colors;
3310         int i;
3311       CODE:
3312         if (items < 3)
3313           croak("i_setcolors: no colors to add");
3314         colors = mymalloc((items-2) * sizeof(i_color));
3315         for (i=0; i < items-2; ++i) {
3316           if (sv_isobject(ST(i+2)) 
3317               && sv_derived_from(ST(i+2), "Imager::Color")) {
3318             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3319             colors[i] = *INT2PTR(i_color *, tmp);
3320           }
3321           else {
3322             myfree(colors);
3323             croak("i_setcolors: pixels must be Imager::Color objects");
3324           }
3325         }
3326         RETVAL = i_setcolors(im, index, colors, items-2);
3327         myfree(colors);
3328       OUTPUT:
3329         RETVAL
3330
3331 void
3332 i_getcolors(im, index, count=1)
3333         Imager::ImgRaw im
3334         int index
3335         int count
3336       PREINIT:
3337         i_color *colors;
3338         int i;
3339       PPCODE:
3340         if (count < 1)
3341           croak("i_getcolors: count must be positive");
3342         colors = malloc_temp(aTHX_ sizeof(i_color) * count);
3343         if (i_getcolors(im, index, colors, count)) {
3344           EXTEND(SP, count);
3345           for (i = 0; i < count; ++i) {
3346             SV *sv = make_i_color_sv(aTHX_ colors+i);
3347             PUSHs(sv);
3348           }
3349         }
3350
3351 undef_neg_int
3352 i_colorcount(im)
3353         Imager::ImgRaw im
3354
3355 undef_neg_int
3356 i_maxcolors(im)
3357         Imager::ImgRaw im
3358
3359 i_palidx
3360 i_findcolor(im, color)
3361         Imager::ImgRaw im
3362         Imager::Color color
3363       CODE:
3364         if (!i_findcolor(im, color, &RETVAL)) {
3365           XSRETURN_UNDEF;
3366         }
3367       OUTPUT:
3368         RETVAL
3369
3370 int
3371 i_img_bits(im)
3372         Imager::ImgRaw  im
3373
3374 int
3375 i_img_type(im)
3376         Imager::ImgRaw  im
3377
3378 int
3379 i_img_virtual(im)
3380         Imager::ImgRaw  im
3381
3382 void
3383 i_gsamp(im, l, r, y, channels)
3384         Imager::ImgRaw im
3385         i_img_dim l
3386         i_img_dim r
3387         i_img_dim y
3388         i_channel_list channels
3389       PREINIT:
3390         i_sample_t *data;
3391         i_img_dim count, i;
3392       PPCODE:
3393         if (l < r) {
3394           data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count);
3395           count = i_gsamp(im, l, r, y, data, channels.channels, channels.count);
3396           if (GIMME_V == G_ARRAY) {
3397             EXTEND(SP, count);
3398             for (i = 0; i < count; ++i)
3399               PUSHs(sv_2mortal(newSViv(data[i])));
3400           }
3401           else {
3402             EXTEND(SP, 1);
3403             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3404           }
3405           myfree(data);
3406         }
3407         else {
3408           if (GIMME_V != G_ARRAY) {
3409             XSRETURN_UNDEF;
3410           }
3411         }
3412
3413 undef_neg_int
3414 i_gsamp_bits(im, l, r, y, bits, target, offset, channels)
3415         Imager::ImgRaw im
3416         i_img_dim l
3417         i_img_dim r
3418         i_img_dim y
3419         int bits
3420         AV *target
3421         STRLEN offset
3422         i_channel_list channels
3423       PREINIT:
3424         unsigned *data;
3425         i_img_dim count, i;
3426       CODE:
3427         i_clear_error();
3428         if (items < 8)
3429           croak("No channel numbers supplied to g_samp()");
3430         if (l < r) {
3431           data = mymalloc(sizeof(unsigned) * (r-l) * channels.count);
3432           count = i_gsamp_bits(im, l, r, y, data, channels.channels, channels.count, bits);
3433           for (i = 0; i < count; ++i) {
3434             av_store(target, i+offset, newSVuv(data[i]));
3435           }
3436           myfree(data);
3437           RETVAL = count;
3438         }
3439         else {
3440           RETVAL = 0;
3441         }
3442       OUTPUT:
3443         RETVAL
3444
3445 undef_neg_int
3446 i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -1)
3447         Imager::ImgRaw im
3448         i_img_dim l
3449         i_img_dim y
3450         int bits
3451         i_channel_list channels
3452         AV *data_av
3453         i_img_dim data_offset
3454         i_img_dim pixel_count
3455       PREINIT:
3456         STRLEN data_count;
3457         size_t data_used;
3458         unsigned *data;
3459         ptrdiff_t i;
3460       CODE:
3461         i_clear_error();
3462
3463         data_count = av_len(data_av) + 1;
3464         if (data_offset < 0) {
3465           croak("data_offset must be non-negative");
3466         }
3467         if (data_offset > data_count) {
3468           croak("data_offset greater than number of samples supplied");
3469         }
3470         if (pixel_count == -1 || 
3471             data_offset + pixel_count * channels.count > data_count) {
3472           pixel_count = (data_count - data_offset) / channels.count;
3473         }
3474
3475         data_used = pixel_count * channels.count;
3476         data = mymalloc(sizeof(unsigned) * data_count);
3477         for (i = 0; i < data_used; ++i)
3478           data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0));
3479
3480         RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels.channels, 
3481                               channels.count, bits);
3482
3483         if (data)
3484           myfree(data);
3485       OUTPUT:
3486         RETVAL
3487
3488 undef_neg_int
3489 i_psamp(im, x, y, channels, data, offset = 0, width = -1)
3490         Imager::ImgRaw im
3491         i_img_dim x
3492         i_img_dim y
3493         i_channel_list channels
3494         i_sample_list data
3495         i_img_dim offset
3496         i_img_dim width
3497     PREINIT:
3498         i_img_dim r;
3499     CODE:
3500         i_clear_error();
3501         if (offset < 0) {
3502           i_push_error(0, "offset must be non-negative");
3503           XSRETURN_UNDEF;
3504         }
3505         if (offset > 0) {
3506           if (offset > data.count) {
3507             i_push_error(0, "offset greater than number of samples supplied");
3508             XSRETURN_UNDEF;
3509           }
3510           data.samples += offset;
3511           data.count -= offset;
3512         }
3513         if (width == -1 ||
3514             width * channels.count > data.count) {
3515           width = data.count / channels.count;
3516         }
3517         r = x + width;
3518         RETVAL = i_psamp(im, x, r, y, data.samples, channels.channels, channels.count);
3519     OUTPUT:
3520         RETVAL
3521
3522 undef_neg_int
3523 i_psampf(im, x, y, channels, data, offset = 0, width = -1)
3524         Imager::ImgRaw im
3525         i_img_dim x
3526         i_img_dim y
3527         i_channel_list channels
3528         i_fsample_list data
3529         i_img_dim offset
3530         i_img_dim width
3531     PREINIT:
3532         i_img_dim r;
3533     CODE:
3534         i_clear_error();
3535         if (offset < 0) {
3536           i_push_error(0, "offset must be non-negative");
3537           XSRETURN_UNDEF;
3538         }
3539         if (offset > 0) {
3540           if (offset > data.count) {
3541             i_push_error(0, "offset greater than number of samples supplied");
3542             XSRETURN_UNDEF;
3543           }
3544           data.samples += offset;
3545           data.count -= offset;
3546         }
3547         if (width == -1 ||
3548             width * channels.count > data.count) {
3549           width = data.count / channels.count;
3550         }
3551         r = x + width;
3552         RETVAL = i_psampf(im, x, r, y, data.samples, channels.channels, channels.count);
3553     OUTPUT:
3554         RETVAL
3555
3556 Imager::ImgRaw
3557 i_img_masked_new(targ, mask, x, y, w, h)
3558         Imager::ImgRaw targ
3559         i_img_dim x
3560         i_img_dim y
3561         i_img_dim w
3562         i_img_dim h
3563       PREINIT:
3564         i_img *mask;
3565       CODE:
3566         if (SvOK(ST(1))) {
3567           if (!sv_isobject(ST(1)) 
3568               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3569             croak("i_img_masked_new: parameter 2 must undef or an image");
3570           }
3571           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3572         }
3573         else
3574           mask = NULL;
3575         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3576       OUTPUT:
3577         RETVAL
3578
3579 int
3580 i_plin(im, l, y, ...)
3581         Imager::ImgRaw  im
3582         i_img_dim     l
3583         i_img_dim     y
3584       PREINIT:
3585         i_color *work;
3586         STRLEN i;
3587         STRLEN len;
3588         size_t count;
3589       CODE:
3590         if (items > 3) {
3591           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3592             /* supplied as a byte string */
3593             work = (i_color *)SvPV(ST(3), len);
3594             count = len / sizeof(i_color);
3595             if (count * sizeof(i_color) != len) {
3596               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3597             }
3598             RETVAL = i_plin(im, l, l+count, y, work);
3599           }
3600           else {
3601             work = mymalloc(sizeof(i_color) * (items-3));
3602             for (i=0; i < items-3; ++i) {
3603               if (sv_isobject(ST(i+3)) 
3604                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3605                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3606                 work[i] = *INT2PTR(i_color *, tmp);
3607               }
3608               else {
3609                 myfree(work);
3610                 croak("i_plin: pixels must be Imager::Color objects");
3611               }
3612             }
3613             RETVAL = i_plin(im, l, l+items-3, y, work);
3614             myfree(work);
3615           }
3616         }
3617         else {
3618           RETVAL = 0;
3619         }
3620       OUTPUT:
3621         RETVAL
3622
3623 int
3624 i_ppixf(im, x, y, cl)
3625         Imager::ImgRaw im
3626         i_img_dim x
3627         i_img_dim y
3628         Imager::Color::Float cl
3629
3630 void
3631 i_gsampf(im, l, r, y, channels)
3632         Imager::ImgRaw im
3633         i_img_dim l
3634         i_img_dim r
3635         i_img_dim y
3636         i_channel_list channels
3637       PREINIT:
3638         i_fsample_t *data;
3639         i_img_dim count, i;
3640       PPCODE:
3641         if (l < r) {
3642           data = mymalloc(sizeof(i_fsample_t) * (r-l) * channels.count);
3643           count = i_gsampf(im, l, r, y, data, channels.channels, channels.count);
3644           if (GIMME_V == G_ARRAY) {
3645             EXTEND(SP, count);
3646             for (i = 0; i < count; ++i)
3647               PUSHs(sv_2mortal(newSVnv(data[i])));
3648           }
3649           else {
3650             EXTEND(SP, 1);
3651             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3652           }
3653           myfree(data);
3654         }
3655         else {
3656           if (GIMME_V != G_ARRAY) {
3657             XSRETURN_UNDEF;
3658           }
3659         }
3660
3661 int
3662 i_plinf(im, l, y, ...)
3663         Imager::ImgRaw  im
3664         i_img_dim     l
3665         i_img_dim     y
3666       PREINIT:
3667         i_fcolor *work;
3668         i_img_dim i;
3669         STRLEN len;
3670         size_t count;
3671       CODE:
3672         if (items > 3) {
3673           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3674             /* supplied as a byte string */
3675             work = (i_fcolor *)SvPV(ST(3), len);
3676             count = len / sizeof(i_fcolor);
3677             if (count * sizeof(i_fcolor) != len) {
3678               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3679             }
3680             RETVAL = i_plinf(im, l, l+count, y, work);
3681           }
3682           else {
3683             work = mymalloc(sizeof(i_fcolor) * (items-3));
3684             for (i=0; i < items-3; ++i) {
3685               if (sv_isobject(ST(i+3)) 
3686                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3687                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3688                 work[i] = *INT2PTR(i_fcolor *, tmp);
3689               }
3690               else {
3691                 myfree(work);
3692                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3693               }
3694             }
3695             /**(char *)0 = 1;*/
3696             RETVAL = i_plinf(im, l, l+items-3, y, work);
3697             myfree(work);
3698           }
3699         }
3700         else {
3701           RETVAL = 0;
3702         }
3703       OUTPUT:
3704         RETVAL
3705
3706 Imager::Color::Float
3707 i_gpixf(im, x, y)
3708         Imager::ImgRaw im
3709         i_img_dim x
3710         i_img_dim y;
3711       CODE:
3712         RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3713         memset(RETVAL, 0, sizeof(*RETVAL));
3714         if (i_gpixf(im, x, y, RETVAL) != 0) {
3715           myfree(RETVAL);
3716           XSRETURN_UNDEF;
3717         }
3718       OUTPUT:
3719         RETVAL
3720
3721 void
3722 i_glin(im, l, r, y)
3723         Imager::ImgRaw im
3724         i_img_dim l
3725         i_img_dim r
3726         i_img_dim y
3727       PREINIT:
3728         i_color *vals;
3729         i_img_dim count, i;
3730       PPCODE:
3731         if (l < r) {
3732           vals = mymalloc((r-l) * sizeof(i_color));
3733           memset(vals, 0, (r-l) * sizeof(i_color));
3734           count = i_glin(im, l, r, y, vals);
3735           if (GIMME_V == G_ARRAY) {
3736             EXTEND(SP, count);
3737             for (i = 0; i < count; ++i) {
3738               SV *sv = make_i_color_sv(aTHX_ vals+i);
3739               PUSHs(sv);
3740             }
3741           }
3742           else if (count) {
3743             EXTEND(SP, 1);
3744             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3745           }
3746           myfree(vals);
3747         }
3748
3749 void
3750 i_glinf(im, l, r, y)
3751         Imager::ImgRaw im
3752         i_img_dim l
3753         i_img_dim r
3754         i_img_dim y
3755       PREINIT:
3756         i_fcolor *vals;
3757         i_img_dim count, i;
3758         i_fcolor zero;
3759       PPCODE:
3760         for (i = 0; i < MAXCHANNELS; ++i)
3761           zero.channel[i] = 0;
3762         if (l < r) {
3763           vals = mymalloc((r-l) * sizeof(i_fcolor));
3764           for (i = 0; i < r-l; ++i)
3765             vals[i] = zero;
3766           count = i_glinf(im, l, r, y, vals);
3767           if (GIMME_V == G_ARRAY) {
3768             EXTEND(SP, count);
3769             for (i = 0; i < count; ++i) {
3770               SV *sv;
3771               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3772               *col = vals[i];
3773               sv = sv_newmortal();
3774               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3775               PUSHs(sv);
3776             }
3777           }
3778           else if (count) {
3779             EXTEND(SP, 1);
3780             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3781           }
3782           myfree(vals);
3783         }
3784
3785 Imager::ImgRaw
3786 i_img_8_new(x, y, ch)
3787         i_img_dim x
3788         i_img_dim y
3789         int ch
3790
3791 Imager::ImgRaw
3792 i_img_16_new(x, y, ch)
3793         i_img_dim x
3794         i_img_dim y
3795         int ch
3796
3797 Imager::ImgRaw
3798 i_img_to_rgb16(im)
3799        Imager::ImgRaw im
3800
3801 Imager::ImgRaw
3802 i_img_double_new(x, y, ch)
3803         i_img_dim x
3804         i_img_dim y
3805         int ch
3806
3807 Imager::ImgRaw
3808 i_img_to_drgb(im)
3809        Imager::ImgRaw im
3810
3811 undef_int
3812 i_tags_addn(im, name_sv, code, idata)
3813         Imager::ImgRaw im
3814         SV *name_sv
3815         int     code
3816         int     idata
3817       PREINIT:
3818         char *name;
3819         STRLEN len;
3820       CODE:
3821         SvGETMAGIC(name_sv);
3822         if (SvOK(name_sv))
3823           name = SvPV_nomg(name_sv, len);
3824         else
3825           name = NULL;
3826         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3827       OUTPUT:
3828         RETVAL
3829
3830 undef_int
3831 i_tags_add(im, name_sv, code, data_sv, idata)
3832         Imager::ImgRaw  im
3833         SV *name_sv
3834         int code
3835         SV *data_sv
3836         int idata
3837       PREINIT:
3838         char *name;
3839         char *data;
3840         STRLEN len;
3841       CODE:
3842         SvGETMAGIC(name_sv);
3843         if (SvOK(name_sv))
3844           name = SvPV_nomg(name_sv, len);
3845         else
3846           name = NULL;
3847         SvGETMAGIC(data_sv);
3848         if (SvOK(data_sv))
3849           data = SvPV(data_sv, len);
3850         else {
3851           data = NULL;
3852           len = 0;
3853         }
3854         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3855       OUTPUT:
3856         RETVAL
3857
3858 SysRet
3859 i_tags_find(im, name, start)
3860         Imager::ImgRaw  im
3861         char *name
3862         int start
3863       PREINIT:
3864         int entry;
3865       CODE:
3866         if (i_tags_find(&im->tags, name, start, &entry)) {
3867           RETVAL = entry;
3868         } else {
3869           XSRETURN_UNDEF;
3870         }
3871       OUTPUT:
3872         RETVAL
3873
3874 SysRet
3875 i_tags_findn(im, code, start)
3876         Imager::ImgRaw  im
3877         int             code
3878         int             start
3879       PREINIT:
3880         int entry;
3881       CODE:
3882         if (i_tags_findn(&im->tags, code, start, &entry)) {
3883           RETVAL = entry;
3884         }
3885         else {
3886           XSRETURN_UNDEF;
3887         }
3888       OUTPUT:
3889         RETVAL
3890
3891 int
3892 i_tags_delete(im, entry)
3893         Imager::ImgRaw  im
3894         int             entry
3895       CODE:
3896         RETVAL = i_tags_delete(&im->tags, entry);
3897       OUTPUT:
3898         RETVAL
3899
3900 int
3901 i_tags_delbyname(im, name)
3902         Imager::ImgRaw  im
3903         char *          name
3904       CODE:
3905         RETVAL = i_tags_delbyname(&im->tags, name);
3906       OUTPUT:
3907         RETVAL
3908
3909 int
3910 i_tags_delbycode(im, code)
3911         Imager::ImgRaw  im
3912         int             code
3913       CODE:
3914         RETVAL = i_tags_delbycode(&im->tags, code);
3915       OUTPUT:
3916         RETVAL
3917
3918 void
3919 i_tags_get(im, index)
3920         Imager::ImgRaw  im
3921         int             index
3922       PPCODE:
3923         if (index >= 0 && index < im->tags.count) {
3924           i_img_tag *entry = im->tags.tags + index;
3925           EXTEND(SP, 5);
3926         
3927           if (entry->name) {
3928             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3929           }
3930           else {
3931             PUSHs(sv_2mortal(newSViv(entry->code)));
3932           }
3933           if (entry->data) {
3934             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3935           }
3936           else {
3937             PUSHs(sv_2mortal(newSViv(entry->idata)));
3938           }
3939         }
3940
3941 void
3942 i_tags_get_string(im, what_sv)
3943         Imager::ImgRaw  im
3944         SV *what_sv
3945       PREINIT:
3946         char const *name = NULL;
3947         int code;
3948         char buffer[200];
3949       PPCODE:
3950         if (SvIOK(what_sv)) {
3951           code = SvIV(what_sv);
3952           name = NULL;
3953         }
3954         else {
3955           name = SvPV_nolen(what_sv);
3956           code = 0;
3957         }
3958         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
3959           EXTEND(SP, 1);
3960           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
3961         }
3962
3963 int
3964 i_tags_count(im)
3965         Imager::ImgRaw  im
3966       CODE:
3967         RETVAL = im->tags.count;
3968       OUTPUT:
3969         RETVAL
3970
3971
3972
3973 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
3974
3975 void
3976 IFILL_DESTROY(fill)
3977         Imager::FillHandle fill
3978
3979 int
3980 IFILL_CLONE_SKIP(...)
3981     CODE:
3982         (void)items; /* avoid unused warning for XS variable */
3983         RETVAL = 1;
3984     OUTPUT:
3985         RETVAL
3986
3987 MODULE = Imager         PACKAGE = Imager
3988
3989 Imager::FillHandle
3990 i_new_fill_solid(cl, combine)
3991         Imager::Color cl
3992         int combine
3993
3994 Imager::FillHandle
3995 i_new_fill_solidf(cl, combine)
3996         Imager::Color::Float cl
3997         int combine
3998
3999 Imager::FillHandle
4000 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
4001         Imager::Color fg
4002         Imager::Color bg
4003         int combine
4004         int hatch
4005         SV *cust_hatch_sv
4006         i_img_dim dx
4007         i_img_dim dy
4008       PREINIT:
4009         unsigned char *cust_hatch;
4010         STRLEN len;
4011       CODE:
4012         SvGETMAGIC(cust_hatch_sv);
4013         if (SvOK(cust_hatch_sv)) {
4014           cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len);
4015         }
4016         else
4017           cust_hatch = NULL;
4018         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
4019       OUTPUT:
4020         RETVAL
4021
4022 Imager::FillHandle
4023 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
4024         Imager::Color::Float fg
4025         Imager::Color::Float bg
4026         int combine
4027         int hatch
4028         SV *cust_hatch_sv
4029         i_img_dim dx
4030         i_img_dim dy
4031       PREINIT:
4032         unsigned char *cust_hatch;
4033         STRLEN len;
4034       CODE:
4035         SvGETMAGIC(cust_hatch_sv);
4036         if (SvOK(cust_hatch_sv)) {
4037           cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len);
4038         }
4039         else
4040           cust_hatch = NULL;
4041         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
4042       OUTPUT:
4043         RETVAL
4044
4045 Imager::FillHandle
4046 i_new_fill_image(src, matrix_sv, xoff, yoff, combine)
4047         Imager::ImgRaw src
4048         SV *matrix_sv
4049         i_img_dim xoff
4050         i_img_dim yoff
4051         int combine
4052       PREINIT:
4053         double matrix[9];
4054         double *matrixp;
4055         AV *av;
4056         IV len;
4057         SV *sv1;
4058         int i;
4059       CODE:
4060         SvGETMAGIC(matrix_sv);
4061         if (!SvOK(matrix_sv)) {
4062           matrixp = NULL;
4063         }
4064         else {
4065           if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV)
4066             croak("i_new_fill_image: matrix parameter must be an arrayref or undef");
4067           av=(AV*)SvRV(matrix_sv);
4068           len=av_len(av)+1;
4069           if (len > 9)
4070             len = 9;
4071           for (i = 0; i < len; ++i) {
4072             sv1=(*(av_fetch(av,i,0)));
4073             matrix[i] = SvNV(sv1);
4074           }
4075           for (; i < 9; ++i)
4076             matrix[i] = 0;
4077           matrixp = matrix;
4078         }
4079         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4080       OUTPUT:
4081         RETVAL
4082
4083 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
4084
4085 # this class is only exposed for testing
4086
4087 int
4088 i_int_hlines_testing()
4089
4090 #if i_int_hlines_testing()
4091
4092 Imager::Internal::Hlines
4093 i_int_hlines_new(start_y, count_y, start_x, count_x)
4094         i_img_dim start_y
4095         int count_y
4096         i_img_dim start_x
4097         int count_x
4098
4099 Imager::Internal::Hlines
4100 i_int_hlines_new_img(im)
4101         Imager::ImgRaw im
4102
4103 void
4104 i_int_hlines_add(hlines, y, minx, width)
4105         Imager::Internal::Hlines hlines
4106         i_img_dim y
4107         i_img_dim minx
4108         i_img_dim width
4109
4110 void
4111 i_int_hlines_DESTROY(hlines)
4112         Imager::Internal::Hlines hlines
4113
4114 SV *
4115 i_int_hlines_dump(hlines)
4116         Imager::Internal::Hlines hlines
4117
4118 int
4119 i_int_hlines_CLONE_SKIP(cls)
4120
4121 #endif
4122
4123 MODULE = Imager  PACKAGE = Imager::Context PREFIX=im_context_
4124
4125 void
4126 im_context_DESTROY(ctx)
4127    Imager::Context ctx
4128
4129 #ifdef PERL_IMPLICIT_CONTEXT
4130
4131 void
4132 im_context_CLONE(...)
4133     CODE:
4134       MY_CXT_CLONE;
4135       (void)items;
4136       /* the following sv_setref_pv() will free this inc */
4137       im_context_refinc(MY_CXT.ctx, "CLONE");
4138       MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE");
4139       sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
4140
4141 #endif
4142
4143 BOOT:
4144         PERL_SET_GLOBAL_CALLBACKS;
4145         PERL_PL_SET_GLOBAL_CALLBACKS;
4146 #ifdef PERL_IMPLICIT_CONTEXT
4147         {
4148           MY_CXT_INIT;
4149           (void)MY_CXT;
4150         }
4151 #endif
4152         start_context(aTHX);
4153         im_get_context = perl_get_context;
4154 #ifdef HAVE_LIBTT
4155         i_tt_start();
4156 #endif