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