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