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