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