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