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