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