]> git.imager.perl.org - imager.git/blob - Imager.xs
note on the PNG / Imager::Probe change
[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 undef_int
1761 i_flipxy(im, direction)
1762     Imager::ImgRaw     im
1763                int     direction
1764
1765 Imager::ImgRaw
1766 i_rotate90(im, degrees)
1767     Imager::ImgRaw      im
1768                int      degrees
1769
1770 Imager::ImgRaw
1771 i_rotate_exact(im, amount, ...)
1772     Imager::ImgRaw      im
1773             double      amount
1774       PREINIT:
1775         i_color *backp = NULL;
1776         i_fcolor *fbackp = NULL;
1777         int i;
1778         SV * sv1;
1779       CODE:
1780         /* extract the bg colors if any */
1781         /* yes, this is kind of strange */
1782         for (i = 2; i < items; ++i) {
1783           sv1 = ST(i);
1784           if (sv_derived_from(sv1, "Imager::Color")) {
1785             IV tmp = SvIV((SV*)SvRV(sv1));
1786             backp = INT2PTR(i_color *, tmp);
1787           }
1788           else if (sv_derived_from(sv1, "Imager::Color::Float")) {
1789             IV tmp = SvIV((SV*)SvRV(sv1));
1790             fbackp = INT2PTR(i_fcolor *, tmp);
1791           }
1792         }
1793         RETVAL = i_rotate_exact_bg(im, amount, backp, fbackp);
1794       OUTPUT:
1795         RETVAL
1796
1797 Imager::ImgRaw
1798 i_matrix_transform(im, xsize, ysize, matrix, ...)
1799     Imager::ImgRaw      im
1800                int      xsize
1801                int      ysize
1802       PREINIT:
1803         double matrix[9];
1804         AV *av;
1805         IV len;
1806         SV *sv1;
1807         int i;
1808         i_color *backp = NULL;
1809         i_fcolor *fbackp = NULL;
1810       CODE:
1811         if (!SvROK(ST(3)) || SvTYPE(SvRV(ST(3))) != SVt_PVAV)
1812           croak("i_matrix_transform: parameter 4 must be an array ref\n");
1813         av=(AV*)SvRV(ST(3));
1814         len=av_len(av)+1;
1815         if (len > 9)
1816           len = 9;
1817         for (i = 0; i < len; ++i) {
1818           sv1=(*(av_fetch(av,i,0)));
1819           matrix[i] = SvNV(sv1);
1820         }
1821         for (; i < 9; ++i)
1822           matrix[i] = 0;
1823         /* extract the bg colors if any */
1824         /* yes, this is kind of strange */
1825         for (i = 4; i < items; ++i) {
1826           sv1 = ST(i);
1827           if (sv_derived_from(sv1, "Imager::Color")) {
1828             IV tmp = SvIV((SV*)SvRV(sv1));
1829             backp = INT2PTR(i_color *, tmp);
1830           }
1831           else if (sv_derived_from(sv1, "Imager::Color::Float")) {
1832             IV tmp = SvIV((SV*)SvRV(sv1));
1833             fbackp = INT2PTR(i_fcolor *, tmp);
1834           }
1835         }
1836         RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp);
1837       OUTPUT:
1838         RETVAL
1839
1840 undef_int
1841 i_gaussian(im,stdev)
1842     Imager::ImgRaw     im
1843             double     stdev
1844
1845 void
1846 i_unsharp_mask(im,stdev,scale)
1847     Imager::ImgRaw     im
1848              float     stdev
1849              double    scale
1850
1851 int
1852 i_conv(im,coef)
1853         Imager::ImgRaw     im
1854         AV *coef
1855      PREINIT:
1856         double*    c_coef;
1857         int     len;
1858         SV* sv1;
1859         int i;
1860     CODE:
1861         len = av_len(coef) + 1;
1862         c_coef=mymalloc( len * sizeof(double) );
1863         for(i = 0; i  < len; i++) {
1864           sv1 = (*(av_fetch(coef, i, 0)));
1865           c_coef[i] = (double)SvNV(sv1);
1866         }
1867         RETVAL = i_conv(im, c_coef, len);
1868         myfree(c_coef);
1869     OUTPUT:
1870         RETVAL
1871
1872 Imager::ImgRaw
1873 i_convert(src, avmain)
1874     Imager::ImgRaw     src
1875     AV *avmain
1876         PREINIT:
1877           float *coeff;
1878           int outchan;
1879           int inchan;
1880           SV **temp;
1881           AV *avsub;
1882           int len;
1883           int i, j;
1884         CODE:
1885           outchan = av_len(avmain)+1;
1886           /* find the biggest */
1887           inchan = 0;
1888           for (j=0; j < outchan; ++j) {
1889             temp = av_fetch(avmain, j, 0);
1890             if (temp && SvROK(*temp) && SvTYPE(SvRV(*temp)) == SVt_PVAV) {
1891               avsub = (AV*)SvRV(*temp);
1892               len = av_len(avsub)+1;
1893               if (len > inchan)
1894                 inchan = len;
1895             }
1896           }
1897           coeff = mymalloc(sizeof(float) * outchan * inchan);
1898           for (j = 0; j < outchan; ++j) {
1899             avsub = (AV*)SvRV(*av_fetch(avmain, j, 0));
1900             len = av_len(avsub)+1;
1901             for (i = 0; i < len; ++i) {
1902               temp = av_fetch(avsub, i, 0);
1903               if (temp)
1904                 coeff[i+j*inchan] = SvNV(*temp);
1905               else
1906                 coeff[i+j*inchan] = 0;
1907             }
1908             while (i < inchan)
1909               coeff[i++ + j*inchan] = 0;
1910           }
1911           RETVAL = i_convert(src, coeff, outchan, inchan);
1912           myfree(coeff);
1913         OUTPUT:
1914           RETVAL
1915
1916
1917 void
1918 i_map(im, pmaps)
1919     Imager::ImgRaw     im
1920         PREINIT:
1921           unsigned int mask = 0;
1922           AV *avmain;
1923           AV *avsub;
1924           SV **temp;
1925           int len;
1926           int i, j;
1927           unsigned char (*maps)[256];
1928         CODE:
1929           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
1930             croak("i_map: parameter 2 must be an arrayref\n");
1931           avmain = (AV*)SvRV(ST(1));
1932           len = av_len(avmain)+1;
1933           if (im->channels < len) len = im->channels;
1934
1935           maps = mymalloc( len * sizeof(unsigned char [256]) );
1936
1937           for (j=0; j<len ; j++) {
1938             temp = av_fetch(avmain, j, 0);
1939             if (temp && SvROK(*temp) && (SvTYPE(SvRV(*temp)) == SVt_PVAV) ) {
1940               avsub = (AV*)SvRV(*temp);
1941               if(av_len(avsub) != 255) continue;
1942               mask |= 1<<j;
1943               for (i=0; i<256 ; i++) {
1944                 int val;
1945                 temp = av_fetch(avsub, i, 0);
1946                 val = temp ? SvIV(*temp) : 0;
1947                 if (val<0) val = 0;
1948                 if (val>255) val = 255;
1949                 maps[j][i] = val;
1950               }
1951             }
1952           }
1953           i_map(im, maps, mask);
1954           myfree(maps);
1955
1956
1957
1958 float
1959 i_img_diff(im1,im2)
1960     Imager::ImgRaw     im1
1961     Imager::ImgRaw     im2
1962
1963 double
1964 i_img_diffd(im1,im2)
1965     Imager::ImgRaw     im1
1966     Imager::ImgRaw     im2
1967
1968 undef_int         
1969 i_init_fonts(t1log=0)
1970     int t1log
1971
1972 bool
1973 _is_color_object(sv)
1974         SV* sv
1975     CODE:
1976         SvGETMAGIC(sv);
1977         RETVAL = SvOK(sv) && SvROK(sv) &&
1978            (sv_derived_from(sv, "Imager::Color")
1979           || sv_derived_from(sv, "Imager::Color::Float"));
1980     OUTPUT:
1981         RETVAL
1982
1983 #ifdef HAVE_LIBT1
1984
1985 void
1986 i_t1_set_aa(st)
1987                int     st
1988
1989 int
1990 i_t1_new(pfb,afm)
1991               char*    pfb
1992               char*    afm
1993
1994 int
1995 i_t1_destroy(font_id)
1996                int     font_id
1997
1998
1999 undef_int
2000 i_t1_cp(im,xb,yb,channel,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
2001     Imager::ImgRaw     im
2002                int     xb
2003                int     yb
2004                int     channel
2005                int     fontnum
2006              float     points
2007                 SV*    str_sv
2008                int     align
2009                int     utf8
2010               char*    flags
2011              PREINIT:
2012                char *str;
2013                STRLEN len;
2014              CODE:
2015 #ifdef SvUTF8
2016                if (SvUTF8(str_sv))
2017                  utf8 = 1;
2018 #endif
2019                str = SvPV(str_sv, len);
2020                RETVAL = i_t1_cp(im, xb,yb,channel,fontnum,points,str,len,align,
2021                                   utf8,flags);
2022            OUTPUT:
2023              RETVAL
2024
2025
2026 void
2027 i_t1_bbox(fontnum,point,str_sv,len_ignored,utf8=0,flags="")
2028                int     fontnum
2029              float     point
2030                 SV*    str_sv
2031                int     utf8
2032               char*    flags
2033              PREINIT:
2034                char *str;
2035                STRLEN len;
2036                int     cords[BOUNDING_BOX_COUNT];
2037                int i;
2038                int rc;
2039              PPCODE:
2040 #ifdef SvUTF8
2041                if (SvUTF8(str_sv))
2042                  utf8 = 1;
2043 #endif
2044                str = SvPV(str_sv, len);
2045                rc = i_t1_bbox(fontnum,point,str,len,cords,utf8,flags);
2046                if (rc > 0) {
2047                  EXTEND(SP, rc);
2048                  for (i = 0; i < rc; ++i)
2049                    PUSHs(sv_2mortal(newSViv(cords[i])));
2050                }
2051
2052
2053
2054 undef_int
2055 i_t1_text(im,xb,yb,cl,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
2056     Imager::ImgRaw     im
2057                int     xb
2058                int     yb
2059      Imager::Color    cl
2060                int     fontnum
2061              float     points
2062                 SV*    str_sv
2063                int     align
2064                int     utf8
2065               char*    flags
2066              PREINIT:
2067                char *str;
2068                STRLEN len;
2069              CODE:
2070 #ifdef SvUTF8
2071                if (SvUTF8(str_sv))
2072                  utf8 = 1;
2073 #endif
2074                str = SvPV(str_sv, len);
2075                RETVAL = i_t1_text(im, xb,yb,cl,fontnum,points,str,len,align,
2076                                   utf8,flags);
2077            OUTPUT:
2078              RETVAL
2079
2080 void
2081 i_t1_has_chars(handle, text_sv, utf8 = 0)
2082         int handle
2083         SV  *text_sv
2084         int utf8
2085       PREINIT:
2086         char const *text;
2087         STRLEN len;
2088         char *work;
2089         int count;
2090         int i;
2091       PPCODE:
2092 #ifdef SvUTF8
2093         if (SvUTF8(text_sv))
2094           utf8 = 1;
2095 #endif
2096         text = SvPV(text_sv, len);
2097         work = mymalloc(len);
2098         count = i_t1_has_chars(handle, text, len, utf8, work);
2099         if (GIMME_V == G_ARRAY) {
2100           EXTEND(SP, count);
2101           for (i = 0; i < count; ++i) {
2102             PUSHs(sv_2mortal(newSViv(work[i])));
2103           }
2104         }
2105         else {
2106           EXTEND(SP, 1);
2107           PUSHs(sv_2mortal(newSVpv(work, count)));
2108         }
2109         myfree(work);
2110
2111 void
2112 i_t1_face_name(handle)
2113         int handle
2114       PREINIT:
2115         char name[255];
2116         int len;
2117       PPCODE:
2118         len = i_t1_face_name(handle, name, sizeof(name));
2119         if (len) {
2120           EXTEND(SP, 1);
2121           PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
2122         }
2123
2124 void
2125 i_t1_glyph_name(handle, text_sv, utf8 = 0)
2126         int handle
2127         SV *text_sv
2128         int utf8
2129       PREINIT:
2130         char const *text;
2131         STRLEN work_len;
2132         int len;
2133         char name[255];
2134       PPCODE:
2135 #ifdef SvUTF8
2136         if (SvUTF8(text_sv))
2137           utf8 = 1;
2138 #endif
2139         text = SvPV(text_sv, work_len);
2140         len = work_len;
2141         while (len) {
2142           unsigned long ch;
2143           if (utf8) {
2144             ch = i_utf8_advance(&text, &len);
2145             if (ch == ~0UL) {
2146               i_push_error(0, "invalid UTF8 character");
2147               break;
2148             }
2149           }
2150           else {
2151             ch = *text++;
2152             --len;
2153           }
2154           EXTEND(SP, 1);
2155           if (i_t1_glyph_name(handle, ch, name, sizeof(name))) {
2156             PUSHs(sv_2mortal(newSVpv(name, 0)));
2157           }
2158           else {
2159             PUSHs(&PL_sv_undef);
2160           } 
2161         }
2162
2163 #endif 
2164
2165 #ifdef HAVE_LIBTT
2166
2167
2168 Imager::Font::TT
2169 i_tt_new(fontname)
2170               char*     fontname
2171
2172
2173 MODULE = Imager         PACKAGE = Imager::Font::TT      PREFIX=TT_
2174
2175 #define TT_DESTROY(handle) i_tt_destroy(handle)
2176
2177 void
2178 TT_DESTROY(handle)
2179      Imager::Font::TT   handle
2180
2181 int
2182 TT_CLONE_SKIP(...)
2183     CODE:
2184         RETVAL = 1;
2185     OUTPUT:
2186         RETVAL
2187
2188
2189 MODULE = Imager         PACKAGE = Imager
2190
2191
2192 undef_int
2193 i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1)
2194   Imager::Font::TT     handle
2195     Imager::ImgRaw     im
2196                int     xb
2197                int     yb
2198      Imager::Color     cl
2199              float     points
2200               SV *     str_sv
2201                int     smooth
2202                int     utf8
2203                int     align
2204              PREINIT:
2205                char *str;
2206                STRLEN len;
2207              CODE:
2208 #ifdef SvUTF8
2209                if (SvUTF8(str_sv))
2210                  utf8 = 1;
2211 #endif
2212                str = SvPV(str_sv, len);
2213                RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, 
2214                                   len, smooth, utf8, align);
2215              OUTPUT:
2216                RETVAL                
2217
2218
2219 undef_int
2220 i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1)
2221   Imager::Font::TT     handle
2222     Imager::ImgRaw     im
2223                int     xb
2224                int     yb
2225                int     channel
2226              float     points
2227               SV *     str_sv
2228                int     smooth
2229                int     utf8
2230                int     align
2231              PREINIT:
2232                char *str;
2233                STRLEN len;
2234              CODE:
2235 #ifdef SvUTF8
2236                if (SvUTF8(str_sv))
2237                  utf8 = 1;
2238 #endif
2239                str = SvPV(str_sv, len);
2240                RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len,
2241                                 smooth, utf8, align);
2242              OUTPUT:
2243                 RETVAL
2244
2245
2246 void
2247 i_tt_bbox(handle,point,str_sv,len_ignored, utf8)
2248   Imager::Font::TT     handle
2249              float     point
2250                SV*    str_sv
2251                int     utf8
2252              PREINIT:
2253                int     cords[BOUNDING_BOX_COUNT],rc;
2254                char *  str;
2255                STRLEN len;
2256                int i;
2257              PPCODE:
2258 #ifdef SvUTF8
2259                if (SvUTF8(ST(2)))
2260                  utf8 = 1;
2261 #endif
2262                str = SvPV(str_sv, len);
2263                if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) {
2264                  EXTEND(SP, rc);
2265                  for (i = 0; i < rc; ++i) {
2266                    PUSHs(sv_2mortal(newSViv(cords[i])));
2267                  }
2268                }
2269
2270 void
2271 i_tt_has_chars(handle, text_sv, utf8)
2272         Imager::Font::TT handle
2273         SV  *text_sv
2274         int utf8
2275       PREINIT:
2276         char const *text;
2277         STRLEN len;
2278         char *work;
2279         int count;
2280         int i;
2281       PPCODE:
2282 #ifdef SvUTF8
2283         if (SvUTF8(text_sv))
2284           utf8 = 1;
2285 #endif
2286         text = SvPV(text_sv, len);
2287         work = mymalloc(len);
2288         count = i_tt_has_chars(handle, text, len, utf8, work);
2289         if (GIMME_V == G_ARRAY) {
2290           EXTEND(SP, count);
2291           for (i = 0; i < count; ++i) {
2292             PUSHs(sv_2mortal(newSViv(work[i])));
2293           }
2294         }
2295         else {
2296           EXTEND(SP, 1);
2297           PUSHs(sv_2mortal(newSVpv(work, count)));
2298         }
2299         myfree(work);
2300
2301 void
2302 i_tt_dump_names(handle)
2303         Imager::Font::TT handle
2304
2305 void
2306 i_tt_face_name(handle)
2307         Imager::Font::TT handle
2308       PREINIT:
2309         char name[255];
2310         int len;
2311       PPCODE:
2312         len = i_tt_face_name(handle, name, sizeof(name));
2313         if (len) {
2314           EXTEND(SP, 1);
2315           PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
2316         }
2317
2318 void
2319 i_tt_glyph_name(handle, text_sv, utf8 = 0)
2320         Imager::Font::TT handle
2321         SV *text_sv
2322         int utf8
2323       PREINIT:
2324         char const *text;
2325         STRLEN work_len;
2326         int len;
2327         int outsize;
2328         char name[255];
2329       PPCODE:
2330 #ifdef SvUTF8
2331         if (SvUTF8(text_sv))
2332           utf8 = 1;
2333 #endif
2334         text = SvPV(text_sv, work_len);
2335         len = work_len;
2336         while (len) {
2337           unsigned long ch;
2338           if (utf8) {
2339             ch = i_utf8_advance(&text, &len);
2340             if (ch == ~0UL) {
2341               i_push_error(0, "invalid UTF8 character");
2342               break;
2343             }
2344           }
2345           else {
2346             ch = *text++;
2347             --len;
2348           }
2349           EXTEND(SP, 1);
2350           if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
2351             PUSHs(sv_2mortal(newSVpv(name, 0)));
2352           }
2353           else {
2354             PUSHs(&PL_sv_undef);
2355           } 
2356         }
2357
2358 #endif 
2359
2360 const char *
2361 i_test_format_probe(ig, length)
2362         Imager::IO     ig
2363                int     length
2364
2365 Imager::ImgRaw
2366 i_readpnm_wiol(ig, allow_incomplete)
2367         Imager::IO     ig
2368                int     allow_incomplete
2369
2370
2371 void
2372 i_readpnm_multi_wiol(ig, allow_incomplete)
2373         Imager::IO ig
2374                int     allow_incomplete
2375       PREINIT:
2376         i_img **imgs;
2377         int count=0;
2378         int i;
2379       PPCODE:
2380         imgs = i_readpnm_multi_wiol(ig, &count, allow_incomplete);
2381         if (imgs) {
2382           EXTEND(SP, count);
2383           for (i = 0; i < count; ++i) {
2384             SV *sv = sv_newmortal();
2385             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2386             PUSHs(sv);
2387           }
2388           myfree(imgs);
2389         }
2390
2391 undef_int
2392 i_writeppm_wiol(im, ig)
2393     Imager::ImgRaw     im
2394         Imager::IO     ig
2395
2396
2397
2398
2399
2400 Imager::ImgRaw
2401 i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
2402         Imager::IO     ig
2403                int     x
2404                int     y
2405                int     datachannels
2406                int     storechannels
2407                int     intrl
2408
2409 undef_int
2410 i_writeraw_wiol(im,ig)
2411     Imager::ImgRaw     im
2412         Imager::IO     ig
2413
2414 undef_int
2415 i_writebmp_wiol(im,ig)
2416     Imager::ImgRaw     im
2417         Imager::IO     ig
2418
2419 Imager::ImgRaw
2420 i_readbmp_wiol(ig, allow_incomplete=0)
2421         Imager::IO     ig
2422         int            allow_incomplete
2423
2424
2425 undef_int
2426 i_writetga_wiol(im,ig, wierdpack, compress, idstring)
2427     Imager::ImgRaw     im
2428         Imager::IO     ig
2429                int     wierdpack
2430                int     compress
2431               char*    idstring
2432             PREINIT:
2433                 int idlen;
2434                CODE:
2435                 idlen  = SvCUR(ST(4));
2436                 RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
2437                 OUTPUT:
2438                 RETVAL
2439
2440
2441 Imager::ImgRaw
2442 i_readtga_wiol(ig, length)
2443         Imager::IO     ig
2444                int     length
2445
2446
2447
2448
2449 Imager::ImgRaw
2450 i_scaleaxis(im,Value,Axis)
2451     Imager::ImgRaw     im
2452              float     Value
2453                int     Axis
2454
2455 Imager::ImgRaw
2456 i_scale_nn(im,scx,scy)
2457     Imager::ImgRaw     im
2458              float     scx
2459              float     scy
2460
2461 Imager::ImgRaw
2462 i_scale_mixing(im, width, height)
2463     Imager::ImgRaw     im
2464                int     width
2465                int     height
2466
2467 Imager::ImgRaw
2468 i_haar(im)
2469     Imager::ImgRaw     im
2470
2471 int
2472 i_count_colors(im,maxc)
2473     Imager::ImgRaw     im
2474                int     maxc
2475
2476 void
2477 i_get_anonymous_color_histo(im, maxc = 0x40000000)
2478    Imager::ImgRaw  im
2479    int maxc
2480     PREINIT:
2481         int i;
2482         unsigned int * col_usage = NULL;
2483         int col_cnt;
2484     PPCODE:
2485         col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc);
2486         EXTEND(SP, col_cnt);
2487         for (i = 0; i < col_cnt; i++)  {
2488             PUSHs(sv_2mortal(newSViv( col_usage[i])));
2489         }
2490         myfree(col_usage);
2491         XSRETURN(col_cnt);
2492
2493
2494 Imager::ImgRaw
2495 i_transform(im,opx,opy,parm)
2496     Imager::ImgRaw     im
2497              PREINIT:
2498              double* parm;
2499              int*    opx;
2500              int*    opy;
2501              int     opxl;
2502              int     opyl;
2503              int     parmlen;
2504              AV* av;
2505              SV* sv1;
2506              int i;
2507              CODE:
2508              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
2509              if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n");
2510              if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n");
2511              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
2512              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n");
2513              if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n");
2514              av=(AV*)SvRV(ST(1));
2515              opxl=av_len(av)+1;
2516              opx=mymalloc( opxl*sizeof(int) );
2517              for(i=0;i<opxl;i++) {
2518                sv1=(*(av_fetch(av,i,0)));
2519                opx[i]=(int)SvIV(sv1);
2520              }
2521              av=(AV*)SvRV(ST(2));
2522              opyl=av_len(av)+1;
2523              opy=mymalloc( opyl*sizeof(int) );
2524              for(i=0;i<opyl;i++) {
2525                sv1=(*(av_fetch(av,i,0)));
2526                opy[i]=(int)SvIV(sv1);
2527              }
2528              av=(AV*)SvRV(ST(3));
2529              parmlen=av_len(av)+1;
2530              parm=mymalloc( parmlen*sizeof(double) );
2531              for(i=0;i<parmlen;i++) { /* FIXME: Bug? */
2532                sv1=(*(av_fetch(av,i,0)));
2533                parm[i]=(double)SvNV(sv1);
2534              }
2535              RETVAL=i_transform(im,opx,opxl,opy,opyl,parm,parmlen);
2536              myfree(parm);
2537              myfree(opy);
2538              myfree(opx);
2539              ST(0) = sv_newmortal();
2540              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2541              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2542
2543 Imager::ImgRaw
2544 i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
2545         SV *sv_width
2546         SV *sv_height
2547         SV *sv_ops
2548         AV *av_n_regs
2549         AV *av_c_regs
2550         AV *av_in_imgs
2551         int channels
2552              PREINIT:
2553              int width;
2554              int height;
2555              struct rm_op *ops;
2556              STRLEN ops_len;
2557              int ops_count;
2558              double *n_regs;
2559              int n_regs_count;
2560              i_color *c_regs;
2561              int c_regs_count;
2562              int in_imgs_count;
2563              i_img **in_imgs;
2564              SV *sv1;
2565              IV tmp;
2566              int i;
2567              CODE:
2568
2569              in_imgs_count = av_len(av_in_imgs)+1;
2570              for (i = 0; i < in_imgs_count; ++i) {
2571                sv1 = *av_fetch(av_in_imgs, i, 0);
2572                if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2573                  croak("sv_in_img must contain only images");
2574                }
2575              }
2576              if (in_imgs_count > 0) {
2577                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2578                for (i = 0; i < in_imgs_count; ++i) {              
2579                  sv1 = *av_fetch(av_in_imgs,i,0);
2580                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2581                    croak("Parameter 5 must contain only images");
2582                  }
2583                  tmp = SvIV((SV*)SvRV(sv1));
2584                  in_imgs[i] = INT2PTR(i_img*, tmp);
2585                }
2586              }
2587              else {
2588                /* no input images */
2589                in_imgs = NULL;
2590              }
2591              /* default the output size from the first input if possible */
2592              if (SvOK(sv_width))
2593                width = SvIV(sv_width);
2594              else if (in_imgs_count)
2595                width = in_imgs[0]->xsize;
2596              else
2597                croak("No output image width supplied");
2598
2599              if (SvOK(sv_height))
2600                height = SvIV(sv_height);
2601              else if (in_imgs_count)
2602                height = in_imgs[0]->ysize;
2603              else
2604                croak("No output image height supplied");
2605
2606              ops = (struct rm_op *)SvPV(sv_ops, ops_len);
2607              if (ops_len % sizeof(struct rm_op))
2608                  croak("Imager: Parameter 3 must be a bitmap of regops\n");
2609              ops_count = ops_len / sizeof(struct rm_op);
2610
2611              n_regs_count = av_len(av_n_regs)+1;
2612              n_regs = mymalloc(n_regs_count * sizeof(double));
2613              for (i = 0; i < n_regs_count; ++i) {
2614                sv1 = *av_fetch(av_n_regs,i,0);
2615                if (SvOK(sv1))
2616                  n_regs[i] = SvNV(sv1);
2617              }
2618              c_regs_count = av_len(av_c_regs)+1;
2619              c_regs = mymalloc(c_regs_count * sizeof(i_color));
2620              /* I don't bother initializing the colou?r registers */
2621
2622              RETVAL=i_transform2(width, height, channels, ops, ops_count, 
2623                                  n_regs, n_regs_count, 
2624                                  c_regs, c_regs_count, in_imgs, in_imgs_count);
2625              if (in_imgs)
2626                  myfree(in_imgs);
2627              myfree(n_regs);
2628              myfree(c_regs);
2629              ST(0) = sv_newmortal();
2630              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2631              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2632
2633
2634 void
2635 i_contrast(im,intensity)
2636     Imager::ImgRaw     im
2637              float     intensity
2638
2639 void
2640 i_hardinvert(im)
2641     Imager::ImgRaw     im
2642
2643 void
2644 i_hardinvertall(im)
2645     Imager::ImgRaw     im
2646
2647 void
2648 i_noise(im,amount,type)
2649     Imager::ImgRaw     im
2650              float     amount
2651      unsigned char     type
2652
2653 void
2654 i_bumpmap(im,bump,channel,light_x,light_y,strength)
2655     Imager::ImgRaw     im
2656     Imager::ImgRaw     bump
2657                int     channel
2658                int     light_x
2659                int     light_y
2660                int     strength
2661
2662
2663 void
2664 i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
2665     Imager::ImgRaw     im
2666     Imager::ImgRaw     bump
2667                int     channel
2668                int     tx
2669                int     ty
2670              float     Lx
2671              float     Ly
2672              float     Lz
2673              float     cd
2674              float     cs
2675              float     n
2676      Imager::Color     Ia
2677      Imager::Color     Il
2678      Imager::Color     Is
2679
2680
2681
2682 void
2683 i_postlevels(im,levels)
2684     Imager::ImgRaw     im
2685              int       levels
2686
2687 void
2688 i_mosaic(im,size)
2689     Imager::ImgRaw     im
2690                int     size
2691
2692 void
2693 i_watermark(im,wmark,tx,ty,pixdiff)
2694     Imager::ImgRaw     im
2695     Imager::ImgRaw     wmark
2696                int     tx
2697                int     ty
2698                int     pixdiff
2699
2700
2701 void
2702 i_autolevels(im,lsat,usat,skew)
2703     Imager::ImgRaw     im
2704              float     lsat
2705              float     usat
2706              float     skew
2707
2708 void
2709 i_radnoise(im,xo,yo,rscale,ascale)
2710     Imager::ImgRaw     im
2711              float     xo
2712              float     yo
2713              float     rscale
2714              float     ascale
2715
2716 void
2717 i_turbnoise(im, xo, yo, scale)
2718     Imager::ImgRaw     im
2719              float     xo
2720              float     yo
2721              float     scale
2722
2723
2724 void
2725 i_gradgen(im, ...)
2726     Imager::ImgRaw     im
2727       PREINIT:
2728         int num;
2729         int *xo;
2730         int *yo;
2731         i_color *ival;
2732         int dmeasure;
2733         int i;
2734         SV *sv;
2735         AV *axx;
2736         AV *ayy;
2737         AV *ac;
2738       CODE:
2739         if (items != 5)
2740             croak("Usage: i_gradgen(im, xo, yo, ival, dmeasure)");
2741         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2742             croak("i_gradgen: Second argument must be an array ref");
2743         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2744             croak("i_gradgen: Third argument must be an array ref");
2745         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2746             croak("i_gradgen: Fourth argument must be an array ref");
2747         axx = (AV *)SvRV(ST(1));
2748         ayy = (AV *)SvRV(ST(2));
2749         ac  = (AV *)SvRV(ST(3));
2750         dmeasure = (int)SvIV(ST(4));
2751         
2752         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2753         num = num <= av_len(ac) ? num : av_len(ac);
2754         num++; 
2755         if (num < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each");
2756         xo = mymalloc( sizeof(int) * num );
2757         yo = mymalloc( sizeof(int) * num );
2758         ival = mymalloc( sizeof(i_color) * num );
2759         for(i = 0; i<num; i++) {
2760           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
2761           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
2762           sv = *av_fetch(ac, i, 0);
2763           if ( !sv_derived_from(sv, "Imager::Color") ) {
2764             free(axx); free(ayy); free(ac);
2765             croak("i_gradgen: Element of fourth argument is not derived from Imager::Color");
2766           }
2767           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
2768         }
2769         i_gradgen(im, num, xo, yo, ival, dmeasure);
2770         myfree(xo);
2771         myfree(yo);
2772         myfree(ival);
2773
2774 Imager::ImgRaw
2775 i_diff_image(im, im2, mindist=0)
2776     Imager::ImgRaw     im
2777     Imager::ImgRaw     im2
2778             double     mindist
2779
2780 undef_int
2781 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2782     Imager::ImgRaw     im
2783             double     xa
2784             double     ya
2785             double     xb
2786             double     yb
2787                int     type
2788                int     repeat
2789                int     combine
2790                int     super_sample
2791             double     ssample_param
2792       PREINIT:
2793         AV *asegs;
2794         int count;
2795         i_fountain_seg *segs;
2796       CODE:
2797         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
2798             croak("i_fountain: argument 11 must be an array ref");
2799         
2800         asegs = (AV *)SvRV(ST(10));
2801         segs = load_fount_segs(aTHX_ asegs, &count);
2802         RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, 
2803                             super_sample, ssample_param, count, segs);
2804         myfree(segs);
2805       OUTPUT:
2806         RETVAL
2807
2808 Imager::FillHandle
2809 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2810             double     xa
2811             double     ya
2812             double     xb
2813             double     yb
2814                int     type
2815                int     repeat
2816                int     combine
2817                int     super_sample
2818             double     ssample_param
2819       PREINIT:
2820         AV *asegs;
2821         int count;
2822         i_fountain_seg *segs;
2823       CODE:
2824         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
2825             croak("i_fountain: argument 11 must be an array ref");
2826         
2827         asegs = (AV *)SvRV(ST(9));
2828         segs = load_fount_segs(aTHX_ asegs, &count);
2829         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
2830                                   super_sample, ssample_param, count, segs);
2831         myfree(segs);        
2832       OUTPUT:
2833         RETVAL
2834
2835 Imager::FillHandle
2836 i_new_fill_opacity(other_fill, alpha_mult)
2837     Imager::FillHandle other_fill
2838     double alpha_mult
2839
2840 void
2841 i_errors()
2842       PREINIT:
2843         i_errmsg *errors;
2844         int i;
2845         AV *av;
2846         SV *sv;
2847       PPCODE:
2848         errors = i_errors();
2849         i = 0;
2850         while (errors[i].msg) {
2851           av = newAV();
2852           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
2853           if (!av_store(av, 0, sv)) {
2854             SvREFCNT_dec(sv);
2855           }
2856           sv = newSViv(errors[i].code);
2857           if (!av_store(av, 1, sv)) {
2858             SvREFCNT_dec(sv);
2859           }
2860           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
2861           ++i;
2862         }
2863
2864 void
2865 i_clear_error()
2866
2867 void
2868 i_push_error(code, msg)
2869         int code
2870         const char *msg
2871
2872 undef_int
2873 i_nearest_color(im, ...)
2874     Imager::ImgRaw     im
2875       PREINIT:
2876         int num;
2877         int *xo;
2878         int *yo;
2879         i_color *ival;
2880         int dmeasure;
2881         int i;
2882         SV *sv;
2883         AV *axx;
2884         AV *ayy;
2885         AV *ac;
2886       CODE:
2887         if (items != 5)
2888             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
2889         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2890             croak("i_nearest_color: Second argument must be an array ref");
2891         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2892             croak("i_nearest_color: Third argument must be an array ref");
2893         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2894             croak("i_nearest_color: Fourth argument must be an array ref");
2895         axx = (AV *)SvRV(ST(1));
2896         ayy = (AV *)SvRV(ST(2));
2897         ac  = (AV *)SvRV(ST(3));
2898         dmeasure = (int)SvIV(ST(4));
2899         
2900         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2901         num = num <= av_len(ac) ? num : av_len(ac);
2902         num++; 
2903         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
2904         xo = mymalloc( sizeof(int) * num );
2905         yo = mymalloc( sizeof(int) * num );
2906         ival = mymalloc( sizeof(i_color) * num );
2907         for(i = 0; i<num; i++) {
2908           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
2909           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
2910           sv = *av_fetch(ac, i, 0);
2911           if ( !sv_derived_from(sv, "Imager::Color") ) {
2912             free(axx); free(ayy); free(ac);
2913             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
2914           }
2915           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
2916         }
2917         RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
2918       OUTPUT:
2919         RETVAL
2920
2921 void
2922 malloc_state()
2923
2924 void
2925 DSO_open(filename)
2926              char*       filename
2927              PREINIT:
2928                void *rc;
2929                char *evstr;
2930              PPCODE:
2931                rc=DSO_open(filename,&evstr);
2932                if (rc!=NULL) {
2933                  if (evstr!=NULL) {
2934                    EXTEND(SP,2); 
2935                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
2936                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
2937                  } else {
2938                    EXTEND(SP,1);
2939                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
2940                  }
2941                }
2942
2943
2944 undef_int
2945 DSO_close(dso_handle)
2946              void*       dso_handle
2947
2948 void
2949 DSO_funclist(dso_handle_v)
2950              void*       dso_handle_v
2951              PREINIT:
2952                int i;
2953                DSO_handle *dso_handle;
2954                func_ptr *functions;
2955              PPCODE:
2956                dso_handle=(DSO_handle*)dso_handle_v;
2957                functions = DSO_funclist(dso_handle);
2958                i=0;
2959                while( functions[i].name != NULL) {
2960                  EXTEND(SP,1);
2961                  PUSHs(sv_2mortal(newSVpv(functions[i].name,0)));
2962                  EXTEND(SP,1);
2963                  PUSHs(sv_2mortal(newSVpv(functions[i++].pcode,0)));
2964                }
2965
2966 void
2967 DSO_call(handle,func_index,hv)
2968                void*  handle
2969                int    func_index
2970              PREINIT:
2971                HV* hv;
2972              PPCODE:
2973                if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
2974                hv=(HV*)SvRV(ST(2));
2975                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
2976                DSO_call( (DSO_handle *)handle,func_index,hv);
2977
2978 SV *
2979 i_get_pixel(im, x, y)
2980         Imager::ImgRaw im
2981         int x
2982         int y;
2983       PREINIT:
2984         i_color *color;
2985       CODE:
2986         color = (i_color *)mymalloc(sizeof(i_color));
2987         if (i_gpix(im, x, y, color) == 0) {
2988           RETVAL = NEWSV(0, 0);
2989           sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
2990         }
2991         else {
2992           myfree(color);
2993           RETVAL = &PL_sv_undef;
2994         }
2995       OUTPUT:
2996         RETVAL
2997         
2998
2999 int
3000 i_ppix(im, x, y, cl)
3001         Imager::ImgRaw im
3002         int x
3003         int y
3004         Imager::Color cl
3005
3006 Imager::ImgRaw
3007 i_img_pal_new(x, y, channels, maxpal)
3008         int     x
3009         int     y
3010         int     channels
3011         int     maxpal
3012
3013 Imager::ImgRaw
3014 i_img_to_pal(src, quant)
3015         Imager::ImgRaw src
3016       PREINIT:
3017         HV *hv;
3018         i_quantize quant;
3019       CODE:
3020         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3021           croak("i_img_to_pal: second argument must be a hash ref");
3022         hv = (HV *)SvRV(ST(1));
3023         memset(&quant, 0, sizeof(quant));
3024         quant.version = 1;
3025         quant.mc_size = 256;
3026         ip_handle_quant_opts(aTHX_ &quant, hv);
3027         RETVAL = i_img_to_pal(src, &quant);
3028         if (RETVAL) {
3029           ip_copy_colors_back(aTHX_ hv, &quant);
3030         }
3031         ip_cleanup_quant_opts(aTHX_ &quant);
3032       OUTPUT:
3033         RETVAL
3034
3035 Imager::ImgRaw
3036 i_img_to_rgb(src)
3037         Imager::ImgRaw src
3038
3039 void
3040 i_gpal(im, l, r, y)
3041         Imager::ImgRaw  im
3042         int     l
3043         int     r
3044         int     y
3045       PREINIT:
3046         i_palidx *work;
3047         int count, i;
3048       PPCODE:
3049         if (l < r) {
3050           work = mymalloc((r-l) * sizeof(i_palidx));
3051           count = i_gpal(im, l, r, y, work);
3052           if (GIMME_V == G_ARRAY) {
3053             EXTEND(SP, count);
3054             for (i = 0; i < count; ++i) {
3055               PUSHs(sv_2mortal(newSViv(work[i])));
3056             }
3057           }
3058           else {
3059             EXTEND(SP, 1);
3060             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3061           }
3062           myfree(work);
3063         }
3064         else {
3065           if (GIMME_V != G_ARRAY) {
3066             EXTEND(SP, 1);
3067             PUSHs(&PL_sv_undef);
3068           }
3069         }
3070
3071 int
3072 i_ppal(im, l, y, ...)
3073         Imager::ImgRaw  im
3074         int     l
3075         int     y
3076       PREINIT:
3077         i_palidx *work;
3078         int i;
3079       CODE:
3080         if (items > 3) {
3081           work = mymalloc(sizeof(i_palidx) * (items-3));
3082           for (i=0; i < items-3; ++i) {
3083             work[i] = SvIV(ST(i+3));
3084           }
3085           validate_i_ppal(im, work, items - 3);
3086           RETVAL = i_ppal(im, l, l+items-3, y, work);
3087           myfree(work);
3088         }
3089         else {
3090           RETVAL = 0;
3091         }
3092       OUTPUT:
3093         RETVAL
3094
3095 int
3096 i_ppal_p(im, l, y, data)
3097         Imager::ImgRaw  im
3098         int     l
3099         int     y
3100         SV *data
3101       PREINIT:
3102         i_palidx const *work;
3103         STRLEN len;
3104       CODE:
3105         work = (i_palidx const *)SvPV(data, len);
3106         len /= sizeof(i_palidx);
3107         if (len > 0) {
3108           validate_i_ppal(im, work, len);
3109           RETVAL = i_ppal(im, l, l+len, y, work);
3110         }
3111         else {
3112           RETVAL = 0;
3113         }
3114       OUTPUT:
3115         RETVAL
3116
3117 SV *
3118 i_addcolors(im, ...)
3119         Imager::ImgRaw  im
3120       PREINIT:
3121         int index;
3122         i_color *colors;
3123         int i;
3124       CODE:
3125         if (items < 2)
3126           croak("i_addcolors: no colors to add");
3127         colors = mymalloc((items-1) * sizeof(i_color));
3128         for (i=0; i < items-1; ++i) {
3129           if (sv_isobject(ST(i+1)) 
3130               && sv_derived_from(ST(i+1), "Imager::Color")) {
3131             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3132             colors[i] = *INT2PTR(i_color *, tmp);
3133           }
3134           else {
3135             myfree(colors);
3136             croak("i_addcolor: pixels must be Imager::Color objects");
3137           }
3138         }
3139         index = i_addcolors(im, colors, items-1);
3140         myfree(colors);
3141         if (index == 0) {
3142           RETVAL = newSVpv("0 but true", 0);
3143         }
3144         else if (index == -1) {
3145           RETVAL = &PL_sv_undef;
3146         }
3147         else {
3148           RETVAL = newSViv(index);
3149         }
3150       OUTPUT:
3151         RETVAL
3152
3153 undef_int 
3154 i_setcolors(im, index, ...)
3155         Imager::ImgRaw  im
3156         int index
3157       PREINIT:
3158         i_color *colors;
3159         int i;
3160       CODE:
3161         if (items < 3)
3162           croak("i_setcolors: no colors to add");
3163         colors = mymalloc((items-2) * sizeof(i_color));
3164         for (i=0; i < items-2; ++i) {
3165           if (sv_isobject(ST(i+2)) 
3166               && sv_derived_from(ST(i+2), "Imager::Color")) {
3167             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3168             colors[i] = *INT2PTR(i_color *, tmp);
3169           }
3170           else {
3171             myfree(colors);
3172             croak("i_setcolors: pixels must be Imager::Color objects");
3173           }
3174         }
3175         RETVAL = i_setcolors(im, index, colors, items-2);
3176         myfree(colors);
3177       OUTPUT:
3178         RETVAL
3179
3180 void
3181 i_getcolors(im, index, ...)
3182         Imager::ImgRaw im
3183         int index
3184       PREINIT:
3185         i_color *colors;
3186         int count = 1;
3187         int i;
3188       PPCODE:
3189         if (items > 3)
3190           croak("i_getcolors: too many arguments");
3191         if (items == 3)
3192           count = SvIV(ST(2));
3193         if (count < 1)
3194           croak("i_getcolors: count must be positive");
3195         colors = mymalloc(sizeof(i_color) * count);
3196         if (i_getcolors(im, index, colors, count)) {
3197           for (i = 0; i < count; ++i) {
3198             i_color *pv;
3199             SV *sv = sv_newmortal();
3200             pv = mymalloc(sizeof(i_color));
3201             *pv = colors[i];
3202             sv_setref_pv(sv, "Imager::Color", (void *)pv);
3203             PUSHs(sv);
3204           }
3205         }
3206         myfree(colors);
3207
3208
3209 undef_neg_int
3210 i_colorcount(im)
3211         Imager::ImgRaw im
3212
3213 undef_neg_int
3214 i_maxcolors(im)
3215         Imager::ImgRaw im
3216
3217 SV *
3218 i_findcolor(im, color)
3219         Imager::ImgRaw im
3220         Imager::Color color
3221       PREINIT:
3222         i_palidx index;
3223       CODE:
3224         if (i_findcolor(im, color, &index)) {
3225           RETVAL = newSViv(index);
3226         }
3227         else {
3228           RETVAL = &PL_sv_undef;
3229         }
3230       OUTPUT:
3231         RETVAL
3232
3233 int
3234 i_img_bits(im)
3235         Imager::ImgRaw  im
3236
3237 int
3238 i_img_type(im)
3239         Imager::ImgRaw  im
3240
3241 int
3242 i_img_virtual(im)
3243         Imager::ImgRaw  im
3244
3245 void
3246 i_gsamp(im, l, r, y, ...)
3247         Imager::ImgRaw im
3248         int l
3249         int r
3250         int y
3251       PREINIT:
3252         int *chans;
3253         int chan_count;
3254         i_sample_t *data;
3255         int count, i;
3256       PPCODE:
3257         if (items < 5)
3258           croak("No channel numbers supplied to g_samp()");
3259         if (l < r) {
3260           chan_count = items - 4;
3261           chans = mymalloc(sizeof(int) * chan_count);
3262           for (i = 0; i < chan_count; ++i)
3263             chans[i] = SvIV(ST(i+4));
3264           data = mymalloc(sizeof(i_sample_t) * (r-l) * chan_count); /* XXX: memleak? */
3265           count = i_gsamp(im, l, r, y, data, chans, chan_count);
3266           myfree(chans);
3267           if (GIMME_V == G_ARRAY) {
3268             EXTEND(SP, count);
3269             for (i = 0; i < count; ++i)
3270               PUSHs(sv_2mortal(newSViv(data[i])));
3271           }
3272           else {
3273             EXTEND(SP, 1);
3274             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3275           }
3276           myfree(data);
3277         }
3278         else {
3279           if (GIMME_V != G_ARRAY) {
3280             EXTEND(SP, 1);
3281             PUSHs(&PL_sv_undef);
3282           }
3283         }
3284
3285 undef_neg_int
3286 i_gsamp_bits(im, l, r, y, bits, target, offset, ...)
3287         Imager::ImgRaw im
3288         int l
3289         int r
3290         int y
3291         int bits
3292         AV *target
3293         int offset
3294       PREINIT:
3295         int *chans;
3296         int chan_count;
3297         unsigned *data;
3298         int count, i;
3299       CODE:
3300         i_clear_error();
3301         if (items < 8)
3302           croak("No channel numbers supplied to g_samp()");
3303         if (l < r) {
3304           chan_count = items - 7;
3305           chans = mymalloc(sizeof(int) * chan_count);
3306           for (i = 0; i < chan_count; ++i)
3307             chans[i] = SvIV(ST(i+7));
3308           data = mymalloc(sizeof(unsigned) * (r-l) * chan_count);
3309           count = i_gsamp_bits(im, l, r, y, data, chans, chan_count, bits);
3310           myfree(chans);
3311           for (i = 0; i < count; ++i) {
3312             av_store(target, i+offset, newSVuv(data[i]));
3313           }
3314           myfree(data);
3315           RETVAL = count;
3316         }
3317         else {
3318           RETVAL = 0;
3319         }
3320       OUTPUT:
3321         RETVAL
3322
3323 undef_neg_int
3324 i_psamp_bits(im, l, y, bits, channels_sv, data_av, data_offset = 0, pixel_count = -1)
3325         Imager::ImgRaw im
3326         int l
3327         int y
3328         int bits
3329         SV *channels_sv
3330         AV *data_av
3331         int data_offset
3332         int pixel_count
3333       PREINIT:
3334         int chan_count;
3335         int *channels;
3336         int data_count;
3337         int data_used;
3338         unsigned *data;
3339         int i;
3340       CODE:
3341         i_clear_error();
3342         if (SvOK(channels_sv)) {
3343           AV *channels_av;
3344           if (!SvROK(channels_sv) || SvTYPE(SvRV(channels_sv)) != SVt_PVAV) {
3345             croak("channels is not an array ref");
3346           }
3347           channels_av = (AV *)SvRV(channels_sv);
3348           chan_count = av_len(channels_av) + 1;
3349           if (chan_count < 1) {
3350             croak("i_psamp_bits: no channels provided");
3351           }
3352           channels = mymalloc(sizeof(int) * chan_count);
3353           for (i = 0; i < chan_count; ++i)
3354             channels[i] = SvIV(*av_fetch(channels_av, i, 0));
3355         }
3356         else {
3357           chan_count = im->channels;
3358           channels = NULL;
3359         }
3360
3361         data_count = av_len(data_av) + 1;
3362         if (data_offset < 0) {
3363           croak("data_offset must by non-negative");
3364         }
3365         if (data_offset > data_count) {
3366           croak("data_offset greater than number of samples supplied");
3367         }
3368         if (pixel_count == -1 || 
3369             data_offset + pixel_count * chan_count > data_count) {
3370           pixel_count = (data_count - data_offset) / chan_count;
3371         }
3372
3373         data_used = pixel_count * chan_count;
3374         data = mymalloc(sizeof(unsigned) * data_count);
3375         for (i = 0; i < data_used; ++i)
3376           data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0));
3377
3378         RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels, 
3379                               chan_count, bits);
3380
3381         if (data)
3382           myfree(data);
3383         if (channels)
3384           myfree(channels);
3385       OUTPUT:
3386         RETVAL
3387
3388 Imager::ImgRaw
3389 i_img_masked_new(targ, mask, x, y, w, h)
3390         Imager::ImgRaw targ
3391         int x
3392         int y
3393         int w
3394         int h
3395       PREINIT:
3396         i_img *mask;
3397       CODE:
3398         if (SvOK(ST(1))) {
3399           if (!sv_isobject(ST(1)) 
3400               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3401             croak("i_img_masked_new: parameter 2 must undef or an image");
3402           }
3403           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3404         }
3405         else
3406           mask = NULL;
3407         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3408       OUTPUT:
3409         RETVAL
3410
3411 int
3412 i_plin(im, l, y, ...)
3413         Imager::ImgRaw  im
3414         int     l
3415         int     y
3416       PREINIT:
3417         i_color *work;
3418         int i;
3419         STRLEN len;
3420         int count;
3421       CODE:
3422         if (items > 3) {
3423           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3424             /* supplied as a byte string */
3425             work = (i_color *)SvPV(ST(3), len);
3426             count = len / sizeof(i_color);
3427             if (count * sizeof(i_color) != len) {
3428               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3429             }
3430             RETVAL = i_plin(im, l, l+count, y, work);
3431           }
3432           else {
3433             work = mymalloc(sizeof(i_color) * (items-3));
3434             for (i=0; i < items-3; ++i) {
3435               if (sv_isobject(ST(i+3)) 
3436                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3437                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3438                 work[i] = *INT2PTR(i_color *, tmp);
3439               }
3440               else {
3441                 myfree(work);
3442                 croak("i_plin: pixels must be Imager::Color objects");
3443               }
3444             }
3445             RETVAL = i_plin(im, l, l+items-3, y, work);
3446             myfree(work);
3447           }
3448         }
3449         else {
3450           RETVAL = 0;
3451         }
3452       OUTPUT:
3453         RETVAL
3454
3455 int
3456 i_ppixf(im, x, y, cl)
3457         Imager::ImgRaw im
3458         int x
3459         int y
3460         Imager::Color::Float cl
3461
3462 void
3463 i_gsampf(im, l, r, y, ...)
3464         Imager::ImgRaw im
3465         int l
3466         int r
3467         int y
3468       PREINIT:
3469         int *chans;
3470         int chan_count;
3471         i_fsample_t *data;
3472         int count, i;
3473       PPCODE:
3474         if (items < 5)
3475           croak("No channel numbers supplied to g_sampf()");
3476         if (l < r) {
3477           chan_count = items - 4;
3478           chans = mymalloc(sizeof(int) * chan_count);
3479           for (i = 0; i < chan_count; ++i)
3480             chans[i] = SvIV(ST(i+4));
3481           data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count);
3482           count = i_gsampf(im, l, r, y, data, chans, chan_count);
3483           myfree(chans);
3484           if (GIMME_V == G_ARRAY) {
3485             EXTEND(SP, count);
3486             for (i = 0; i < count; ++i)
3487               PUSHs(sv_2mortal(newSVnv(data[i])));
3488           }
3489           else {
3490             EXTEND(SP, 1);
3491             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3492           }
3493           myfree(data);
3494         }
3495         else {
3496           if (GIMME_V != G_ARRAY) {
3497             EXTEND(SP, 1);
3498             PUSHs(&PL_sv_undef);
3499           }
3500         }
3501
3502 int
3503 i_plinf(im, l, y, ...)
3504         Imager::ImgRaw  im
3505         int     l
3506         int     y
3507       PREINIT:
3508         i_fcolor *work;
3509         int i;
3510         STRLEN len;
3511         int count;
3512       CODE:
3513         if (items > 3) {
3514           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3515             /* supplied as a byte string */
3516             work = (i_fcolor *)SvPV(ST(3), len);
3517             count = len / sizeof(i_fcolor);
3518             if (count * sizeof(i_fcolor) != len) {
3519               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3520             }
3521             RETVAL = i_plinf(im, l, l+count, y, work);
3522           }
3523           else {
3524             work = mymalloc(sizeof(i_fcolor) * (items-3));
3525             for (i=0; i < items-3; ++i) {
3526               if (sv_isobject(ST(i+3)) 
3527                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3528                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3529                 work[i] = *INT2PTR(i_fcolor *, tmp);
3530               }
3531               else {
3532                 myfree(work);
3533                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3534               }
3535             }
3536             /**(char *)0 = 1;*/
3537             RETVAL = i_plinf(im, l, l+items-3, y, work);
3538             myfree(work);
3539           }
3540         }
3541         else {
3542           RETVAL = 0;
3543         }
3544       OUTPUT:
3545         RETVAL
3546
3547 SV *
3548 i_gpixf(im, x, y)
3549         Imager::ImgRaw im
3550         int x
3551         int y;
3552       PREINIT:
3553         i_fcolor *color;
3554       CODE:
3555         color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3556         if (i_gpixf(im, x, y, color) == 0) {
3557           RETVAL = NEWSV(0,0);
3558           sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
3559         }
3560         else {
3561           myfree(color);
3562           RETVAL = &PL_sv_undef;
3563         }
3564       OUTPUT:
3565         RETVAL
3566
3567 void
3568 i_glin(im, l, r, y)
3569         Imager::ImgRaw im
3570         int l
3571         int r
3572         int y
3573       PREINIT:
3574         i_color *vals;
3575         int count, i;
3576       PPCODE:
3577         if (l < r) {
3578           vals = mymalloc((r-l) * sizeof(i_color));
3579           memset(vals, 0, (r-l) * sizeof(i_color));
3580           count = i_glin(im, l, r, y, vals);
3581           if (GIMME_V == G_ARRAY) {
3582             EXTEND(SP, count);
3583             for (i = 0; i < count; ++i) {
3584               SV *sv;
3585               i_color *col = mymalloc(sizeof(i_color));
3586               *col = vals[i];
3587               sv = sv_newmortal();
3588               sv_setref_pv(sv, "Imager::Color", (void *)col);
3589               PUSHs(sv);
3590             }
3591           }
3592           else if (count) {
3593             EXTEND(SP, 1);
3594             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3595           }
3596           myfree(vals);
3597         }
3598
3599 void
3600 i_glinf(im, l, r, y)
3601         Imager::ImgRaw im
3602         int l
3603         int r
3604         int y
3605       PREINIT:
3606         i_fcolor *vals;
3607         int count, i;
3608         i_fcolor zero;
3609       PPCODE:
3610         for (i = 0; i < MAXCHANNELS; ++i)
3611           zero.channel[i] = 0;
3612         if (l < r) {
3613           vals = mymalloc((r-l) * sizeof(i_fcolor));
3614           for (i = 0; i < r-l; ++i)
3615             vals[i] = zero;
3616           count = i_glinf(im, l, r, y, vals);
3617           if (GIMME_V == G_ARRAY) {
3618             EXTEND(SP, count);
3619             for (i = 0; i < count; ++i) {
3620               SV *sv;
3621               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3622               *col = vals[i];
3623               sv = sv_newmortal();
3624               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3625               PUSHs(sv);
3626             }
3627           }
3628           else if (count) {
3629             EXTEND(SP, 1);
3630             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3631           }
3632           myfree(vals);
3633         }
3634
3635 Imager::ImgRaw
3636 i_img_16_new(x, y, ch)
3637         int x
3638         int y
3639         int ch
3640
3641 Imager::ImgRaw
3642 i_img_to_rgb16(im)
3643        Imager::ImgRaw im
3644
3645 Imager::ImgRaw
3646 i_img_double_new(x, y, ch)
3647         int x
3648         int y
3649         int ch
3650
3651 undef_int
3652 i_tags_addn(im, name, code, idata)
3653         Imager::ImgRaw im
3654         int     code
3655         int     idata
3656       PREINIT:
3657         char *name;
3658         STRLEN len;
3659       CODE:
3660         if (SvOK(ST(1)))
3661           name = SvPV(ST(1), len);
3662         else
3663           name = NULL;
3664         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3665       OUTPUT:
3666         RETVAL
3667
3668 undef_int
3669 i_tags_add(im, name, code, data, idata)
3670         Imager::ImgRaw  im
3671         int code
3672         int idata
3673       PREINIT:
3674         char *name;
3675         char *data;
3676         STRLEN len;
3677       CODE:
3678         if (SvOK(ST(1)))
3679           name = SvPV(ST(1), len);
3680         else
3681           name = NULL;
3682         if (SvOK(ST(3)))
3683           data = SvPV(ST(3), len);
3684         else {
3685           data = NULL;
3686           len = 0;
3687         }
3688         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3689       OUTPUT:
3690         RETVAL
3691
3692 SV *
3693 i_tags_find(im, name, start)
3694         Imager::ImgRaw  im
3695         char *name
3696         int start
3697       PREINIT:
3698         int entry;
3699       CODE:
3700         if (i_tags_find(&im->tags, name, start, &entry)) {
3701           if (entry == 0)
3702             RETVAL = newSVpv("0 but true", 0);
3703           else
3704             RETVAL = newSViv(entry);
3705         } else {
3706           RETVAL = &PL_sv_undef;
3707         }
3708       OUTPUT:
3709         RETVAL
3710
3711 SV *
3712 i_tags_findn(im, code, start)
3713         Imager::ImgRaw  im
3714         int             code
3715         int             start
3716       PREINIT:
3717         int entry;
3718       CODE:
3719         if (i_tags_findn(&im->tags, code, start, &entry)) {
3720           if (entry == 0)
3721             RETVAL = newSVpv("0 but true", 0);
3722           else
3723             RETVAL = newSViv(entry);
3724         }
3725         else {
3726           RETVAL = &PL_sv_undef;
3727         }
3728       OUTPUT:
3729         RETVAL
3730
3731 int
3732 i_tags_delete(im, entry)
3733         Imager::ImgRaw  im
3734         int             entry
3735       CODE:
3736         RETVAL = i_tags_delete(&im->tags, entry);
3737       OUTPUT:
3738         RETVAL
3739
3740 int
3741 i_tags_delbyname(im, name)
3742         Imager::ImgRaw  im
3743         char *          name
3744       CODE:
3745         RETVAL = i_tags_delbyname(&im->tags, name);
3746       OUTPUT:
3747         RETVAL
3748
3749 int
3750 i_tags_delbycode(im, code)
3751         Imager::ImgRaw  im
3752         int             code
3753       CODE:
3754         RETVAL = i_tags_delbycode(&im->tags, code);
3755       OUTPUT:
3756         RETVAL
3757
3758 void
3759 i_tags_get(im, index)
3760         Imager::ImgRaw  im
3761         int             index
3762       PPCODE:
3763         if (index >= 0 && index < im->tags.count) {
3764           i_img_tag *entry = im->tags.tags + index;
3765           EXTEND(SP, 5);
3766         
3767           if (entry->name) {
3768             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3769           }
3770           else {
3771             PUSHs(sv_2mortal(newSViv(entry->code)));
3772           }
3773           if (entry->data) {
3774             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3775           }
3776           else {
3777             PUSHs(sv_2mortal(newSViv(entry->idata)));
3778           }
3779         }
3780
3781 void
3782 i_tags_get_string(im, what_sv)
3783         Imager::ImgRaw  im
3784         SV *what_sv
3785       PREINIT:
3786         char const *name = NULL;
3787         int code;
3788         char buffer[200];
3789       PPCODE:
3790         if (SvIOK(what_sv)) {
3791           code = SvIV(what_sv);
3792           name = NULL;
3793         }
3794         else {
3795           name = SvPV_nolen(what_sv);
3796           code = 0;
3797         }
3798         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
3799           EXTEND(SP, 1);
3800           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
3801         }
3802
3803 int
3804 i_tags_count(im)
3805         Imager::ImgRaw  im
3806       CODE:
3807         RETVAL = im->tags.count;
3808       OUTPUT:
3809         RETVAL
3810
3811 #ifdef HAVE_WIN32
3812
3813 void
3814 i_wf_bbox(face, size, text_sv, utf8=0)
3815         char *face
3816         int size
3817         SV *text_sv
3818         int utf8
3819       PREINIT:
3820         int cords[BOUNDING_BOX_COUNT];
3821         int rc, i;
3822         char const *text;
3823          STRLEN text_len;
3824       PPCODE:
3825         text = SvPV(text_sv, text_len);
3826 #ifdef SvUTF8
3827         if (SvUTF8(text_sv))
3828           utf8 = 1;
3829 #endif
3830         if (rc = i_wf_bbox(face, size, text, text_len, cords, utf8)) {
3831           EXTEND(SP, rc);  
3832           for (i = 0; i < rc; ++i) 
3833             PUSHs(sv_2mortal(newSViv(cords[i])));
3834         }
3835
3836 undef_int
3837 i_wf_text(face, im, tx, ty, cl, size, text_sv, align, aa, utf8 = 0)
3838         char *face
3839         Imager::ImgRaw im
3840         int tx
3841         int ty
3842         Imager::Color cl
3843         int size
3844         SV *text_sv
3845         int align
3846         int aa
3847         int utf8
3848       PREINIT:
3849         char const *text;
3850         STRLEN text_len;
3851       CODE:
3852         text = SvPV(text_sv, text_len);
3853 #ifdef SvUTF8
3854         if (SvUTF8(text_sv))
3855           utf8 = 1;
3856 #endif
3857         RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, text_len, 
3858                            align, aa, utf8);
3859       OUTPUT:
3860         RETVAL
3861
3862 undef_int
3863 i_wf_cp(face, im, tx, ty, channel, size, text_sv, align, aa, utf8 = 0)
3864         char *face
3865         Imager::ImgRaw im
3866         int tx
3867         int ty
3868         int channel
3869         int size
3870         SV *text_sv
3871         int align
3872         int aa
3873         int utf8
3874       PREINIT:
3875         char const *text;
3876         STRLEN text_len;
3877       CODE:
3878         text = SvPV(text_sv, text_len);
3879 #ifdef SvUTF8
3880         if (SvUTF8(text_sv))
3881           utf8 = 1;
3882 #endif
3883         RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, text_len, 
3884                          align, aa, utf8);
3885       OUTPUT:
3886         RETVAL
3887
3888 undef_int
3889 i_wf_addfont(font)
3890         char *font
3891
3892 undef_int
3893 i_wf_delfont(font)
3894         char *font
3895
3896 #endif
3897
3898 #ifdef HAVE_FT2
3899
3900 MODULE = Imager         PACKAGE = Imager::Font::FT2     PREFIX=FT2_
3901
3902 #define FT2_DESTROY(font) i_ft2_destroy(font)
3903
3904 void
3905 FT2_DESTROY(font)
3906         Imager::Font::FT2 font
3907
3908 int
3909 FT2_CLONE_SKIP(...)
3910     CODE:
3911         RETVAL = 1;
3912     OUTPUT:
3913         RETVAL
3914
3915 MODULE = Imager         PACKAGE = Imager::Font::FreeType2 
3916
3917 Imager::Font::FT2
3918 i_ft2_new(name, index)
3919         char *name
3920         int index
3921
3922 undef_int
3923 i_ft2_setdpi(font, xdpi, ydpi)
3924         Imager::Font::FT2 font
3925         int xdpi
3926         int ydpi
3927
3928 void
3929 i_ft2_getdpi(font)
3930         Imager::Font::FT2 font
3931       PREINIT:
3932         int xdpi, ydpi;
3933       CODE:
3934         if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
3935           EXTEND(SP, 2);
3936           PUSHs(sv_2mortal(newSViv(xdpi)));
3937           PUSHs(sv_2mortal(newSViv(ydpi)));
3938         }
3939
3940 undef_int
3941 i_ft2_sethinting(font, hinting)
3942         Imager::Font::FT2 font
3943         int hinting
3944
3945 undef_int
3946 i_ft2_settransform(font, matrix)
3947         Imager::Font::FT2 font
3948       PREINIT:
3949         double matrix[6];
3950         int len;
3951         AV *av;
3952         SV *sv1;
3953         int i;
3954       CODE:
3955         if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
3956           croak("i_ft2_settransform: parameter 2 must be an array ref\n");
3957         av=(AV*)SvRV(ST(1));
3958         len=av_len(av)+1;
3959         if (len > 6)
3960           len = 6;
3961         for (i = 0; i < len; ++i) {
3962           sv1=(*(av_fetch(av,i,0)));
3963           matrix[i] = SvNV(sv1);
3964         }
3965         for (; i < 6; ++i)
3966           matrix[i] = 0;
3967         RETVAL = i_ft2_settransform(font, matrix);
3968       OUTPUT:
3969         RETVAL
3970
3971 void
3972 i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
3973         Imager::Font::FT2 font
3974         double cheight
3975         double cwidth
3976         SV *text_sv
3977         int utf8
3978       PREINIT:
3979         int bbox[BOUNDING_BOX_COUNT];
3980         int i;
3981         char *text;
3982         STRLEN text_len;
3983         int rc;
3984       PPCODE:
3985         text = SvPV(text_sv, text_len);
3986 #ifdef SvUTF8
3987         if (SvUTF8(text_sv))
3988           utf8 = 1;
3989 #endif
3990         rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8);
3991         if (rc) {
3992           EXTEND(SP, rc);
3993           for (i = 0; i < rc; ++i)
3994             PUSHs(sv_2mortal(newSViv(bbox[i])));
3995         }
3996
3997 void
3998 i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
3999         Imager::Font::FT2 font
4000         double cheight
4001         double cwidth
4002         char *text
4003         int vlayout
4004         int utf8
4005       PREINIT:
4006         int bbox[8];
4007         int i;
4008       PPCODE:
4009 #ifdef SvUTF8
4010         if (SvUTF8(ST(3)))
4011           utf8 = 1;
4012 #endif
4013         if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
4014                          utf8, bbox)) {
4015           EXTEND(SP, 8);
4016           for (i = 0; i < 8; ++i)
4017             PUSHs(sv_2mortal(newSViv(bbox[i])));
4018         }
4019
4020 undef_int
4021 i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
4022         Imager::Font::FT2 font
4023         Imager::ImgRaw im
4024         int tx
4025         int ty
4026         Imager::Color cl
4027         double cheight
4028         double cwidth
4029         int align
4030         int aa
4031         int vlayout
4032         int utf8
4033       PREINIT:
4034         char *text;
4035         STRLEN len;
4036       CODE:
4037 #ifdef SvUTF8
4038         if (SvUTF8(ST(7))) {
4039           utf8 = 1;
4040         }
4041 #endif
4042         text = SvPV(ST(7), len);
4043         RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
4044                             len, align, aa, vlayout, utf8);
4045       OUTPUT:
4046         RETVAL
4047
4048 undef_int
4049 i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text_sv, align, aa, vlayout, utf8)
4050         Imager::Font::FT2 font
4051         Imager::ImgRaw im
4052         int tx
4053         int ty
4054         int channel
4055         double cheight
4056         double cwidth
4057         SV *text_sv
4058         int align
4059         int aa
4060         int vlayout
4061         int utf8
4062       PREINIT:
4063         char const *text;
4064         STRLEN len;
4065       CODE:
4066 #ifdef SvUTF8
4067         if (SvUTF8(ST(7)))
4068           utf8 = 1;
4069 #endif
4070         text = SvPV(text_sv, len);
4071         RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
4072                           len, align, aa, vlayout, 1);
4073       OUTPUT:
4074         RETVAL
4075
4076 void
4077 ft2_transform_box(font, x0, x1, x2, x3)
4078         Imager::Font::FT2 font
4079         int x0
4080         int x1
4081         int x2
4082         int x3
4083       PREINIT:
4084         int box[4];
4085       PPCODE:
4086         box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
4087         ft2_transform_box(font, box);
4088           EXTEND(SP, 4);
4089           PUSHs(sv_2mortal(newSViv(box[0])));
4090           PUSHs(sv_2mortal(newSViv(box[1])));
4091           PUSHs(sv_2mortal(newSViv(box[2])));
4092           PUSHs(sv_2mortal(newSViv(box[3])));
4093
4094 void
4095 i_ft2_has_chars(handle, text_sv, utf8)
4096         Imager::Font::FT2 handle
4097         SV  *text_sv
4098         int utf8
4099       PREINIT:
4100         char *text;
4101         STRLEN len;
4102         char *work;
4103         int count;
4104         int i;
4105       PPCODE:
4106 #ifdef SvUTF8
4107         if (SvUTF8(text_sv))
4108           utf8 = 1;
4109 #endif
4110         text = SvPV(text_sv, len);
4111         work = mymalloc(len);
4112         count = i_ft2_has_chars(handle, text, len, utf8, work);
4113         if (GIMME_V == G_ARRAY) {
4114           EXTEND(SP, count);
4115           for (i = 0; i < count; ++i) {
4116             PUSHs(sv_2mortal(newSViv(work[i])));
4117           }
4118         }
4119         else {
4120           EXTEND(SP, 1);
4121           PUSHs(sv_2mortal(newSVpv(work, count)));
4122         }
4123         myfree(work);
4124
4125 void
4126 i_ft2_face_name(handle)
4127         Imager::Font::FT2 handle
4128       PREINIT:
4129         char name[255];
4130         int len;
4131       PPCODE:
4132         len = i_ft2_face_name(handle, name, sizeof(name));
4133         if (len) {
4134           EXTEND(SP, 1);
4135           PUSHs(sv_2mortal(newSVpv(name, 0)));
4136         }
4137
4138 undef_int
4139 i_ft2_can_face_name()
4140
4141 void
4142 i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
4143         Imager::Font::FT2 handle
4144         SV *text_sv
4145         int utf8
4146         int reliable_only
4147       PREINIT:
4148         char const *text;
4149         STRLEN work_len;
4150         int len;
4151         char name[255];
4152       PPCODE:
4153 #ifdef SvUTF8
4154         if (SvUTF8(text_sv))
4155           utf8 = 1;
4156 #endif
4157         text = SvPV(text_sv, work_len);
4158         len = work_len;
4159         while (len) {
4160           unsigned long ch;
4161           if (utf8) {
4162             ch = i_utf8_advance(&text, &len);
4163             if (ch == ~0UL) {
4164               i_push_error(0, "invalid UTF8 character");
4165               break;
4166             }
4167           }
4168           else {
4169             ch = *text++;
4170             --len;
4171           }
4172           EXTEND(SP, 1);
4173           if (i_ft2_glyph_name(handle, ch, name, sizeof(name), 
4174                                          reliable_only)) {
4175             PUSHs(sv_2mortal(newSVpv(name, 0)));
4176           }
4177           else {
4178             PUSHs(&PL_sv_undef);
4179           } 
4180         }
4181
4182 int
4183 i_ft2_can_do_glyph_names()
4184
4185 int
4186 i_ft2_face_has_glyph_names(handle)
4187         Imager::Font::FT2 handle
4188
4189 int
4190 i_ft2_is_multiple_master(handle)
4191         Imager::Font::FT2 handle
4192
4193 void
4194 i_ft2_get_multiple_masters(handle)
4195         Imager::Font::FT2 handle
4196       PREINIT:
4197         i_font_mm mm;
4198         int i;
4199       PPCODE:
4200         if (i_ft2_get_multiple_masters(handle, &mm)) {
4201           EXTEND(SP, 2+mm.num_axis);
4202           PUSHs(sv_2mortal(newSViv(mm.num_axis)));
4203           PUSHs(sv_2mortal(newSViv(mm.num_designs)));
4204           for (i = 0; i < mm.num_axis; ++i) {
4205             AV *av = newAV();
4206             SV *sv;
4207             av_extend(av, 3);
4208             sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name));
4209             SvREFCNT_inc(sv);
4210             av_store(av, 0, sv);
4211             sv = newSViv(mm.axis[i].minimum);
4212             SvREFCNT_inc(sv);
4213             av_store(av, 1, sv);
4214             sv = newSViv(mm.axis[i].maximum);
4215             SvREFCNT_inc(sv);
4216             av_store(av, 2, sv);
4217             PUSHs(newRV_noinc((SV *)av));
4218           }
4219         }
4220
4221 undef_int
4222 i_ft2_set_mm_coords(handle, ...)
4223         Imager::Font::FT2 handle
4224       PROTOTYPE: DISABLE
4225       PREINIT:
4226         long *coords;
4227         int ix_coords, i;
4228       CODE:
4229         /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so
4230            transfer the array manually */
4231         ix_coords = items-1;
4232         coords = mymalloc(sizeof(long) * ix_coords);
4233         for (i = 0; i < ix_coords; ++i) {
4234           coords[i] = (long)SvIV(ST(1+i));
4235         }
4236         RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords);
4237         myfree(coords);
4238       OUTPUT:
4239         RETVAL
4240
4241 #endif
4242
4243 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
4244
4245 void
4246 IFILL_DESTROY(fill)
4247         Imager::FillHandle fill
4248
4249 int
4250 IFILL_CLONE_SKIP(...)
4251     CODE:
4252         RETVAL = 1;
4253     OUTPUT:
4254         RETVAL
4255
4256 MODULE = Imager         PACKAGE = Imager
4257
4258 Imager::FillHandle
4259 i_new_fill_solid(cl, combine)
4260         Imager::Color cl
4261         int combine
4262
4263 Imager::FillHandle
4264 i_new_fill_solidf(cl, combine)
4265         Imager::Color::Float cl
4266         int combine
4267
4268 Imager::FillHandle
4269 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
4270         Imager::Color fg
4271         Imager::Color bg
4272         int combine
4273         int hatch
4274         int dx
4275         int dy
4276       PREINIT:
4277         unsigned char *cust_hatch;
4278         STRLEN len;
4279       CODE:
4280         if (SvOK(ST(4))) {
4281           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4282         }
4283         else
4284           cust_hatch = NULL;
4285         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
4286       OUTPUT:
4287         RETVAL
4288
4289 Imager::FillHandle
4290 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
4291         Imager::Color::Float fg
4292         Imager::Color::Float bg
4293         int combine
4294         int hatch
4295         int dx
4296         int dy
4297       PREINIT:
4298         unsigned char *cust_hatch;
4299         STRLEN len;
4300       CODE:
4301         if (SvOK(ST(4))) {
4302           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4303         }
4304         else
4305           cust_hatch = NULL;
4306         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
4307       OUTPUT:
4308         RETVAL
4309
4310 Imager::FillHandle
4311 i_new_fill_image(src, matrix, xoff, yoff, combine)
4312         Imager::ImgRaw src
4313         int xoff
4314         int yoff
4315         int combine
4316       PREINIT:
4317         double matrix[9];
4318         double *matrixp;
4319         AV *av;
4320         IV len;
4321         SV *sv1;
4322         int i;
4323       CODE:
4324         if (!SvOK(ST(1))) {
4325           matrixp = NULL;
4326         }
4327         else {
4328           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4329             croak("i_new_fill_image: parameter must be an arrayref");
4330           av=(AV*)SvRV(ST(1));
4331           len=av_len(av)+1;
4332           if (len > 9)
4333             len = 9;
4334           for (i = 0; i < len; ++i) {
4335             sv1=(*(av_fetch(av,i,0)));
4336             matrix[i] = SvNV(sv1);
4337           }
4338           for (; i < 9; ++i)
4339             matrix[i] = 0;
4340           matrixp = matrix;
4341         }
4342         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4343       OUTPUT:
4344         RETVAL
4345
4346 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
4347
4348 # this class is only exposed for testing
4349
4350 int
4351 i_int_hlines_testing()
4352
4353 #if i_int_hlines_testing()
4354
4355 Imager::Internal::Hlines
4356 i_int_hlines_new(start_y, count_y, start_x, count_x)
4357         int start_y
4358         int count_y
4359         int start_x
4360         int count_x
4361
4362 Imager::Internal::Hlines
4363 i_int_hlines_new_img(im)
4364         Imager::ImgRaw im
4365
4366 void
4367 i_int_hlines_add(hlines, y, minx, width)
4368         Imager::Internal::Hlines hlines
4369         int y
4370         int minx
4371         int width
4372
4373 void
4374 i_int_hlines_DESTROY(hlines)
4375         Imager::Internal::Hlines hlines
4376
4377 SV *
4378 i_int_hlines_dump(hlines)
4379         Imager::Internal::Hlines hlines
4380
4381 int
4382 i_int_hlines_CLONE_SKIP(cls)
4383         SV *cls
4384
4385 #endif
4386
4387 BOOT:
4388         PERL_SET_GLOBAL_CALLBACKS;
4389         PERL_PL_SET_GLOBAL_CALLBACKS;