[rt #69243] use the AV* typemap for i_matrix_transform()
[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_av, ...)
1985     Imager::ImgRaw      im
1986                i_img_dim      xsize
1987                i_img_dim      ysize
1988     AV *matrix_av
1989       PREINIT:
1990         double matrix[9];
1991         STRLEN len;
1992         SV *sv1;
1993         int i;
1994         i_color *backp = NULL;
1995         i_fcolor *fbackp = NULL;
1996       CODE:
1997         len=av_len(matrix_av)+1;
1998         if (len > 9)
1999           len = 9;
2000         for (i = 0; i < len; ++i) {
2001           sv1=(*(av_fetch(matrix_av,i,0)));
2002           matrix[i] = SvNV(sv1);
2003         }
2004         for (; i < 9; ++i)
2005           matrix[i] = 0;
2006         /* extract the bg colors if any */
2007         /* yes, this is kind of strange */
2008         for (i = 4; i < items; ++i) {
2009           sv1 = ST(i);
2010           if (sv_derived_from(sv1, "Imager::Color")) {
2011             IV tmp = SvIV((SV*)SvRV(sv1));
2012             backp = INT2PTR(i_color *, tmp);
2013           }
2014           else if (sv_derived_from(sv1, "Imager::Color::Float")) {
2015             IV tmp = SvIV((SV*)SvRV(sv1));
2016             fbackp = INT2PTR(i_fcolor *, tmp);
2017           }
2018         }
2019         RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp);
2020       OUTPUT:
2021         RETVAL
2022
2023 undef_int
2024 i_gaussian(im,stdev)
2025     Imager::ImgRaw     im
2026             double     stdev
2027
2028 void
2029 i_unsharp_mask(im,stdev,scale)
2030     Imager::ImgRaw     im
2031              double    stdev
2032              double    scale
2033
2034 int
2035 i_conv(im,coef)
2036         Imager::ImgRaw     im
2037         AV *coef
2038      PREINIT:
2039         double*    c_coef;
2040         int     len;
2041         SV* sv1;
2042         int i;
2043     CODE:
2044         len = av_len(coef) + 1;
2045         c_coef=mymalloc( len * sizeof(double) );
2046         for(i = 0; i  < len; i++) {
2047           sv1 = (*(av_fetch(coef, i, 0)));
2048           c_coef[i] = (double)SvNV(sv1);
2049         }
2050         RETVAL = i_conv(im, c_coef, len);
2051         myfree(c_coef);
2052     OUTPUT:
2053         RETVAL
2054
2055 Imager::ImgRaw
2056 i_convert(src, avmain)
2057     Imager::ImgRaw     src
2058     AV *avmain
2059         PREINIT:
2060           double *coeff;
2061           int outchan;
2062           int inchan;
2063           SV **temp;
2064           AV *avsub;
2065           int len;
2066           int i, j;
2067         CODE:
2068           outchan = av_len(avmain)+1;
2069           /* find the biggest */
2070           inchan = 0;
2071           for (j=0; j < outchan; ++j) {
2072             temp = av_fetch(avmain, j, 0);
2073             if (temp && SvROK(*temp) && SvTYPE(SvRV(*temp)) == SVt_PVAV) {
2074               avsub = (AV*)SvRV(*temp);
2075               len = av_len(avsub)+1;
2076               if (len > inchan)
2077                 inchan = len;
2078             }
2079             else {
2080               i_push_errorf(0, "invalid matrix: element %d is not an array ref", j);
2081               XSRETURN(0);
2082             }
2083           }
2084           coeff = mymalloc(sizeof(double) * outchan * inchan);
2085           for (j = 0; j < outchan; ++j) {
2086             avsub = (AV*)SvRV(*av_fetch(avmain, j, 0));
2087             len = av_len(avsub)+1;
2088             for (i = 0; i < len; ++i) {
2089               temp = av_fetch(avsub, i, 0);
2090               if (temp)
2091                 coeff[i+j*inchan] = SvNV(*temp);
2092               else
2093                 coeff[i+j*inchan] = 0;
2094             }
2095             while (i < inchan)
2096               coeff[i++ + j*inchan] = 0;
2097           }
2098           RETVAL = i_convert(src, coeff, outchan, inchan);
2099           myfree(coeff);
2100         OUTPUT:
2101           RETVAL
2102
2103
2104 undef_int
2105 i_map(im, pmaps)
2106     Imager::ImgRaw     im
2107         PREINIT:
2108           unsigned int mask = 0;
2109           AV *avmain;
2110           AV *avsub;
2111           SV **temp;
2112           int len;
2113           int i, j;
2114           unsigned char (*maps)[256];
2115         CODE:
2116           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
2117             croak("i_map: parameter 2 must be an arrayref\n");
2118           avmain = (AV*)SvRV(ST(1));
2119           len = av_len(avmain)+1;
2120           if (im->channels < len) len = im->channels;
2121
2122           maps = mymalloc( len * sizeof(unsigned char [256]) );
2123
2124           for (j=0; j<len ; j++) {
2125             temp = av_fetch(avmain, j, 0);
2126             if (temp && SvROK(*temp) && (SvTYPE(SvRV(*temp)) == SVt_PVAV) ) {
2127               avsub = (AV*)SvRV(*temp);
2128               if(av_len(avsub) != 255) continue;
2129               mask |= 1<<j;
2130               for (i=0; i<256 ; i++) {
2131                 int val;
2132                 temp = av_fetch(avsub, i, 0);
2133                 val = temp ? SvIV(*temp) : 0;
2134                 if (val<0) val = 0;
2135                 if (val>255) val = 255;
2136                 maps[j][i] = val;
2137               }
2138             }
2139           }
2140           i_map(im, maps, mask);
2141           myfree(maps);
2142           RETVAL = 1;
2143     OUTPUT:
2144         RETVAL
2145
2146
2147
2148 float
2149 i_img_diff(im1,im2)
2150     Imager::ImgRaw     im1
2151     Imager::ImgRaw     im2
2152
2153 double
2154 i_img_diffd(im1,im2)
2155     Imager::ImgRaw     im1
2156     Imager::ImgRaw     im2
2157
2158 int
2159 i_img_samef(im1, im2, epsilon = i_img_epsilonf(), what=NULL)
2160     Imager::ImgRaw    im1
2161     Imager::ImgRaw    im2
2162     double epsilon
2163     const char *what
2164
2165 double
2166 i_img_epsilonf()
2167
2168 bool
2169 _is_color_object(sv)
2170         SV* sv
2171     CODE:
2172         SvGETMAGIC(sv);
2173         RETVAL = SvOK(sv) && SvROK(sv) &&
2174            (sv_derived_from(sv, "Imager::Color")
2175           || sv_derived_from(sv, "Imager::Color::Float"));
2176     OUTPUT:
2177         RETVAL
2178
2179 #ifdef HAVE_LIBTT
2180
2181
2182 Imager::Font::TT
2183 i_tt_new(fontname)
2184               char*     fontname
2185
2186
2187 MODULE = Imager         PACKAGE = Imager::Font::TT      PREFIX=TT_
2188
2189 #define TT_DESTROY(handle) i_tt_destroy(handle)
2190
2191 void
2192 TT_DESTROY(handle)
2193      Imager::Font::TT   handle
2194
2195 int
2196 TT_CLONE_SKIP(...)
2197     CODE:
2198         (void)items; /* avoid unused warning */
2199         RETVAL = 1;
2200     OUTPUT:
2201         RETVAL
2202
2203
2204 MODULE = Imager         PACKAGE = Imager
2205
2206
2207 undef_int
2208 i_tt_text(handle,im,xb,yb,cl,points,str_sv,smooth,utf8,align=1)
2209   Imager::Font::TT     handle
2210     Imager::ImgRaw     im
2211                i_img_dim     xb
2212                i_img_dim     yb
2213      Imager::Color     cl
2214              double     points
2215               SV *     str_sv
2216                int     smooth
2217                int     utf8
2218                int     align
2219              PREINIT:
2220                char *str;
2221                STRLEN len;
2222              CODE:
2223                str = SvPV(str_sv, len);
2224 #ifdef SvUTF8
2225                if (SvUTF8(str_sv))
2226                  utf8 = 1;
2227 #endif
2228                RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, 
2229                                   len, smooth, utf8, align);
2230              OUTPUT:
2231                RETVAL                
2232
2233
2234 undef_int
2235 i_tt_cp(handle,im,xb,yb,channel,points,str_sv,smooth,utf8,align=1)
2236   Imager::Font::TT     handle
2237     Imager::ImgRaw     im
2238                i_img_dim     xb
2239                i_img_dim     yb
2240                int     channel
2241              double     points
2242               SV *     str_sv
2243                int     smooth
2244                int     utf8
2245                int     align
2246              PREINIT:
2247                char *str;
2248                STRLEN len;
2249              CODE:
2250                str = SvPV(str_sv, len);
2251 #ifdef SvUTF8
2252                if (SvUTF8(str_sv))
2253                  utf8 = 1;
2254 #endif
2255                RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len,
2256                                 smooth, utf8, align);
2257              OUTPUT:
2258                 RETVAL
2259
2260
2261 void
2262 i_tt_bbox(handle,point,str_sv,utf8)
2263   Imager::Font::TT     handle
2264              double     point
2265                SV*    str_sv
2266                int     utf8
2267              PREINIT:
2268                i_img_dim cords[BOUNDING_BOX_COUNT];
2269                int rc;
2270                char *  str;
2271                STRLEN len;
2272                int i;
2273              PPCODE:
2274                str = SvPV(str_sv, len);
2275 #ifdef SvUTF8
2276                if (SvUTF8(ST(2)))
2277                  utf8 = 1;
2278 #endif
2279                if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) {
2280                  EXTEND(SP, rc);
2281                  for (i = 0; i < rc; ++i) {
2282                    PUSHs(sv_2mortal(newSViv(cords[i])));
2283                  }
2284                }
2285
2286 void
2287 i_tt_has_chars(handle, text_sv, utf8)
2288         Imager::Font::TT handle
2289         SV  *text_sv
2290         int utf8
2291       PREINIT:
2292         char const *text;
2293         STRLEN len;
2294         char *work;
2295         size_t count;
2296         size_t i;
2297       PPCODE:
2298         i_clear_error();
2299         text = SvPV(text_sv, len);
2300 #ifdef SvUTF8
2301         if (SvUTF8(text_sv))
2302           utf8 = 1;
2303 #endif
2304         work = mymalloc(len);
2305         count = i_tt_has_chars(handle, text, len, utf8, work);
2306         if (GIMME_V == G_ARRAY) {
2307           EXTEND(SP, count);
2308           for (i = 0; i < count; ++i) {
2309             PUSHs(boolSV(work[i]));
2310           }
2311         }
2312         else {
2313           EXTEND(SP, 1);
2314           PUSHs(sv_2mortal(newSVpv(work, count)));
2315         }
2316         myfree(work);
2317
2318 void
2319 i_tt_dump_names(handle)
2320         Imager::Font::TT handle
2321
2322 void
2323 i_tt_face_name(handle)
2324         Imager::Font::TT handle
2325       PREINIT:
2326         char name[255];
2327         size_t len;
2328       PPCODE:
2329         len = i_tt_face_name(handle, name, sizeof(name));
2330         if (len) {
2331           EXTEND(SP, 1);
2332           PUSHs(sv_2mortal(newSVpv(name, len-1)));
2333         }
2334
2335 void
2336 i_tt_glyph_name(handle, text_sv, utf8 = 0)
2337         Imager::Font::TT handle
2338         SV *text_sv
2339         int utf8
2340       PREINIT:
2341         char const *text;
2342         STRLEN work_len;
2343         size_t len;
2344         size_t outsize;
2345         char name[255];
2346         SSize_t count = 0;
2347       PPCODE:
2348         i_clear_error();
2349         text = SvPV(text_sv, work_len);
2350 #ifdef SvUTF8
2351         if (SvUTF8(text_sv))
2352           utf8 = 1;
2353 #endif
2354         len = work_len;
2355         while (len) {
2356           unsigned long ch;
2357           if (utf8) {
2358             ch = i_utf8_advance(&text, &len);
2359             if (ch == ~0UL) {
2360               i_push_error(0, "invalid UTF8 character");
2361               XSRETURN_EMPTY;
2362             }
2363           }
2364           else {
2365             ch = *text++;
2366             --len;
2367           }
2368           EXTEND(SP, count+1);
2369           if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
2370             ST(count) = sv_2mortal(newSVpv(name, 0));
2371           }
2372           else {
2373             ST(count) = &PL_sv_undef;
2374           }
2375           ++count;
2376         }
2377         XSRETURN(count);
2378
2379 #endif 
2380
2381 const char *
2382 i_test_format_probe(ig, length)
2383         Imager::IO     ig
2384                int     length
2385
2386 Imager::ImgRaw
2387 i_readpnm_wiol(ig, allow_incomplete)
2388         Imager::IO     ig
2389                int     allow_incomplete
2390
2391
2392 void
2393 i_readpnm_multi_wiol(ig, allow_incomplete)
2394         Imager::IO ig
2395                int     allow_incomplete
2396       PREINIT:
2397         i_img **imgs;
2398         int count=0;
2399         int i;
2400       PPCODE:
2401         imgs = i_readpnm_multi_wiol(ig, &count, allow_incomplete);
2402         if (imgs) {
2403           EXTEND(SP, count);
2404           for (i = 0; i < count; ++i) {
2405             SV *sv = sv_newmortal();
2406             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2407             PUSHs(sv);
2408           }
2409           myfree(imgs);
2410         }
2411
2412 undef_int
2413 i_writeppm_wiol(im, ig)
2414     Imager::ImgRaw     im
2415         Imager::IO     ig
2416
2417
2418
2419
2420
2421 Imager::ImgRaw
2422 i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
2423         Imager::IO     ig
2424                i_img_dim     x
2425                i_img_dim     y
2426                int     datachannels
2427                int     storechannels
2428                int     intrl
2429
2430 undef_int
2431 i_writeraw_wiol(im,ig)
2432     Imager::ImgRaw     im
2433         Imager::IO     ig
2434
2435 undef_int
2436 i_writebmp_wiol(im,ig)
2437     Imager::ImgRaw     im
2438         Imager::IO     ig
2439
2440 Imager::ImgRaw
2441 i_readbmp_wiol(ig, allow_incomplete=0)
2442         Imager::IO     ig
2443         int            allow_incomplete
2444
2445
2446 undef_int
2447 i_writetga_wiol(im,ig, wierdpack, compress, idstring)
2448     Imager::ImgRaw     im
2449         Imager::IO     ig
2450                int     wierdpack
2451                int     compress
2452               char*    idstring
2453             PREINIT:
2454                 int idlen;
2455                CODE:
2456                 idlen  = SvCUR(ST(4));
2457                 RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
2458                 OUTPUT:
2459                 RETVAL
2460
2461
2462 Imager::ImgRaw
2463 i_readtga_wiol(ig, length)
2464         Imager::IO     ig
2465                int     length
2466
2467
2468
2469
2470 Imager::ImgRaw
2471 i_scaleaxis(im,Value,Axis)
2472     Imager::ImgRaw     im
2473              double     Value
2474                int     Axis
2475
2476 Imager::ImgRaw
2477 i_scale_nn(im,scx,scy)
2478     Imager::ImgRaw     im
2479              double    scx
2480              double    scy
2481
2482 Imager::ImgRaw
2483 i_scale_mixing(im, width, height)
2484     Imager::ImgRaw     im
2485                i_img_dim     width
2486                i_img_dim     height
2487
2488 Imager::ImgRaw
2489 i_haar(im)
2490     Imager::ImgRaw     im
2491
2492 int
2493 i_count_colors(im,maxc)
2494     Imager::ImgRaw     im
2495                int     maxc
2496
2497 void
2498 i_get_anonymous_color_histo(im, maxc = 0x40000000)
2499    Imager::ImgRaw  im
2500    int maxc
2501     PREINIT:
2502         int i;
2503         unsigned int * col_usage = NULL;
2504         int col_cnt;
2505     PPCODE:
2506         col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc);
2507         EXTEND(SP, col_cnt);
2508         for (i = 0; i < col_cnt; i++)  {
2509             PUSHs(sv_2mortal(newSViv( col_usage[i])));
2510         }
2511         myfree(col_usage);
2512         XSRETURN(col_cnt);
2513
2514
2515 void
2516 i_transform(im,opx,opy,parm)
2517     Imager::ImgRaw     im
2518              PREINIT:
2519              double* parm;
2520              int *opx;
2521              int *opy;
2522              int     opxl;
2523              int     opyl;
2524              int     parmlen;
2525              AV* av;
2526              SV* sv1;
2527              int i;
2528              i_img *result;
2529              PPCODE:
2530              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
2531              if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n");
2532              if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n");
2533              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
2534              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n");
2535              if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n");
2536              av=(AV*)SvRV(ST(1));
2537              opxl=av_len(av)+1;
2538              opx=mymalloc( opxl*sizeof(int) );
2539              for(i=0;i<opxl;i++) {
2540                sv1=(*(av_fetch(av,i,0)));
2541                opx[i]=(int)SvIV(sv1);
2542              }
2543              av=(AV*)SvRV(ST(2));
2544              opyl=av_len(av)+1;
2545              opy=mymalloc( opyl*sizeof(int) );
2546              for(i=0;i<opyl;i++) {
2547                sv1=(*(av_fetch(av,i,0)));
2548                opy[i]=(int)SvIV(sv1);
2549              }
2550              av=(AV*)SvRV(ST(3));
2551              parmlen=av_len(av)+1;
2552              parm=mymalloc( parmlen*sizeof(double) );
2553              for(i=0;i<parmlen;i++) { /* FIXME: Bug? */
2554                sv1=(*(av_fetch(av,i,0)));
2555                parm[i]=(double)SvNV(sv1);
2556              }
2557              result=i_transform(im,opx,opxl,opy,opyl,parm,parmlen);
2558              myfree(parm);
2559              myfree(opy);
2560              myfree(opx);
2561              if (result) {
2562                SV *result_sv = sv_newmortal();
2563                EXTEND(SP, 1);
2564                sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result);
2565                PUSHs(result_sv);
2566              }
2567
2568 void
2569 i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
2570         SV *sv_width
2571         SV *sv_height
2572         SV *sv_ops
2573         AV *av_n_regs
2574         AV *av_c_regs
2575         AV *av_in_imgs
2576         int channels
2577              PREINIT:
2578              i_img_dim width;
2579              i_img_dim height;
2580              struct rm_op *ops;
2581              STRLEN ops_len;
2582              int ops_count;
2583              double *n_regs;
2584              int n_regs_count;
2585              i_color *c_regs;
2586              int c_regs_count;
2587              int in_imgs_count;
2588              i_img **in_imgs;
2589              SV *sv1;
2590              IV tmp;
2591              int i;
2592              i_img *result;
2593              PPCODE:
2594
2595              in_imgs_count = av_len(av_in_imgs)+1;
2596              for (i = 0; i < in_imgs_count; ++i) {
2597                sv1 = *av_fetch(av_in_imgs, i, 0);
2598                if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2599                  croak("sv_in_img must contain only images");
2600                }
2601              }
2602              if (in_imgs_count > 0) {
2603                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2604                for (i = 0; i < in_imgs_count; ++i) {              
2605                  sv1 = *av_fetch(av_in_imgs,i,0);
2606                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2607                    croak("Parameter 5 must contain only images");
2608                  }
2609                  tmp = SvIV((SV*)SvRV(sv1));
2610                  in_imgs[i] = INT2PTR(i_img*, tmp);
2611                }
2612              }
2613              else {
2614                /* no input images */
2615                in_imgs = NULL;
2616              }
2617              /* default the output size from the first input if possible */
2618              if (SvOK(sv_width))
2619                width = SvIV(sv_width);
2620              else if (in_imgs_count)
2621                width = in_imgs[0]->xsize;
2622              else
2623                croak("No output image width supplied");
2624
2625              if (SvOK(sv_height))
2626                height = SvIV(sv_height);
2627              else if (in_imgs_count)
2628                height = in_imgs[0]->ysize;
2629              else
2630                croak("No output image height supplied");
2631
2632              ops = (struct rm_op *)SvPV(sv_ops, ops_len);
2633              if (ops_len % sizeof(struct rm_op))
2634                  croak("Imager: Parameter 3 must be a bitmap of regops\n");
2635              ops_count = ops_len / sizeof(struct rm_op);
2636
2637              n_regs_count = av_len(av_n_regs)+1;
2638              n_regs = mymalloc(n_regs_count * sizeof(double));
2639              for (i = 0; i < n_regs_count; ++i) {
2640                sv1 = *av_fetch(av_n_regs,i,0);
2641                if (SvOK(sv1))
2642                  n_regs[i] = SvNV(sv1);
2643              }
2644              c_regs_count = av_len(av_c_regs)+1;
2645              c_regs = mymalloc(c_regs_count * sizeof(i_color));
2646              /* I don't bother initializing the colou?r registers */
2647
2648              result=i_transform2(width, height, channels, ops, ops_count, 
2649                                  n_regs, n_regs_count, 
2650                                  c_regs, c_regs_count, in_imgs, in_imgs_count);
2651              if (in_imgs)
2652                  myfree(in_imgs);
2653              myfree(n_regs);
2654              myfree(c_regs);
2655              if (result) {
2656                SV *result_sv = sv_newmortal();
2657                EXTEND(SP, 1);
2658                sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result);
2659                PUSHs(result_sv);
2660              }
2661
2662
2663 void
2664 i_contrast(im,intensity)
2665     Imager::ImgRaw     im
2666              float     intensity
2667
2668 void
2669 i_hardinvert(im)
2670     Imager::ImgRaw     im
2671
2672 void
2673 i_hardinvertall(im)
2674     Imager::ImgRaw     im
2675
2676 void
2677 i_noise(im,amount,type)
2678     Imager::ImgRaw     im
2679              float     amount
2680      unsigned char     type
2681
2682 void
2683 i_bumpmap(im,bump,channel,light_x,light_y,strength)
2684     Imager::ImgRaw     im
2685     Imager::ImgRaw     bump
2686                int     channel
2687          i_img_dim     light_x
2688          i_img_dim     light_y
2689          i_img_dim     strength
2690
2691
2692 void
2693 i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
2694     Imager::ImgRaw     im
2695     Imager::ImgRaw     bump
2696                int     channel
2697                i_img_dim     tx
2698                i_img_dim     ty
2699              double     Lx
2700              double     Ly
2701              double     Lz
2702              float     cd
2703              float     cs
2704              float     n
2705      Imager::Color     Ia
2706      Imager::Color     Il
2707      Imager::Color     Is
2708
2709
2710
2711 void
2712 i_postlevels(im,levels)
2713     Imager::ImgRaw     im
2714              int       levels
2715
2716 void
2717 i_mosaic(im,size)
2718     Imager::ImgRaw     im
2719          i_img_dim     size
2720
2721 void
2722 i_watermark(im,wmark,tx,ty,pixdiff)
2723     Imager::ImgRaw     im
2724     Imager::ImgRaw     wmark
2725                i_img_dim     tx
2726                i_img_dim     ty
2727                int     pixdiff
2728
2729
2730 void
2731 i_autolevels(im,lsat,usat,skew)
2732     Imager::ImgRaw     im
2733              float     lsat
2734              float     usat
2735              float     skew
2736
2737 void
2738 i_radnoise(im,xo,yo,rscale,ascale)
2739     Imager::ImgRaw     im
2740              float     xo
2741              float     yo
2742              float     rscale
2743              float     ascale
2744
2745 void
2746 i_turbnoise(im, xo, yo, scale)
2747     Imager::ImgRaw     im
2748              float     xo
2749              float     yo
2750              float     scale
2751
2752
2753 void
2754 i_gradgen(im, ...)
2755     Imager::ImgRaw     im
2756       PREINIT:
2757         int num;
2758         i_img_dim *xo;
2759         i_img_dim *yo;
2760         i_color *ival;
2761         int dmeasure;
2762         int i;
2763         SV *sv;
2764         AV *axx;
2765         AV *ayy;
2766         AV *ac;
2767       CODE:
2768         if (items != 5)
2769             croak("Usage: i_gradgen(im, xo, yo, ival, dmeasure)");
2770         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2771             croak("i_gradgen: Second argument must be an array ref");
2772         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2773             croak("i_gradgen: Third argument must be an array ref");
2774         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2775             croak("i_gradgen: Fourth argument must be an array ref");
2776         axx = (AV *)SvRV(ST(1));
2777         ayy = (AV *)SvRV(ST(2));
2778         ac  = (AV *)SvRV(ST(3));
2779         dmeasure = (int)SvIV(ST(4));
2780         
2781         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2782         num = num <= av_len(ac) ? num : av_len(ac);
2783         num++; 
2784         if (num < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each");
2785         xo = mymalloc( sizeof(i_img_dim) * num );
2786         yo = mymalloc( sizeof(i_img_dim) * num );
2787         ival = mymalloc( sizeof(i_color) * num );
2788         for(i = 0; i<num; i++) {
2789           xo[i]   = (i_img_dim)SvIV(* av_fetch(axx, i, 0));
2790           yo[i]   = (i_img_dim)SvIV(* av_fetch(ayy, i, 0));
2791           sv = *av_fetch(ac, i, 0);
2792           if ( !sv_derived_from(sv, "Imager::Color") ) {
2793             free(axx); free(ayy); free(ac);
2794             croak("i_gradgen: Element of fourth argument is not derived from Imager::Color");
2795           }
2796           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
2797         }
2798         i_gradgen(im, num, xo, yo, ival, dmeasure);
2799         myfree(xo);
2800         myfree(yo);
2801         myfree(ival);
2802
2803 Imager::ImgRaw
2804 i_diff_image(im, im2, mindist=0)
2805     Imager::ImgRaw     im
2806     Imager::ImgRaw     im2
2807             double     mindist
2808
2809 undef_int
2810 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2811     Imager::ImgRaw     im
2812             double     xa
2813             double     ya
2814             double     xb
2815             double     yb
2816                int     type
2817                int     repeat
2818                int     combine
2819                int     super_sample
2820             double     ssample_param
2821       PREINIT:
2822         AV *asegs;
2823         int count;
2824         i_fountain_seg *segs;
2825       CODE:
2826         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
2827             croak("i_fountain: argument 11 must be an array ref");
2828         
2829         asegs = (AV *)SvRV(ST(10));
2830         segs = load_fount_segs(aTHX_ asegs, &count);
2831         RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, 
2832                             super_sample, ssample_param, count, segs);
2833         myfree(segs);
2834       OUTPUT:
2835         RETVAL
2836
2837 Imager::FillHandle
2838 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2839             double     xa
2840             double     ya
2841             double     xb
2842             double     yb
2843                int     type
2844                int     repeat
2845                int     combine
2846                int     super_sample
2847             double     ssample_param
2848       PREINIT:
2849         AV *asegs;
2850         int count;
2851         i_fountain_seg *segs;
2852       CODE:
2853         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
2854             croak("i_fountain: argument 11 must be an array ref");
2855         
2856         asegs = (AV *)SvRV(ST(9));
2857         segs = load_fount_segs(aTHX_ asegs, &count);
2858         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
2859                                   super_sample, ssample_param, count, segs);
2860         myfree(segs);        
2861       OUTPUT:
2862         RETVAL
2863
2864 Imager::FillHandle
2865 i_new_fill_opacity(other_fill, alpha_mult)
2866     Imager::FillHandle other_fill
2867     double alpha_mult
2868
2869 void
2870 i_errors()
2871       PREINIT:
2872         i_errmsg *errors;
2873         int i;
2874         AV *av;
2875         SV *sv;
2876       PPCODE:
2877         errors = i_errors();
2878         i = 0;
2879         while (errors[i].msg) {
2880           av = newAV();
2881           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
2882           if (!av_store(av, 0, sv)) {
2883             SvREFCNT_dec(sv);
2884           }
2885           sv = newSViv(errors[i].code);
2886           if (!av_store(av, 1, sv)) {
2887             SvREFCNT_dec(sv);
2888           }
2889           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
2890           ++i;
2891         }
2892
2893 void
2894 i_clear_error()
2895
2896 void
2897 i_push_error(code, msg)
2898         int code
2899         const char *msg
2900
2901 undef_int
2902 i_nearest_color(im, ...)
2903     Imager::ImgRaw     im
2904       PREINIT:
2905         int num;
2906         i_img_dim *xo;
2907         i_img_dim *yo;
2908         i_color *ival;
2909         int dmeasure;
2910         int i;
2911         SV *sv;
2912         AV *axx;
2913         AV *ayy;
2914         AV *ac;
2915       CODE:
2916         if (items != 5)
2917             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
2918         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2919             croak("i_nearest_color: Second argument must be an array ref");
2920         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2921             croak("i_nearest_color: Third argument must be an array ref");
2922         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2923             croak("i_nearest_color: Fourth argument must be an array ref");
2924         axx = (AV *)SvRV(ST(1));
2925         ayy = (AV *)SvRV(ST(2));
2926         ac  = (AV *)SvRV(ST(3));
2927         dmeasure = (int)SvIV(ST(4));
2928         
2929         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2930         num = num <= av_len(ac) ? num : av_len(ac);
2931         num++; 
2932         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
2933         xo = mymalloc( sizeof(i_img_dim) * num );
2934         yo = mymalloc( sizeof(i_img_dim) * num );
2935         ival = mymalloc( sizeof(i_color) * num );
2936         for(i = 0; i<num; i++) {
2937           xo[i]   = (i_img_dim)SvIV(* av_fetch(axx, i, 0));
2938           yo[i]   = (i_img_dim)SvIV(* av_fetch(ayy, i, 0));
2939           sv = *av_fetch(ac, i, 0);
2940           if ( !sv_derived_from(sv, "Imager::Color") ) {
2941             free(axx); free(ayy); free(ac);
2942             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
2943           }
2944           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
2945         }
2946         RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
2947       OUTPUT:
2948         RETVAL
2949
2950 void
2951 malloc_state()
2952
2953 void
2954 DSO_open(filename)
2955              char*       filename
2956              PREINIT:
2957                void *rc;
2958                char *evstr;
2959              PPCODE:
2960                rc=DSO_open(filename,&evstr);
2961                if (rc!=NULL) {
2962                  if (evstr!=NULL) {
2963                    EXTEND(SP,2); 
2964                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
2965                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
2966                  } else {
2967                    EXTEND(SP,1);
2968                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
2969                  }
2970                }
2971
2972
2973 undef_int
2974 DSO_close(dso_handle)
2975              void*       dso_handle
2976
2977 void
2978 DSO_funclist(dso_handle_v)
2979              void*       dso_handle_v
2980              PREINIT:
2981                int i;
2982                DSO_handle *dso_handle;
2983                func_ptr *functions;
2984              PPCODE:
2985                dso_handle=(DSO_handle*)dso_handle_v;
2986                functions = DSO_funclist(dso_handle);
2987                i=0;
2988                while( functions[i].name != NULL) {
2989                  EXTEND(SP,1);
2990                  PUSHs(sv_2mortal(newSVpv(functions[i].name,0)));
2991                  EXTEND(SP,1);
2992                  PUSHs(sv_2mortal(newSVpv(functions[i++].pcode,0)));
2993                }
2994
2995 void
2996 DSO_call(handle,func_index,hv)
2997                void*  handle
2998                int    func_index
2999              PREINIT:
3000                HV* hv;
3001              PPCODE:
3002                if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
3003                hv=(HV*)SvRV(ST(2));
3004                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
3005                DSO_call( (DSO_handle *)handle,func_index,hv);
3006
3007 SV *
3008 i_get_pixel(im, x, y)
3009         Imager::ImgRaw im
3010         i_img_dim x
3011         i_img_dim y;
3012       PREINIT:
3013         i_color *color;
3014       CODE:
3015         color = (i_color *)mymalloc(sizeof(i_color));
3016         if (i_gpix(im, x, y, color) == 0) {
3017           RETVAL = NEWSV(0, 0);
3018           sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
3019         }
3020         else {
3021           myfree(color);
3022           RETVAL = &PL_sv_undef;
3023         }
3024       OUTPUT:
3025         RETVAL
3026         
3027
3028 int
3029 i_ppix(im, x, y, cl)
3030         Imager::ImgRaw im
3031         i_img_dim x
3032         i_img_dim y
3033         Imager::Color cl
3034
3035 Imager::ImgRaw
3036 i_img_pal_new(x, y, channels, maxpal)
3037         i_img_dim x
3038         i_img_dim y
3039         int     channels
3040         int     maxpal
3041
3042 Imager::ImgRaw
3043 i_img_to_pal(src, quant)
3044         Imager::ImgRaw src
3045       PREINIT:
3046         HV *hv;
3047         i_quantize quant;
3048       CODE:
3049         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3050           croak("i_img_to_pal: second argument must be a hash ref");
3051         hv = (HV *)SvRV(ST(1));
3052         memset(&quant, 0, sizeof(quant));
3053         quant.version = 1;
3054         quant.mc_size = 256;
3055         ip_handle_quant_opts(aTHX_ &quant, hv);
3056         RETVAL = i_img_to_pal(src, &quant);
3057         if (RETVAL) {
3058           ip_copy_colors_back(aTHX_ hv, &quant);
3059         }
3060         ip_cleanup_quant_opts(aTHX_ &quant);
3061       OUTPUT:
3062         RETVAL
3063
3064 Imager::ImgRaw
3065 i_img_to_rgb(src)
3066         Imager::ImgRaw src
3067
3068 void
3069 i_img_make_palette(HV *quant_hv, ...)
3070       PREINIT:
3071         size_t count = items - 1;
3072         i_quantize quant;
3073         i_img **imgs = NULL;
3074         ssize_t i;
3075       PPCODE:
3076         if (count <= 0)
3077           croak("Please supply at least one image (%d)", (int)count);
3078         imgs = mymalloc(sizeof(i_img *) * count);
3079         for (i = 0; i < count; ++i) {
3080           SV *img_sv = ST(i + 1);
3081           if (SvROK(img_sv) && sv_derived_from(img_sv, "Imager::ImgRaw")) {
3082             imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(img_sv)));
3083           }
3084           else {
3085             myfree(imgs);
3086             croak("Image %d is not an image object", (int)i+1);
3087           }
3088         }
3089         memset(&quant, 0, sizeof(quant));
3090         quant.version = 1;
3091         quant.mc_size = 256;
3092         ip_handle_quant_opts(aTHX_ &quant, quant_hv);
3093         i_quant_makemap(&quant, imgs, count);
3094         EXTEND(SP, quant.mc_count);
3095         for (i = 0; i < quant.mc_count; ++i) {
3096           SV *sv_c = make_i_color_sv(aTHX_ quant.mc_colors + i);
3097           PUSHs(sv_c);
3098         }
3099         ip_cleanup_quant_opts(aTHX_ &quant);
3100         
3101
3102 void
3103 i_gpal(im, l, r, y)
3104         Imager::ImgRaw  im
3105         i_img_dim     l
3106         i_img_dim     r
3107         i_img_dim     y
3108       PREINIT:
3109         i_palidx *work;
3110         int count, i;
3111       PPCODE:
3112         if (l < r) {
3113           work = mymalloc((r-l) * sizeof(i_palidx));
3114           count = i_gpal(im, l, r, y, work);
3115           if (GIMME_V == G_ARRAY) {
3116             EXTEND(SP, count);
3117             for (i = 0; i < count; ++i) {
3118               PUSHs(sv_2mortal(newSViv(work[i])));
3119             }
3120           }
3121           else {
3122             EXTEND(SP, 1);
3123             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3124           }
3125           myfree(work);
3126         }
3127         else {
3128           if (GIMME_V != G_ARRAY) {
3129             EXTEND(SP, 1);
3130             PUSHs(&PL_sv_undef);
3131           }
3132         }
3133
3134 int
3135 i_ppal(im, l, y, ...)
3136         Imager::ImgRaw  im
3137         i_img_dim     l
3138         i_img_dim     y
3139       PREINIT:
3140         i_palidx *work;
3141         i_img_dim i;
3142       CODE:
3143         if (items > 3) {
3144           work = malloc_temp(aTHX_ sizeof(i_palidx) * (items-3));
3145           for (i=0; i < items-3; ++i) {
3146             work[i] = SvIV(ST(i+3));
3147           }
3148           validate_i_ppal(im, work, items - 3);
3149           RETVAL = i_ppal(im, l, l+items-3, y, work);
3150         }
3151         else {
3152           RETVAL = 0;
3153         }
3154       OUTPUT:
3155         RETVAL
3156
3157 int
3158 i_ppal_p(im, l, y, data)
3159         Imager::ImgRaw  im
3160         i_img_dim     l
3161         i_img_dim     y
3162         SV *data
3163       PREINIT:
3164         i_palidx const *work;
3165         STRLEN len;
3166       CODE:
3167         work = (i_palidx const *)SvPV(data, len);
3168         len /= sizeof(i_palidx);
3169         if (len > 0) {
3170           validate_i_ppal(im, work, len);
3171           RETVAL = i_ppal(im, l, l+len, y, work);
3172         }
3173         else {
3174           RETVAL = 0;
3175         }
3176       OUTPUT:
3177         RETVAL
3178
3179 SV *
3180 i_addcolors(im, ...)
3181         Imager::ImgRaw  im
3182       PREINIT:
3183         int index;
3184         i_color *colors;
3185         int i;
3186       CODE:
3187         if (items < 2)
3188           croak("i_addcolors: no colors to add");
3189         colors = mymalloc((items-1) * sizeof(i_color));
3190         for (i=0; i < items-1; ++i) {
3191           if (sv_isobject(ST(i+1)) 
3192               && sv_derived_from(ST(i+1), "Imager::Color")) {
3193             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3194             colors[i] = *INT2PTR(i_color *, tmp);
3195           }
3196           else {
3197             myfree(colors);
3198             croak("i_addcolor: pixels must be Imager::Color objects");
3199           }
3200         }
3201         index = i_addcolors(im, colors, items-1);
3202         myfree(colors);
3203         if (index == 0) {
3204           RETVAL = newSVpv("0 but true", 0);
3205         }
3206         else if (index == -1) {
3207           RETVAL = &PL_sv_undef;
3208         }
3209         else {
3210           RETVAL = newSViv(index);
3211         }
3212       OUTPUT:
3213         RETVAL
3214
3215 undef_int 
3216 i_setcolors(im, index, ...)
3217         Imager::ImgRaw  im
3218         int index
3219       PREINIT:
3220         i_color *colors;
3221         int i;
3222       CODE:
3223         if (items < 3)
3224           croak("i_setcolors: no colors to add");
3225         colors = mymalloc((items-2) * sizeof(i_color));
3226         for (i=0; i < items-2; ++i) {
3227           if (sv_isobject(ST(i+2)) 
3228               && sv_derived_from(ST(i+2), "Imager::Color")) {
3229             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3230             colors[i] = *INT2PTR(i_color *, tmp);
3231           }
3232           else {
3233             myfree(colors);
3234             croak("i_setcolors: pixels must be Imager::Color objects");
3235           }
3236         }
3237         RETVAL = i_setcolors(im, index, colors, items-2);
3238         myfree(colors);
3239       OUTPUT:
3240         RETVAL
3241
3242 void
3243 i_getcolors(im, index, ...)
3244         Imager::ImgRaw im
3245         int index
3246       PREINIT:
3247         i_color *colors;
3248         int count = 1;
3249         int i;
3250       PPCODE:
3251         if (items > 3)
3252           croak("i_getcolors: too many arguments");
3253         if (items == 3)
3254           count = SvIV(ST(2));
3255         if (count < 1)
3256           croak("i_getcolors: count must be positive");
3257         colors = mymalloc(sizeof(i_color) * count);
3258         if (i_getcolors(im, index, colors, count)) {
3259           for (i = 0; i < count; ++i) {
3260             SV *sv = make_i_color_sv(aTHX_ colors+i);
3261             PUSHs(sv);
3262           }
3263         }
3264         myfree(colors);
3265
3266
3267 undef_neg_int
3268 i_colorcount(im)
3269         Imager::ImgRaw im
3270
3271 undef_neg_int
3272 i_maxcolors(im)
3273         Imager::ImgRaw im
3274
3275 SV *
3276 i_findcolor(im, color)
3277         Imager::ImgRaw im
3278         Imager::Color color
3279       PREINIT:
3280         i_palidx index;
3281       CODE:
3282         if (i_findcolor(im, color, &index)) {
3283           RETVAL = newSViv(index);
3284         }
3285         else {
3286           RETVAL = &PL_sv_undef;
3287         }
3288       OUTPUT:
3289         RETVAL
3290
3291 int
3292 i_img_bits(im)
3293         Imager::ImgRaw  im
3294
3295 int
3296 i_img_type(im)
3297         Imager::ImgRaw  im
3298
3299 int
3300 i_img_virtual(im)
3301         Imager::ImgRaw  im
3302
3303 void
3304 i_gsamp(im, l, r, y, channels)
3305         Imager::ImgRaw im
3306         i_img_dim l
3307         i_img_dim r
3308         i_img_dim y
3309         i_channel_list channels
3310       PREINIT:
3311         i_sample_t *data;
3312         i_img_dim count, i;
3313       PPCODE:
3314         if (l < r) {
3315           data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count); /* XXX: memleak? */
3316           count = i_gsamp(im, l, r, y, data, channels.channels, channels.count);
3317           if (GIMME_V == G_ARRAY) {
3318             EXTEND(SP, count);
3319             for (i = 0; i < count; ++i)
3320               PUSHs(sv_2mortal(newSViv(data[i])));
3321           }
3322           else {
3323             EXTEND(SP, 1);
3324             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3325           }
3326           myfree(data);
3327         }
3328         else {
3329           if (GIMME_V != G_ARRAY) {
3330             EXTEND(SP, 1);
3331             PUSHs(&PL_sv_undef);
3332           }
3333         }
3334
3335 undef_neg_int
3336 i_gsamp_bits(im, l, r, y, bits, target, offset, channels)
3337         Imager::ImgRaw im
3338         i_img_dim l
3339         i_img_dim r
3340         i_img_dim y
3341         int bits
3342         AV *target
3343         STRLEN offset
3344         i_channel_list channels
3345       PREINIT:
3346         unsigned *data;
3347         i_img_dim count, i;
3348       CODE:
3349         i_clear_error();
3350         if (items < 8)
3351           croak("No channel numbers supplied to g_samp()");
3352         if (l < r) {
3353           data = mymalloc(sizeof(unsigned) * (r-l) * channels.count);
3354           count = i_gsamp_bits(im, l, r, y, data, channels.channels, channels.count, bits);
3355           for (i = 0; i < count; ++i) {
3356             av_store(target, i+offset, newSVuv(data[i]));
3357           }
3358           myfree(data);
3359           RETVAL = count;
3360         }
3361         else {
3362           RETVAL = 0;
3363         }
3364       OUTPUT:
3365         RETVAL
3366
3367 undef_neg_int
3368 i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -1)
3369         Imager::ImgRaw im
3370         i_img_dim l
3371         i_img_dim y
3372         int bits
3373         i_channel_list channels
3374         AV *data_av
3375         i_img_dim data_offset
3376         i_img_dim pixel_count
3377       PREINIT:
3378         STRLEN data_count;
3379         size_t data_used;
3380         unsigned *data;
3381         ptrdiff_t i;
3382       CODE:
3383         i_clear_error();
3384
3385         data_count = av_len(data_av) + 1;
3386         if (data_offset < 0) {
3387           croak("data_offset must be non-negative");
3388         }
3389         if (data_offset > data_count) {
3390           croak("data_offset greater than number of samples supplied");
3391         }
3392         if (pixel_count == -1 || 
3393             data_offset + pixel_count * channels.count > data_count) {
3394           pixel_count = (data_count - data_offset) / channels.count;
3395         }
3396
3397         data_used = pixel_count * channels.count;
3398         data = mymalloc(sizeof(unsigned) * data_count);
3399         for (i = 0; i < data_used; ++i)
3400           data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0));
3401
3402         RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels.channels, 
3403                               channels.count, bits);
3404
3405         if (data)
3406           myfree(data);
3407       OUTPUT:
3408         RETVAL
3409
3410 undef_neg_int
3411 i_psamp(im, x, y, channels, data, offset = 0, width = -1)
3412         Imager::ImgRaw im
3413         i_img_dim x
3414         i_img_dim y
3415         i_channel_list channels
3416         i_sample_list data
3417         i_img_dim offset
3418         i_img_dim width
3419     PREINIT:
3420         i_img_dim r;
3421     CODE:
3422         i_clear_error();
3423         if (offset < 0) {
3424           i_push_error(0, "offset must be non-negative");
3425           XSRETURN_UNDEF;
3426         }
3427         if (offset > 0) {
3428           if (offset > data.count) {
3429             i_push_error(0, "offset greater than number of samples supplied");
3430             XSRETURN_UNDEF;
3431           }
3432           data.samples += offset;
3433           data.count -= offset;
3434         }
3435         if (width == -1 ||
3436             width * channels.count > data.count) {
3437           width = data.count / channels.count;
3438         }
3439         r = x + width;
3440         RETVAL = i_psamp(im, x, r, y, data.samples, channels.channels, channels.count);
3441     OUTPUT:
3442         RETVAL
3443
3444 undef_neg_int
3445 i_psampf(im, x, y, channels, data, offset = 0, width = -1)
3446         Imager::ImgRaw im
3447         i_img_dim x
3448         i_img_dim y
3449         i_channel_list channels
3450         i_fsample_list data
3451         i_img_dim offset
3452         i_img_dim width
3453     PREINIT:
3454         i_img_dim r;
3455     CODE:
3456         i_clear_error();
3457         if (offset < 0) {
3458           i_push_error(0, "offset must be non-negative");
3459           XSRETURN_UNDEF;
3460         }
3461         if (offset > 0) {
3462           if (offset > data.count) {
3463             i_push_error(0, "offset greater than number of samples supplied");
3464             XSRETURN_UNDEF;
3465           }
3466           data.samples += offset;
3467           data.count -= offset;
3468         }
3469         if (width == -1 ||
3470             width * channels.count > data.count) {
3471           width = data.count / channels.count;
3472         }
3473         r = x + width;
3474         RETVAL = i_psampf(im, x, r, y, data.samples, channels.channels, channels.count);
3475     OUTPUT:
3476         RETVAL
3477
3478 Imager::ImgRaw
3479 i_img_masked_new(targ, mask, x, y, w, h)
3480         Imager::ImgRaw targ
3481         i_img_dim x
3482         i_img_dim y
3483         i_img_dim w
3484         i_img_dim h
3485       PREINIT:
3486         i_img *mask;
3487       CODE:
3488         if (SvOK(ST(1))) {
3489           if (!sv_isobject(ST(1)) 
3490               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3491             croak("i_img_masked_new: parameter 2 must undef or an image");
3492           }
3493           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3494         }
3495         else
3496           mask = NULL;
3497         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3498       OUTPUT:
3499         RETVAL
3500
3501 int
3502 i_plin(im, l, y, ...)
3503         Imager::ImgRaw  im
3504         i_img_dim     l
3505         i_img_dim     y
3506       PREINIT:
3507         i_color *work;
3508         STRLEN i;
3509         STRLEN len;
3510         size_t count;
3511       CODE:
3512         if (items > 3) {
3513           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3514             /* supplied as a byte string */
3515             work = (i_color *)SvPV(ST(3), len);
3516             count = len / sizeof(i_color);
3517             if (count * sizeof(i_color) != len) {
3518               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3519             }
3520             RETVAL = i_plin(im, l, l+count, y, work);
3521           }
3522           else {
3523             work = mymalloc(sizeof(i_color) * (items-3));
3524             for (i=0; i < items-3; ++i) {
3525               if (sv_isobject(ST(i+3)) 
3526                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3527                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3528                 work[i] = *INT2PTR(i_color *, tmp);
3529               }
3530               else {
3531                 myfree(work);
3532                 croak("i_plin: pixels must be Imager::Color objects");
3533               }
3534             }
3535             RETVAL = i_plin(im, l, l+items-3, y, work);
3536             myfree(work);
3537           }
3538         }
3539         else {
3540           RETVAL = 0;
3541         }
3542       OUTPUT:
3543         RETVAL
3544
3545 int
3546 i_ppixf(im, x, y, cl)
3547         Imager::ImgRaw im
3548         i_img_dim x
3549         i_img_dim y
3550         Imager::Color::Float cl
3551
3552 void
3553 i_gsampf(im, l, r, y, channels)
3554         Imager::ImgRaw im
3555         i_img_dim l
3556         i_img_dim r
3557         i_img_dim y
3558         i_channel_list channels
3559       PREINIT:
3560         i_fsample_t *data;
3561         i_img_dim count, i;
3562       PPCODE:
3563         if (l < r) {
3564           data = mymalloc(sizeof(i_fsample_t) * (r-l) * channels.count);
3565           count = i_gsampf(im, l, r, y, data, channels.channels, channels.count);
3566           if (GIMME_V == G_ARRAY) {
3567             EXTEND(SP, count);
3568             for (i = 0; i < count; ++i)
3569               PUSHs(sv_2mortal(newSVnv(data[i])));
3570           }
3571           else {
3572             EXTEND(SP, 1);
3573             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3574           }
3575           myfree(data);
3576         }
3577         else {
3578           if (GIMME_V != G_ARRAY) {
3579             EXTEND(SP, 1);
3580             PUSHs(&PL_sv_undef);
3581           }
3582         }
3583
3584 int
3585 i_plinf(im, l, y, ...)
3586         Imager::ImgRaw  im
3587         i_img_dim     l
3588         i_img_dim     y
3589       PREINIT:
3590         i_fcolor *work;
3591         i_img_dim i;
3592         STRLEN len;
3593         size_t count;
3594       CODE:
3595         if (items > 3) {
3596           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3597             /* supplied as a byte string */
3598             work = (i_fcolor *)SvPV(ST(3), len);
3599             count = len / sizeof(i_fcolor);
3600             if (count * sizeof(i_fcolor) != len) {
3601               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3602             }
3603             RETVAL = i_plinf(im, l, l+count, y, work);
3604           }
3605           else {
3606             work = mymalloc(sizeof(i_fcolor) * (items-3));
3607             for (i=0; i < items-3; ++i) {
3608               if (sv_isobject(ST(i+3)) 
3609                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3610                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3611                 work[i] = *INT2PTR(i_fcolor *, tmp);
3612               }
3613               else {
3614                 myfree(work);
3615                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3616               }
3617             }
3618             /**(char *)0 = 1;*/
3619             RETVAL = i_plinf(im, l, l+items-3, y, work);
3620             myfree(work);
3621           }
3622         }
3623         else {
3624           RETVAL = 0;
3625         }
3626       OUTPUT:
3627         RETVAL
3628
3629 SV *
3630 i_gpixf(im, x, y)
3631         Imager::ImgRaw im
3632         i_img_dim x
3633         i_img_dim y;
3634       PREINIT:
3635         i_fcolor *color;
3636       CODE:
3637         color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3638         if (i_gpixf(im, x, y, color) == 0) {
3639           RETVAL = NEWSV(0,0);
3640           sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
3641         }
3642         else {
3643           myfree(color);
3644           RETVAL = &PL_sv_undef;
3645         }
3646       OUTPUT:
3647         RETVAL
3648
3649 void
3650 i_glin(im, l, r, y)
3651         Imager::ImgRaw im
3652         i_img_dim l
3653         i_img_dim r
3654         i_img_dim y
3655       PREINIT:
3656         i_color *vals;
3657         i_img_dim count, i;
3658       PPCODE:
3659         if (l < r) {
3660           vals = mymalloc((r-l) * sizeof(i_color));
3661           memset(vals, 0, (r-l) * sizeof(i_color));
3662           count = i_glin(im, l, r, y, vals);
3663           if (GIMME_V == G_ARRAY) {
3664             EXTEND(SP, count);
3665             for (i = 0; i < count; ++i) {
3666               SV *sv = make_i_color_sv(aTHX_ vals+i);
3667               PUSHs(sv);
3668             }
3669           }
3670           else if (count) {
3671             EXTEND(SP, 1);
3672             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3673           }
3674           myfree(vals);
3675         }
3676
3677 void
3678 i_glinf(im, l, r, y)
3679         Imager::ImgRaw im
3680         i_img_dim l
3681         i_img_dim r
3682         i_img_dim y
3683       PREINIT:
3684         i_fcolor *vals;
3685         i_img_dim count, i;
3686         i_fcolor zero;
3687       PPCODE:
3688         for (i = 0; i < MAXCHANNELS; ++i)
3689           zero.channel[i] = 0;
3690         if (l < r) {
3691           vals = mymalloc((r-l) * sizeof(i_fcolor));
3692           for (i = 0; i < r-l; ++i)
3693             vals[i] = zero;
3694           count = i_glinf(im, l, r, y, vals);
3695           if (GIMME_V == G_ARRAY) {
3696             EXTEND(SP, count);
3697             for (i = 0; i < count; ++i) {
3698               SV *sv;
3699               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3700               *col = vals[i];
3701               sv = sv_newmortal();
3702               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3703               PUSHs(sv);
3704             }
3705           }
3706           else if (count) {
3707             EXTEND(SP, 1);
3708             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3709           }
3710           myfree(vals);
3711         }
3712
3713 Imager::ImgRaw
3714 i_img_8_new(x, y, ch)
3715         i_img_dim x
3716         i_img_dim y
3717         int ch
3718
3719 Imager::ImgRaw
3720 i_img_16_new(x, y, ch)
3721         i_img_dim x
3722         i_img_dim y
3723         int ch
3724
3725 Imager::ImgRaw
3726 i_img_to_rgb16(im)
3727        Imager::ImgRaw im
3728
3729 Imager::ImgRaw
3730 i_img_double_new(x, y, ch)
3731         i_img_dim x
3732         i_img_dim y
3733         int ch
3734
3735 Imager::ImgRaw
3736 i_img_to_drgb(im)
3737        Imager::ImgRaw im
3738
3739 undef_int
3740 i_tags_addn(im, name, code, idata)
3741         Imager::ImgRaw im
3742         int     code
3743         int     idata
3744       PREINIT:
3745         char *name;
3746         STRLEN len;
3747       CODE:
3748         if (SvOK(ST(1)))
3749           name = SvPV(ST(1), len);
3750         else
3751           name = NULL;
3752         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3753       OUTPUT:
3754         RETVAL
3755
3756 undef_int
3757 i_tags_add(im, name, code, data, idata)
3758         Imager::ImgRaw  im
3759         int code
3760         int idata
3761       PREINIT:
3762         char *name;
3763         char *data;
3764         STRLEN len;
3765       CODE:
3766         if (SvOK(ST(1)))
3767           name = SvPV(ST(1), len);
3768         else
3769           name = NULL;
3770         if (SvOK(ST(3)))
3771           data = SvPV(ST(3), len);
3772         else {
3773           data = NULL;
3774           len = 0;
3775         }
3776         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3777       OUTPUT:
3778         RETVAL
3779
3780 SV *
3781 i_tags_find(im, name, start)
3782         Imager::ImgRaw  im
3783         char *name
3784         int start
3785       PREINIT:
3786         int entry;
3787       CODE:
3788         if (i_tags_find(&im->tags, name, start, &entry)) {
3789           if (entry == 0)
3790             RETVAL = newSVpv("0 but true", 0);
3791           else
3792             RETVAL = newSViv(entry);
3793         } else {
3794           RETVAL = &PL_sv_undef;
3795         }
3796       OUTPUT:
3797         RETVAL
3798
3799 SV *
3800 i_tags_findn(im, code, start)
3801         Imager::ImgRaw  im
3802         int             code
3803         int             start
3804       PREINIT:
3805         int entry;
3806       CODE:
3807         if (i_tags_findn(&im->tags, code, start, &entry)) {
3808           if (entry == 0)
3809             RETVAL = newSVpv("0 but true", 0);
3810           else
3811             RETVAL = newSViv(entry);
3812         }
3813         else {
3814           RETVAL = &PL_sv_undef;
3815         }
3816       OUTPUT:
3817         RETVAL
3818
3819 int
3820 i_tags_delete(im, entry)
3821         Imager::ImgRaw  im
3822         int             entry
3823       CODE:
3824         RETVAL = i_tags_delete(&im->tags, entry);
3825       OUTPUT:
3826         RETVAL
3827
3828 int
3829 i_tags_delbyname(im, name)
3830         Imager::ImgRaw  im
3831         char *          name
3832       CODE:
3833         RETVAL = i_tags_delbyname(&im->tags, name);
3834       OUTPUT:
3835         RETVAL
3836
3837 int
3838 i_tags_delbycode(im, code)
3839         Imager::ImgRaw  im
3840         int             code
3841       CODE:
3842         RETVAL = i_tags_delbycode(&im->tags, code);
3843       OUTPUT:
3844         RETVAL
3845
3846 void
3847 i_tags_get(im, index)
3848         Imager::ImgRaw  im
3849         int             index
3850       PPCODE:
3851         if (index >= 0 && index < im->tags.count) {
3852           i_img_tag *entry = im->tags.tags + index;
3853           EXTEND(SP, 5);
3854         
3855           if (entry->name) {
3856             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3857           }
3858           else {
3859             PUSHs(sv_2mortal(newSViv(entry->code)));
3860           }
3861           if (entry->data) {
3862             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3863           }
3864           else {
3865             PUSHs(sv_2mortal(newSViv(entry->idata)));
3866           }
3867         }
3868
3869 void
3870 i_tags_get_string(im, what_sv)
3871         Imager::ImgRaw  im
3872         SV *what_sv
3873       PREINIT:
3874         char const *name = NULL;
3875         int code;
3876         char buffer[200];
3877       PPCODE:
3878         if (SvIOK(what_sv)) {
3879           code = SvIV(what_sv);
3880           name = NULL;
3881         }
3882         else {
3883           name = SvPV_nolen(what_sv);
3884           code = 0;
3885         }
3886         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
3887           EXTEND(SP, 1);
3888           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
3889         }
3890
3891 int
3892 i_tags_count(im)
3893         Imager::ImgRaw  im
3894       CODE:
3895         RETVAL = im->tags.count;
3896       OUTPUT:
3897         RETVAL
3898
3899
3900
3901 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
3902
3903 void
3904 IFILL_DESTROY(fill)
3905         Imager::FillHandle fill
3906
3907 int
3908 IFILL_CLONE_SKIP(...)
3909     CODE:
3910         (void)items; /* avoid unused warning for XS variable */
3911         RETVAL = 1;
3912     OUTPUT:
3913         RETVAL
3914
3915 MODULE = Imager         PACKAGE = Imager
3916
3917 Imager::FillHandle
3918 i_new_fill_solid(cl, combine)
3919         Imager::Color cl
3920         int combine
3921
3922 Imager::FillHandle
3923 i_new_fill_solidf(cl, combine)
3924         Imager::Color::Float cl
3925         int combine
3926
3927 Imager::FillHandle
3928 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
3929         Imager::Color fg
3930         Imager::Color bg
3931         int combine
3932         int hatch
3933         i_img_dim dx
3934         i_img_dim dy
3935       PREINIT:
3936         unsigned char *cust_hatch;
3937         STRLEN len;
3938       CODE:
3939         if (SvOK(ST(4))) {
3940           cust_hatch = (unsigned char *)SvPV(ST(4), len);
3941         }
3942         else
3943           cust_hatch = NULL;
3944         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
3945       OUTPUT:
3946         RETVAL
3947
3948 Imager::FillHandle
3949 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
3950         Imager::Color::Float fg
3951         Imager::Color::Float bg
3952         int combine
3953         int hatch
3954         i_img_dim dx
3955         i_img_dim dy
3956       PREINIT:
3957         unsigned char *cust_hatch;
3958         STRLEN len;
3959       CODE:
3960         if (SvOK(ST(4))) {
3961           cust_hatch = (unsigned char *)SvPV(ST(4), len);
3962         }
3963         else
3964           cust_hatch = NULL;
3965         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
3966       OUTPUT:
3967         RETVAL
3968
3969 Imager::FillHandle
3970 i_new_fill_image(src, matrix, xoff, yoff, combine)
3971         Imager::ImgRaw src
3972         i_img_dim xoff
3973         i_img_dim yoff
3974         int combine
3975       PREINIT:
3976         double matrix[9];
3977         double *matrixp;
3978         AV *av;
3979         IV len;
3980         SV *sv1;
3981         int i;
3982       CODE:
3983         if (!SvOK(ST(1))) {
3984           matrixp = NULL;
3985         }
3986         else {
3987           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
3988             croak("i_new_fill_image: parameter must be an arrayref");
3989           av=(AV*)SvRV(ST(1));
3990           len=av_len(av)+1;
3991           if (len > 9)
3992             len = 9;
3993           for (i = 0; i < len; ++i) {
3994             sv1=(*(av_fetch(av,i,0)));
3995             matrix[i] = SvNV(sv1);
3996           }
3997           for (; i < 9; ++i)
3998             matrix[i] = 0;
3999           matrixp = matrix;
4000         }
4001         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4002       OUTPUT:
4003         RETVAL
4004
4005 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
4006
4007 # this class is only exposed for testing
4008
4009 int
4010 i_int_hlines_testing()
4011
4012 #if i_int_hlines_testing()
4013
4014 Imager::Internal::Hlines
4015 i_int_hlines_new(start_y, count_y, start_x, count_x)
4016         i_img_dim start_y
4017         int count_y
4018         i_img_dim start_x
4019         int count_x
4020
4021 Imager::Internal::Hlines
4022 i_int_hlines_new_img(im)
4023         Imager::ImgRaw im
4024
4025 void
4026 i_int_hlines_add(hlines, y, minx, width)
4027         Imager::Internal::Hlines hlines
4028         i_img_dim y
4029         i_img_dim minx
4030         i_img_dim width
4031
4032 void
4033 i_int_hlines_DESTROY(hlines)
4034         Imager::Internal::Hlines hlines
4035
4036 SV *
4037 i_int_hlines_dump(hlines)
4038         Imager::Internal::Hlines hlines
4039
4040 int
4041 i_int_hlines_CLONE_SKIP(cls)
4042
4043 #endif
4044
4045 MODULE = Imager  PACKAGE = Imager::Context PREFIX=im_context_
4046
4047 void
4048 im_context_DESTROY(ctx)
4049    Imager::Context ctx
4050
4051 #ifdef PERL_IMPLICIT_CONTEXT
4052
4053 void
4054 im_context_CLONE(...)
4055     CODE:
4056       MY_CXT_CLONE;
4057       (void)items;
4058       /* the following sv_setref_pv() will free this inc */
4059       im_context_refinc(MY_CXT.ctx, "CLONE");
4060       MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE");
4061       sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
4062
4063 #endif
4064
4065 BOOT:
4066         PERL_SET_GLOBAL_CALLBACKS;
4067         PERL_PL_SET_GLOBAL_CALLBACKS;
4068 #ifdef PERL_IMPLICIT_CONTEXT
4069         {
4070           MY_CXT_INIT;
4071           (void)MY_CXT;
4072         }
4073 #endif
4074         start_context(aTHX);
4075         im_get_context = perl_get_context;
4076 #ifdef HAVE_LIBTT
4077         i_tt_start();
4078 #endif