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