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