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