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