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