]> git.imager.perl.org - imager.git/blob - Imager.xs
963277ad227f9a8916372675a059e3b509d70261
[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 i_get_anonymous_color_histo(im, maxc = 0x40000000)
2977    Imager::ImgRaw  im
2978    int maxc
2979     PREINIT:
2980         int i;
2981         unsigned int * col_usage = NULL;
2982         int col_cnt;
2983     PPCODE:
2984         col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc);
2985         EXTEND(SP, col_cnt);
2986         for (i = 0; i < col_cnt; i++)  {
2987             PUSHs(sv_2mortal(newSViv( col_usage[i])));
2988         }
2989         myfree(col_usage);
2990         XSRETURN(col_cnt);
2991
2992
2993 Imager::ImgRaw
2994 i_transform(im,opx,opy,parm)
2995     Imager::ImgRaw     im
2996              PREINIT:
2997              double* parm;
2998              int*    opx;
2999              int*    opy;
3000              int     opxl;
3001              int     opyl;
3002              int     parmlen;
3003              AV* av;
3004              SV* sv1;
3005              int i;
3006              CODE:
3007              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
3008              if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n");
3009              if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n");
3010              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
3011              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n");
3012              if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n");
3013              av=(AV*)SvRV(ST(1));
3014              opxl=av_len(av)+1;
3015              opx=mymalloc( opxl*sizeof(int) );
3016              for(i=0;i<opxl;i++) {
3017                sv1=(*(av_fetch(av,i,0)));
3018                opx[i]=(int)SvIV(sv1);
3019              }
3020              av=(AV*)SvRV(ST(2));
3021              opyl=av_len(av)+1;
3022              opy=mymalloc( opyl*sizeof(int) );
3023              for(i=0;i<opyl;i++) {
3024                sv1=(*(av_fetch(av,i,0)));
3025                opy[i]=(int)SvIV(sv1);
3026              }
3027              av=(AV*)SvRV(ST(3));
3028              parmlen=av_len(av)+1;
3029              parm=mymalloc( parmlen*sizeof(double) );
3030              for(i=0;i<parmlen;i++) { /* FIXME: Bug? */
3031                sv1=(*(av_fetch(av,i,0)));
3032                parm[i]=(double)SvNV(sv1);
3033              }
3034              RETVAL=i_transform(im,opx,opxl,opy,opyl,parm,parmlen);
3035              myfree(parm);
3036              myfree(opy);
3037              myfree(opx);
3038              ST(0) = sv_newmortal();
3039              if (RETVAL == 0) ST(0)=&PL_sv_undef;
3040              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
3041
3042 Imager::ImgRaw
3043 i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
3044         SV *sv_width
3045         SV *sv_height
3046         SV *sv_ops
3047         AV *av_n_regs
3048         AV *av_c_regs
3049         AV *av_in_imgs
3050         int channels
3051              PREINIT:
3052              int width;
3053              int height;
3054              struct rm_op *ops;
3055              STRLEN ops_len;
3056              int ops_count;
3057              double *n_regs;
3058              int n_regs_count;
3059              i_color *c_regs;
3060              int c_regs_count;
3061              int in_imgs_count;
3062              i_img **in_imgs;
3063              SV *sv1;
3064              IV tmp;
3065              int i;
3066              CODE:
3067
3068              in_imgs_count = av_len(av_in_imgs)+1;
3069              for (i = 0; i < in_imgs_count; ++i) {
3070                sv1 = *av_fetch(av_in_imgs, i, 0);
3071                if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
3072                  croak("sv_in_img must contain only images");
3073                }
3074              }
3075              if (in_imgs_count > 0) {
3076                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
3077                for (i = 0; i < in_imgs_count; ++i) {              
3078                  sv1 = *av_fetch(av_in_imgs,i,0);
3079                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
3080                    croak("Parameter 5 must contain only images");
3081                  }
3082                  tmp = SvIV((SV*)SvRV(sv1));
3083                  in_imgs[i] = INT2PTR(i_img*, tmp);
3084                }
3085              }
3086              else {
3087                /* no input images */
3088                in_imgs = NULL;
3089              }
3090              /* default the output size from the first input if possible */
3091              if (SvOK(sv_width))
3092                width = SvIV(sv_width);
3093              else if (in_imgs_count)
3094                width = in_imgs[0]->xsize;
3095              else
3096                croak("No output image width supplied");
3097
3098              if (SvOK(sv_height))
3099                height = SvIV(sv_height);
3100              else if (in_imgs_count)
3101                height = in_imgs[0]->ysize;
3102              else
3103                croak("No output image height supplied");
3104
3105              ops = (struct rm_op *)SvPV(sv_ops, ops_len);
3106              if (ops_len % sizeof(struct rm_op))
3107                  croak("Imager: Parameter 3 must be a bitmap of regops\n");
3108              ops_count = ops_len / sizeof(struct rm_op);
3109
3110              n_regs_count = av_len(av_n_regs)+1;
3111              n_regs = mymalloc(n_regs_count * sizeof(double));
3112              for (i = 0; i < n_regs_count; ++i) {
3113                sv1 = *av_fetch(av_n_regs,i,0);
3114                if (SvOK(sv1))
3115                  n_regs[i] = SvNV(sv1);
3116              }
3117              c_regs_count = av_len(av_c_regs)+1;
3118              c_regs = mymalloc(c_regs_count * sizeof(i_color));
3119              /* I don't bother initializing the colou?r registers */
3120
3121              RETVAL=i_transform2(width, height, channels, ops, ops_count, 
3122                                  n_regs, n_regs_count, 
3123                                  c_regs, c_regs_count, in_imgs, in_imgs_count);
3124              if (in_imgs)
3125                  myfree(in_imgs);
3126              myfree(n_regs);
3127              myfree(c_regs);
3128              ST(0) = sv_newmortal();
3129              if (RETVAL == 0) ST(0)=&PL_sv_undef;
3130              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
3131
3132
3133 void
3134 i_contrast(im,intensity)
3135     Imager::ImgRaw     im
3136              float     intensity
3137
3138 void
3139 i_hardinvert(im)
3140     Imager::ImgRaw     im
3141
3142 void
3143 i_noise(im,amount,type)
3144     Imager::ImgRaw     im
3145              float     amount
3146      unsigned char     type
3147
3148 void
3149 i_bumpmap(im,bump,channel,light_x,light_y,strength)
3150     Imager::ImgRaw     im
3151     Imager::ImgRaw     bump
3152                int     channel
3153                int     light_x
3154                int     light_y
3155                int     strength
3156
3157
3158 void
3159 i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
3160     Imager::ImgRaw     im
3161     Imager::ImgRaw     bump
3162                int     channel
3163                int     tx
3164                int     ty
3165              float     Lx
3166              float     Ly
3167              float     Lz
3168              float     cd
3169              float     cs
3170              float     n
3171      Imager::Color     Ia
3172      Imager::Color     Il
3173      Imager::Color     Is
3174
3175
3176
3177 void
3178 i_postlevels(im,levels)
3179     Imager::ImgRaw     im
3180              int       levels
3181
3182 void
3183 i_mosaic(im,size)
3184     Imager::ImgRaw     im
3185                int     size
3186
3187 void
3188 i_watermark(im,wmark,tx,ty,pixdiff)
3189     Imager::ImgRaw     im
3190     Imager::ImgRaw     wmark
3191                int     tx
3192                int     ty
3193                int     pixdiff
3194
3195
3196 void
3197 i_autolevels(im,lsat,usat,skew)
3198     Imager::ImgRaw     im
3199              float     lsat
3200              float     usat
3201              float     skew
3202
3203 void
3204 i_radnoise(im,xo,yo,rscale,ascale)
3205     Imager::ImgRaw     im
3206              float     xo
3207              float     yo
3208              float     rscale
3209              float     ascale
3210
3211 void
3212 i_turbnoise(im, xo, yo, scale)
3213     Imager::ImgRaw     im
3214              float     xo
3215              float     yo
3216              float     scale
3217
3218
3219 void
3220 i_gradgen(im, ...)
3221     Imager::ImgRaw     im
3222       PREINIT:
3223         int num;
3224         int *xo;
3225         int *yo;
3226         i_color *ival;
3227         int dmeasure;
3228         int i;
3229         SV *sv;
3230         AV *axx;
3231         AV *ayy;
3232         AV *ac;
3233       CODE:
3234         if (items != 5)
3235             croak("Usage: i_gradgen(im, xo, yo, ival, dmeasure)");
3236         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3237             croak("i_gradgen: Second argument must be an array ref");
3238         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
3239             croak("i_gradgen: Third argument must be an array ref");
3240         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
3241             croak("i_gradgen: Fourth argument must be an array ref");
3242         axx = (AV *)SvRV(ST(1));
3243         ayy = (AV *)SvRV(ST(2));
3244         ac  = (AV *)SvRV(ST(3));
3245         dmeasure = (int)SvIV(ST(4));
3246         
3247         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
3248         num = num <= av_len(ac) ? num : av_len(ac);
3249         num++; 
3250         if (num < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each");
3251         xo = mymalloc( sizeof(int) * num );
3252         yo = mymalloc( sizeof(int) * num );
3253         ival = mymalloc( sizeof(i_color) * num );
3254         for(i = 0; i<num; i++) {
3255           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
3256           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
3257           sv = *av_fetch(ac, i, 0);
3258           if ( !sv_derived_from(sv, "Imager::Color") ) {
3259             free(axx); free(ayy); free(ac);
3260             croak("i_gradgen: Element of fourth argument is not derived from Imager::Color");
3261           }
3262           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
3263         }
3264         i_gradgen(im, num, xo, yo, ival, dmeasure);
3265         myfree(xo);
3266         myfree(yo);
3267         myfree(ival);
3268
3269 Imager::ImgRaw
3270 i_diff_image(im, im2, mindist=0)
3271     Imager::ImgRaw     im
3272     Imager::ImgRaw     im2
3273             double     mindist
3274
3275 undef_int
3276 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
3277     Imager::ImgRaw     im
3278             double     xa
3279             double     ya
3280             double     xb
3281             double     yb
3282                int     type
3283                int     repeat
3284                int     combine
3285                int     super_sample
3286             double     ssample_param
3287       PREINIT:
3288         AV *asegs;
3289         int count;
3290         i_fountain_seg *segs;
3291       CODE:
3292         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
3293             croak("i_fountain: argument 11 must be an array ref");
3294         
3295         asegs = (AV *)SvRV(ST(10));
3296         segs = load_fount_segs(asegs, &count);
3297         RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, 
3298                             super_sample, ssample_param, count, segs);
3299         myfree(segs);
3300       OUTPUT:
3301         RETVAL
3302
3303 Imager::FillHandle
3304 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
3305             double     xa
3306             double     ya
3307             double     xb
3308             double     yb
3309                int     type
3310                int     repeat
3311                int     combine
3312                int     super_sample
3313             double     ssample_param
3314       PREINIT:
3315         AV *asegs;
3316         int count;
3317         i_fountain_seg *segs;
3318       CODE:
3319         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
3320             croak("i_fountain: argument 11 must be an array ref");
3321         
3322         asegs = (AV *)SvRV(ST(9));
3323         segs = load_fount_segs(asegs, &count);
3324         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
3325                                   super_sample, ssample_param, count, segs);
3326         myfree(segs);        
3327       OUTPUT:
3328         RETVAL
3329
3330 void
3331 i_errors()
3332       PREINIT:
3333         i_errmsg *errors;
3334         int i;
3335         AV *av;
3336         SV *sv;
3337       PPCODE:
3338         errors = i_errors();
3339         i = 0;
3340         while (errors[i].msg) {
3341           av = newAV();
3342           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
3343           if (!av_store(av, 0, sv)) {
3344             SvREFCNT_dec(sv);
3345           }
3346           sv = newSViv(errors[i].code);
3347           if (!av_store(av, 1, sv)) {
3348             SvREFCNT_dec(sv);
3349           }
3350           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
3351           ++i;
3352         }
3353
3354 void
3355 i_clear_error()
3356
3357 void
3358 i_push_error(code, msg)
3359         int code
3360         const char *msg
3361
3362 undef_int
3363 i_nearest_color(im, ...)
3364     Imager::ImgRaw     im
3365       PREINIT:
3366         int num;
3367         int *xo;
3368         int *yo;
3369         i_color *ival;
3370         int dmeasure;
3371         int i;
3372         SV *sv;
3373         AV *axx;
3374         AV *ayy;
3375         AV *ac;
3376       CODE:
3377         if (items != 5)
3378             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
3379         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3380             croak("i_nearest_color: Second argument must be an array ref");
3381         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
3382             croak("i_nearest_color: Third argument must be an array ref");
3383         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
3384             croak("i_nearest_color: Fourth argument must be an array ref");
3385         axx = (AV *)SvRV(ST(1));
3386         ayy = (AV *)SvRV(ST(2));
3387         ac  = (AV *)SvRV(ST(3));
3388         dmeasure = (int)SvIV(ST(4));
3389         
3390         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
3391         num = num <= av_len(ac) ? num : av_len(ac);
3392         num++; 
3393         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
3394         xo = mymalloc( sizeof(int) * num );
3395         yo = mymalloc( sizeof(int) * num );
3396         ival = mymalloc( sizeof(i_color) * num );
3397         for(i = 0; i<num; i++) {
3398           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
3399           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
3400           sv = *av_fetch(ac, i, 0);
3401           if ( !sv_derived_from(sv, "Imager::Color") ) {
3402             free(axx); free(ayy); free(ac);
3403             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
3404           }
3405           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
3406         }
3407         RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
3408       OUTPUT:
3409         RETVAL
3410
3411 void
3412 malloc_state()
3413
3414 void
3415 DSO_open(filename)
3416              char*       filename
3417              PREINIT:
3418                void *rc;
3419                char *evstr;
3420              PPCODE:
3421                rc=DSO_open(filename,&evstr);
3422                if (rc!=NULL) {
3423                  if (evstr!=NULL) {
3424                    EXTEND(SP,2); 
3425                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3426                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
3427                  } else {
3428                    EXTEND(SP,1);
3429                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3430                  }
3431                }
3432
3433
3434 undef_int
3435 DSO_close(dso_handle)
3436              void*       dso_handle
3437
3438 void
3439 DSO_funclist(dso_handle_v)
3440              void*       dso_handle_v
3441              PREINIT:
3442                int i;
3443                DSO_handle *dso_handle;
3444              PPCODE:
3445                dso_handle=(DSO_handle*)dso_handle_v;
3446                i=0;
3447                while( dso_handle->function_list[i].name != NULL) {
3448                  EXTEND(SP,1);
3449                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i].name,0)));
3450                  EXTEND(SP,1);
3451                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i++].pcode,0)));
3452                }
3453
3454
3455 void
3456 DSO_call(handle,func_index,hv)
3457                void*  handle
3458                int    func_index
3459              PREINIT:
3460                HV* hv;
3461              PPCODE:
3462                if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
3463                hv=(HV*)SvRV(ST(2));
3464                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
3465                DSO_call( (DSO_handle *)handle,func_index,hv);
3466
3467
3468
3469 SV *
3470 i_get_pixel(im, x, y)
3471         Imager::ImgRaw im
3472         int x
3473         int y;
3474       PREINIT:
3475         i_color *color;
3476       CODE:
3477         color = (i_color *)mymalloc(sizeof(i_color));
3478         if (i_gpix(im, x, y, color) == 0) {
3479           RETVAL = NEWSV(0, 0);
3480           sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
3481         }
3482         else {
3483           myfree(color);
3484           RETVAL = &PL_sv_undef;
3485         }
3486       OUTPUT:
3487         RETVAL
3488         
3489
3490 int
3491 i_ppix(im, x, y, cl)
3492         Imager::ImgRaw im
3493         int x
3494         int y
3495         Imager::Color cl
3496
3497 Imager::ImgRaw
3498 i_img_pal_new(x, y, channels, maxpal)
3499         int     x
3500         int     y
3501         int     channels
3502         int     maxpal
3503
3504 Imager::ImgRaw
3505 i_img_to_pal(src, quant)
3506         Imager::ImgRaw src
3507       PREINIT:
3508         HV *hv;
3509         i_quantize quant;
3510       CODE:
3511         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3512           croak("i_img_to_pal: second argument must be a hash ref");
3513         hv = (HV *)SvRV(ST(1));
3514         memset(&quant, 0, sizeof(quant));
3515         quant.mc_size = 256;
3516         handle_quant_opts(&quant, hv);
3517         RETVAL = i_img_to_pal(src, &quant);
3518         if (RETVAL) {
3519           copy_colors_back(hv, &quant);
3520         }
3521         cleanup_quant_opts(&quant);
3522       OUTPUT:
3523         RETVAL
3524
3525 Imager::ImgRaw
3526 i_img_to_rgb(src)
3527         Imager::ImgRaw src
3528
3529 void
3530 i_gpal(im, l, r, y)
3531         Imager::ImgRaw  im
3532         int     l
3533         int     r
3534         int     y
3535       PREINIT:
3536         i_palidx *work;
3537         int count, i;
3538       PPCODE:
3539         if (l < r) {
3540           work = mymalloc((r-l) * sizeof(i_palidx));
3541           count = i_gpal(im, l, r, y, work);
3542           if (GIMME_V == G_ARRAY) {
3543             EXTEND(SP, count);
3544             for (i = 0; i < count; ++i) {
3545               PUSHs(sv_2mortal(newSViv(work[i])));
3546             }
3547           }
3548           else {
3549             EXTEND(SP, 1);
3550             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3551           }
3552           myfree(work);
3553         }
3554         else {
3555           if (GIMME_V != G_ARRAY) {
3556             EXTEND(SP, 1);
3557             PUSHs(&PL_sv_undef);
3558           }
3559         }
3560
3561 int
3562 i_ppal(im, l, y, ...)
3563         Imager::ImgRaw  im
3564         int     l
3565         int     y
3566       PREINIT:
3567         i_palidx *work;
3568         int i;
3569       CODE:
3570         if (items > 3) {
3571           work = mymalloc(sizeof(i_palidx) * (items-3));
3572           for (i=0; i < items-3; ++i) {
3573             work[i] = SvIV(ST(i+3));
3574           }
3575           validate_i_ppal(im, work, items - 3);
3576           RETVAL = i_ppal(im, l, l+items-3, y, work);
3577           myfree(work);
3578         }
3579         else {
3580           RETVAL = 0;
3581         }
3582       OUTPUT:
3583         RETVAL
3584
3585 int
3586 i_ppal_p(im, l, y, data)
3587         Imager::ImgRaw  im
3588         int     l
3589         int     y
3590         SV *data
3591       PREINIT:
3592         i_palidx const *work;
3593         STRLEN len;
3594       CODE:
3595         work = (i_palidx const *)SvPV(data, len);
3596         len /= sizeof(i_palidx);
3597         if (len > 0) {
3598           validate_i_ppal(im, work, len);
3599           RETVAL = i_ppal(im, l, l+len, y, work);
3600         }
3601         else {
3602           RETVAL = 0;
3603         }
3604       OUTPUT:
3605         RETVAL
3606
3607 SV *
3608 i_addcolors(im, ...)
3609         Imager::ImgRaw  im
3610       PREINIT:
3611         int index;
3612         i_color *colors;
3613         int i;
3614       CODE:
3615         if (items < 2)
3616           croak("i_addcolors: no colors to add");
3617         colors = mymalloc((items-1) * sizeof(i_color));
3618         for (i=0; i < items-1; ++i) {
3619           if (sv_isobject(ST(i+1)) 
3620               && sv_derived_from(ST(i+1), "Imager::Color")) {
3621             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3622             colors[i] = *INT2PTR(i_color *, tmp);
3623           }
3624           else {
3625             myfree(colors);
3626             croak("i_addcolor: pixels must be Imager::Color objects");
3627           }
3628         }
3629         index = i_addcolors(im, colors, items-1);
3630         myfree(colors);
3631         if (index == 0) {
3632           RETVAL = newSVpv("0 but true", 0);
3633         }
3634         else if (index == -1) {
3635           RETVAL = &PL_sv_undef;
3636         }
3637         else {
3638           RETVAL = newSViv(index);
3639         }
3640       OUTPUT:
3641         RETVAL
3642
3643 undef_int 
3644 i_setcolors(im, index, ...)
3645         Imager::ImgRaw  im
3646         int index
3647       PREINIT:
3648         i_color *colors;
3649         int i;
3650       CODE:
3651         if (items < 3)
3652           croak("i_setcolors: no colors to add");
3653         colors = mymalloc((items-2) * sizeof(i_color));
3654         for (i=0; i < items-2; ++i) {
3655           if (sv_isobject(ST(i+2)) 
3656               && sv_derived_from(ST(i+2), "Imager::Color")) {
3657             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3658             colors[i] = *INT2PTR(i_color *, tmp);
3659           }
3660           else {
3661             myfree(colors);
3662             croak("i_setcolors: pixels must be Imager::Color objects");
3663           }
3664         }
3665         RETVAL = i_setcolors(im, index, colors, items-2);
3666         myfree(colors);
3667       OUTPUT:
3668         RETVAL
3669
3670 void
3671 i_getcolors(im, index, ...)
3672         Imager::ImgRaw im
3673         int index
3674       PREINIT:
3675         i_color *colors;
3676         int count = 1;
3677         int i;
3678       PPCODE:
3679         if (items > 3)
3680           croak("i_getcolors: too many arguments");
3681         if (items == 3)
3682           count = SvIV(ST(2));
3683         if (count < 1)
3684           croak("i_getcolors: count must be positive");
3685         colors = mymalloc(sizeof(i_color) * count);
3686         if (i_getcolors(im, index, colors, count)) {
3687           for (i = 0; i < count; ++i) {
3688             i_color *pv;
3689             SV *sv = sv_newmortal();
3690             pv = mymalloc(sizeof(i_color));
3691             *pv = colors[i];
3692             sv_setref_pv(sv, "Imager::Color", (void *)pv);
3693             PUSHs(sv);
3694           }
3695         }
3696         myfree(colors);
3697
3698
3699 undef_neg_int
3700 i_colorcount(im)
3701         Imager::ImgRaw im
3702
3703 undef_neg_int
3704 i_maxcolors(im)
3705         Imager::ImgRaw im
3706
3707 SV *
3708 i_findcolor(im, color)
3709         Imager::ImgRaw im
3710         Imager::Color color
3711       PREINIT:
3712         i_palidx index;
3713       CODE:
3714         if (i_findcolor(im, color, &index)) {
3715           RETVAL = newSViv(index);
3716         }
3717         else {
3718           RETVAL = &PL_sv_undef;
3719         }
3720       OUTPUT:
3721         RETVAL
3722
3723 int
3724 i_img_bits(im)
3725         Imager::ImgRaw  im
3726
3727 int
3728 i_img_type(im)
3729         Imager::ImgRaw  im
3730
3731 int
3732 i_img_virtual(im)
3733         Imager::ImgRaw  im
3734
3735 void
3736 i_gsamp(im, l, r, y, ...)
3737         Imager::ImgRaw im
3738         int l
3739         int r
3740         int y
3741       PREINIT:
3742         int *chans;
3743         int chan_count;
3744         i_sample_t *data;
3745         int count, i;
3746       PPCODE:
3747         if (items < 5)
3748           croak("No channel numbers supplied to g_samp()");
3749         if (l < r) {
3750           chan_count = items - 4;
3751           chans = mymalloc(sizeof(int) * chan_count);
3752           for (i = 0; i < chan_count; ++i)
3753             chans[i] = SvIV(ST(i+4));
3754           data = mymalloc(sizeof(i_sample_t) * (r-l) * chan_count); /* XXX: memleak? */
3755           count = i_gsamp(im, l, r, y, data, chans, chan_count);
3756           myfree(chans);
3757           if (GIMME_V == G_ARRAY) {
3758             EXTEND(SP, count);
3759             for (i = 0; i < count; ++i)
3760               PUSHs(sv_2mortal(newSViv(data[i])));
3761           }
3762           else {
3763             EXTEND(SP, 1);
3764             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3765           }
3766           myfree(data);
3767         }
3768         else {
3769           if (GIMME_V != G_ARRAY) {
3770             EXTEND(SP, 1);
3771             PUSHs(&PL_sv_undef);
3772           }
3773         }
3774
3775
3776 Imager::ImgRaw
3777 i_img_masked_new(targ, mask, x, y, w, h)
3778         Imager::ImgRaw targ
3779         int x
3780         int y
3781         int w
3782         int h
3783       PREINIT:
3784         i_img *mask;
3785       CODE:
3786         if (SvOK(ST(1))) {
3787           if (!sv_isobject(ST(1)) 
3788               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3789             croak("i_img_masked_new: parameter 2 must undef or an image");
3790           }
3791           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3792         }
3793         else
3794           mask = NULL;
3795         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3796       OUTPUT:
3797         RETVAL
3798
3799 int
3800 i_plin(im, l, y, ...)
3801         Imager::ImgRaw  im
3802         int     l
3803         int     y
3804       PREINIT:
3805         i_color *work;
3806         int i;
3807         STRLEN len;
3808         int count;
3809       CODE:
3810         if (items > 3) {
3811           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3812             /* supplied as a byte string */
3813             work = (i_color *)SvPV(ST(3), len);
3814             count = len / sizeof(i_color);
3815             if (count * sizeof(i_color) != len) {
3816               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3817             }
3818             RETVAL = i_plin(im, l, l+count, y, work);
3819           }
3820           else {
3821             work = mymalloc(sizeof(i_color) * (items-3));
3822             for (i=0; i < items-3; ++i) {
3823               if (sv_isobject(ST(i+3)) 
3824                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3825                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3826                 work[i] = *INT2PTR(i_color *, tmp);
3827               }
3828               else {
3829                 myfree(work);
3830                 croak("i_plin: pixels must be Imager::Color objects");
3831               }
3832             }
3833             RETVAL = i_plin(im, l, l+items-3, y, work);
3834             myfree(work);
3835           }
3836         }
3837         else {
3838           RETVAL = 0;
3839         }
3840       OUTPUT:
3841         RETVAL
3842
3843 int
3844 i_ppixf(im, x, y, cl)
3845         Imager::ImgRaw im
3846         int x
3847         int y
3848         Imager::Color::Float cl
3849
3850 void
3851 i_gsampf(im, l, r, y, ...)
3852         Imager::ImgRaw im
3853         int l
3854         int r
3855         int y
3856       PREINIT:
3857         int *chans;
3858         int chan_count;
3859         i_fsample_t *data;
3860         int count, i;
3861       PPCODE:
3862         if (items < 5)
3863           croak("No channel numbers supplied to g_sampf()");
3864         if (l < r) {
3865           chan_count = items - 4;
3866           chans = mymalloc(sizeof(int) * chan_count);
3867           for (i = 0; i < chan_count; ++i)
3868             chans[i] = SvIV(ST(i+4));
3869           data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count);
3870           count = i_gsampf(im, l, r, y, data, chans, chan_count);
3871           myfree(chans);
3872           if (GIMME_V == G_ARRAY) {
3873             EXTEND(SP, count);
3874             for (i = 0; i < count; ++i)
3875               PUSHs(sv_2mortal(newSVnv(data[i])));
3876           }
3877           else {
3878             EXTEND(SP, 1);
3879             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3880           }
3881           myfree(data);
3882         }
3883         else {
3884           if (GIMME_V != G_ARRAY) {
3885             EXTEND(SP, 1);
3886             PUSHs(&PL_sv_undef);
3887           }
3888         }
3889
3890 int
3891 i_plinf(im, l, y, ...)
3892         Imager::ImgRaw  im
3893         int     l
3894         int     y
3895       PREINIT:
3896         i_fcolor *work;
3897         int i;
3898         STRLEN len;
3899         int count;
3900       CODE:
3901         if (items > 3) {
3902           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3903             /* supplied as a byte string */
3904             work = (i_fcolor *)SvPV(ST(3), len);
3905             count = len / sizeof(i_fcolor);
3906             if (count * sizeof(i_fcolor) != len) {
3907               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3908             }
3909             RETVAL = i_plinf(im, l, l+count, y, work);
3910           }
3911           else {
3912             work = mymalloc(sizeof(i_fcolor) * (items-3));
3913             for (i=0; i < items-3; ++i) {
3914               if (sv_isobject(ST(i+3)) 
3915                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3916                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3917                 work[i] = *INT2PTR(i_fcolor *, tmp);
3918               }
3919               else {
3920                 myfree(work);
3921                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3922               }
3923             }
3924             /**(char *)0 = 1;*/
3925             RETVAL = i_plinf(im, l, l+items-3, y, work);
3926             myfree(work);
3927           }
3928         }
3929         else {
3930           RETVAL = 0;
3931         }
3932       OUTPUT:
3933         RETVAL
3934
3935 SV *
3936 i_gpixf(im, x, y)
3937         Imager::ImgRaw im
3938         int x
3939         int y;
3940       PREINIT:
3941         i_fcolor *color;
3942       CODE:
3943         color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3944         if (i_gpixf(im, x, y, color) == 0) {
3945           RETVAL = NEWSV(0,0);
3946           sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
3947         }
3948         else {
3949           myfree(color);
3950           RETVAL = &PL_sv_undef;
3951         }
3952       OUTPUT:
3953         RETVAL
3954
3955 void
3956 i_glin(im, l, r, y)
3957         Imager::ImgRaw im
3958         int l
3959         int r
3960         int y
3961       PREINIT:
3962         i_color *vals;
3963         int count, i;
3964       PPCODE:
3965         if (l < r) {
3966           vals = mymalloc((r-l) * sizeof(i_color));
3967           memset(vals, 0, (r-l) * sizeof(i_color));
3968           count = i_glin(im, l, r, y, vals);
3969           if (GIMME_V == G_ARRAY) {
3970             EXTEND(SP, count);
3971             for (i = 0; i < count; ++i) {
3972               SV *sv;
3973               i_color *col = mymalloc(sizeof(i_color));
3974               *col = vals[i];
3975               sv = sv_newmortal();
3976               sv_setref_pv(sv, "Imager::Color", (void *)col);
3977               PUSHs(sv);
3978             }
3979           }
3980           else if (count) {
3981             EXTEND(SP, 1);
3982             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3983           }
3984           myfree(vals);
3985         }
3986
3987 void
3988 i_glinf(im, l, r, y)
3989         Imager::ImgRaw im
3990         int l
3991         int r
3992         int y
3993       PREINIT:
3994         i_fcolor *vals;
3995         int count, i;
3996         i_fcolor zero;
3997       PPCODE:
3998         for (i = 0; i < MAXCHANNELS; ++i)
3999           zero.channel[i] = 0;
4000         if (l < r) {
4001           vals = mymalloc((r-l) * sizeof(i_fcolor));
4002           for (i = 0; i < r-l; ++i)
4003             vals[i] = zero;
4004           count = i_glinf(im, l, r, y, vals);
4005           if (GIMME_V == G_ARRAY) {
4006             EXTEND(SP, count);
4007             for (i = 0; i < count; ++i) {
4008               SV *sv;
4009               i_fcolor *col = mymalloc(sizeof(i_fcolor));
4010               *col = vals[i];
4011               sv = sv_newmortal();
4012               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
4013               PUSHs(sv);
4014             }
4015           }
4016           else if (count) {
4017             EXTEND(SP, 1);
4018             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
4019           }
4020           myfree(vals);
4021         }
4022
4023 Imager::ImgRaw
4024 i_img_16_new(x, y, ch)
4025         int x
4026         int y
4027         int ch
4028
4029 Imager::ImgRaw
4030 i_img_to_rgb16(im)
4031        Imager::ImgRaw im
4032
4033 Imager::ImgRaw
4034 i_img_double_new(x, y, ch)
4035         int x
4036         int y
4037         int ch
4038
4039 undef_int
4040 i_tags_addn(im, name, code, idata)
4041         Imager::ImgRaw im
4042         int     code
4043         int     idata
4044       PREINIT:
4045         char *name;
4046         STRLEN len;
4047       CODE:
4048         if (SvOK(ST(1)))
4049           name = SvPV(ST(1), len);
4050         else
4051           name = NULL;
4052         RETVAL = i_tags_addn(&im->tags, name, code, idata);
4053       OUTPUT:
4054         RETVAL
4055
4056 undef_int
4057 i_tags_add(im, name, code, data, idata)
4058         Imager::ImgRaw  im
4059         int code
4060         int idata
4061       PREINIT:
4062         char *name;
4063         char *data;
4064         STRLEN len;
4065       CODE:
4066         if (SvOK(ST(1)))
4067           name = SvPV(ST(1), len);
4068         else
4069           name = NULL;
4070         if (SvOK(ST(3)))
4071           data = SvPV(ST(3), len);
4072         else {
4073           data = NULL;
4074           len = 0;
4075         }
4076         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
4077       OUTPUT:
4078         RETVAL
4079
4080 SV *
4081 i_tags_find(im, name, start)
4082         Imager::ImgRaw  im
4083         char *name
4084         int start
4085       PREINIT:
4086         int entry;
4087       CODE:
4088         if (i_tags_find(&im->tags, name, start, &entry)) {
4089           if (entry == 0)
4090             RETVAL = newSVpv("0 but true", 0);
4091           else
4092             RETVAL = newSViv(entry);
4093         } else {
4094           RETVAL = &PL_sv_undef;
4095         }
4096       OUTPUT:
4097         RETVAL
4098
4099 SV *
4100 i_tags_findn(im, code, start)
4101         Imager::ImgRaw  im
4102         int             code
4103         int             start
4104       PREINIT:
4105         int entry;
4106       CODE:
4107         if (i_tags_findn(&im->tags, code, start, &entry)) {
4108           if (entry == 0)
4109             RETVAL = newSVpv("0 but true", 0);
4110           else
4111             RETVAL = newSViv(entry);
4112         }
4113         else {
4114           RETVAL = &PL_sv_undef;
4115         }
4116       OUTPUT:
4117         RETVAL
4118
4119 int
4120 i_tags_delete(im, entry)
4121         Imager::ImgRaw  im
4122         int             entry
4123       CODE:
4124         RETVAL = i_tags_delete(&im->tags, entry);
4125       OUTPUT:
4126         RETVAL
4127
4128 int
4129 i_tags_delbyname(im, name)
4130         Imager::ImgRaw  im
4131         char *          name
4132       CODE:
4133         RETVAL = i_tags_delbyname(&im->tags, name);
4134       OUTPUT:
4135         RETVAL
4136
4137 int
4138 i_tags_delbycode(im, code)
4139         Imager::ImgRaw  im
4140         int             code
4141       CODE:
4142         RETVAL = i_tags_delbycode(&im->tags, code);
4143       OUTPUT:
4144         RETVAL
4145
4146 void
4147 i_tags_get(im, index)
4148         Imager::ImgRaw  im
4149         int             index
4150       PPCODE:
4151         if (index >= 0 && index < im->tags.count) {
4152           i_img_tag *entry = im->tags.tags + index;
4153           EXTEND(SP, 5);
4154         
4155           if (entry->name) {
4156             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
4157           }
4158           else {
4159             PUSHs(sv_2mortal(newSViv(entry->code)));
4160           }
4161           if (entry->data) {
4162             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
4163           }
4164           else {
4165             PUSHs(sv_2mortal(newSViv(entry->idata)));
4166           }
4167         }
4168
4169 void
4170 i_tags_get_string(im, what_sv)
4171         Imager::ImgRaw  im
4172         SV *what_sv
4173       PREINIT:
4174         char const *name = NULL;
4175         int code;
4176         char buffer[200];
4177       PPCODE:
4178         if (SvIOK(what_sv)) {
4179           code = SvIV(what_sv);
4180           name = NULL;
4181         }
4182         else {
4183           name = SvPV_nolen(what_sv);
4184           code = 0;
4185         }
4186         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
4187           EXTEND(SP, 1);
4188           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
4189         }
4190
4191 int
4192 i_tags_count(im)
4193         Imager::ImgRaw  im
4194       CODE:
4195         RETVAL = im->tags.count;
4196       OUTPUT:
4197         RETVAL
4198
4199 #ifdef HAVE_WIN32
4200
4201 void
4202 i_wf_bbox(face, size, text_sv, utf8=0)
4203         char *face
4204         int size
4205         SV *text_sv
4206         int utf8
4207       PREINIT:
4208         int cords[BOUNDING_BOX_COUNT];
4209         int rc, i;
4210         char const *text;
4211          STRLEN text_len;
4212       PPCODE:
4213         text = SvPV(text_sv, text_len);
4214 #ifdef SvUTF8
4215         if (SvUTF8(text_sv))
4216           utf8 = 1;
4217 #endif
4218         if (rc = i_wf_bbox(face, size, text, text_len, cords, utf8)) {
4219           EXTEND(SP, rc);  
4220           for (i = 0; i < rc; ++i) 
4221             PUSHs(sv_2mortal(newSViv(cords[i])));
4222         }
4223
4224 undef_int
4225 i_wf_text(face, im, tx, ty, cl, size, text_sv, align, aa, utf8 = 0)
4226         char *face
4227         Imager::ImgRaw im
4228         int tx
4229         int ty
4230         Imager::Color cl
4231         int size
4232         SV *text_sv
4233         int align
4234         int aa
4235         int utf8
4236       PREINIT:
4237         char const *text;
4238         STRLEN text_len;
4239       CODE:
4240         text = SvPV(text_sv, text_len);
4241 #ifdef SvUTF8
4242         if (SvUTF8(text_sv))
4243           utf8 = 1;
4244 #endif
4245         RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, text_len, 
4246                            align, aa, utf8);
4247       OUTPUT:
4248         RETVAL
4249
4250 undef_int
4251 i_wf_cp(face, im, tx, ty, channel, size, text_sv, align, aa, utf8 = 0)
4252         char *face
4253         Imager::ImgRaw im
4254         int tx
4255         int ty
4256         int channel
4257         int size
4258         SV *text_sv
4259         int align
4260         int aa
4261         int utf8
4262       PREINIT:
4263         char const *text;
4264         STRLEN text_len;
4265       CODE:
4266         text = SvPV(text_sv, text_len);
4267 #ifdef SvUTF8
4268         if (SvUTF8(text_sv))
4269           utf8 = 1;
4270 #endif
4271         RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, text_len, 
4272                          align, aa, utf8);
4273       OUTPUT:
4274         RETVAL
4275
4276 undef_int
4277 i_wf_addfont(font)
4278         char *font
4279
4280 undef_int
4281 i_wf_delfont(font)
4282         char *font
4283
4284 #endif
4285
4286 #ifdef HAVE_FT2
4287
4288 MODULE = Imager         PACKAGE = Imager::Font::FT2     PREFIX=FT2_
4289
4290 #define FT2_DESTROY(font) i_ft2_destroy(font)
4291
4292 void
4293 FT2_DESTROY(font)
4294         Imager::Font::FT2 font
4295
4296 MODULE = Imager         PACKAGE = Imager::Font::FreeType2 
4297
4298 Imager::Font::FT2
4299 i_ft2_new(name, index)
4300         char *name
4301         int index
4302
4303 undef_int
4304 i_ft2_setdpi(font, xdpi, ydpi)
4305         Imager::Font::FT2 font
4306         int xdpi
4307         int ydpi
4308
4309 void
4310 i_ft2_getdpi(font)
4311         Imager::Font::FT2 font
4312       PREINIT:
4313         int xdpi, ydpi;
4314       CODE:
4315         if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
4316           EXTEND(SP, 2);
4317           PUSHs(sv_2mortal(newSViv(xdpi)));
4318           PUSHs(sv_2mortal(newSViv(ydpi)));
4319         }
4320
4321 undef_int
4322 i_ft2_sethinting(font, hinting)
4323         Imager::Font::FT2 font
4324         int hinting
4325
4326 undef_int
4327 i_ft2_settransform(font, matrix)
4328         Imager::Font::FT2 font
4329       PREINIT:
4330         double matrix[6];
4331         int len;
4332         AV *av;
4333         SV *sv1;
4334         int i;
4335       CODE:
4336         if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4337           croak("i_ft2_settransform: parameter 2 must be an array ref\n");
4338         av=(AV*)SvRV(ST(1));
4339         len=av_len(av)+1;
4340         if (len > 6)
4341           len = 6;
4342         for (i = 0; i < len; ++i) {
4343           sv1=(*(av_fetch(av,i,0)));
4344           matrix[i] = SvNV(sv1);
4345         }
4346         for (; i < 6; ++i)
4347           matrix[i] = 0;
4348         RETVAL = i_ft2_settransform(font, matrix);
4349       OUTPUT:
4350         RETVAL
4351
4352 void
4353 i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
4354         Imager::Font::FT2 font
4355         double cheight
4356         double cwidth
4357         SV *text_sv
4358         int utf8
4359       PREINIT:
4360         int bbox[BOUNDING_BOX_COUNT];
4361         int i;
4362         char *text;
4363         STRLEN text_len;
4364         int rc;
4365       PPCODE:
4366         text = SvPV(text_sv, text_len);
4367 #ifdef SvUTF8
4368         if (SvUTF8(text_sv))
4369           utf8 = 1;
4370 #endif
4371         rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8);
4372         if (rc) {
4373           EXTEND(SP, rc);
4374           for (i = 0; i < rc; ++i)
4375             PUSHs(sv_2mortal(newSViv(bbox[i])));
4376         }
4377
4378 void
4379 i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
4380         Imager::Font::FT2 font
4381         double cheight
4382         double cwidth
4383         char *text
4384         int vlayout
4385         int utf8
4386       PREINIT:
4387         int bbox[8];
4388         int i;
4389       PPCODE:
4390 #ifdef SvUTF8
4391         if (SvUTF8(ST(3)))
4392           utf8 = 1;
4393 #endif
4394         if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
4395                          utf8, bbox)) {
4396           EXTEND(SP, 8);
4397           for (i = 0; i < 8; ++i)
4398             PUSHs(sv_2mortal(newSViv(bbox[i])));
4399         }
4400
4401 undef_int
4402 i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
4403         Imager::Font::FT2 font
4404         Imager::ImgRaw im
4405         int tx
4406         int ty
4407         Imager::Color cl
4408         double cheight
4409         double cwidth
4410         int align
4411         int aa
4412         int vlayout
4413         int utf8
4414       PREINIT:
4415         char *text;
4416         STRLEN len;
4417       CODE:
4418 #ifdef SvUTF8
4419         if (SvUTF8(ST(7))) {
4420           utf8 = 1;
4421         }
4422 #endif
4423         text = SvPV(ST(7), len);
4424         RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
4425                             len, align, aa, vlayout, utf8);
4426       OUTPUT:
4427         RETVAL
4428
4429 undef_int
4430 i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text_sv, align, aa, vlayout, utf8)
4431         Imager::Font::FT2 font
4432         Imager::ImgRaw im
4433         int tx
4434         int ty
4435         int channel
4436         double cheight
4437         double cwidth
4438         SV *text_sv
4439         int align
4440         int aa
4441         int vlayout
4442         int utf8
4443       PREINIT:
4444         char const *text;
4445         STRLEN len;
4446       CODE:
4447 #ifdef SvUTF8
4448         if (SvUTF8(ST(7)))
4449           utf8 = 1;
4450 #endif
4451         text = SvPV(text_sv, len);
4452         RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
4453                           len, align, aa, vlayout, 1);
4454       OUTPUT:
4455         RETVAL
4456
4457 void
4458 ft2_transform_box(font, x0, x1, x2, x3)
4459         Imager::Font::FT2 font
4460         int x0
4461         int x1
4462         int x2
4463         int x3
4464       PREINIT:
4465         int box[4];
4466       PPCODE:
4467         box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
4468         ft2_transform_box(font, box);
4469           EXTEND(SP, 4);
4470           PUSHs(sv_2mortal(newSViv(box[0])));
4471           PUSHs(sv_2mortal(newSViv(box[1])));
4472           PUSHs(sv_2mortal(newSViv(box[2])));
4473           PUSHs(sv_2mortal(newSViv(box[3])));
4474
4475 void
4476 i_ft2_has_chars(handle, text_sv, utf8)
4477         Imager::Font::FT2 handle
4478         SV  *text_sv
4479         int utf8
4480       PREINIT:
4481         char *text;
4482         STRLEN len;
4483         char *work;
4484         int count;
4485         int i;
4486       PPCODE:
4487 #ifdef SvUTF8
4488         if (SvUTF8(text_sv))
4489           utf8 = 1;
4490 #endif
4491         text = SvPV(text_sv, len);
4492         work = mymalloc(len);
4493         count = i_ft2_has_chars(handle, text, len, utf8, work);
4494         if (GIMME_V == G_ARRAY) {
4495           EXTEND(SP, count);
4496           for (i = 0; i < count; ++i) {
4497             PUSHs(sv_2mortal(newSViv(work[i])));
4498           }
4499         }
4500         else {
4501           EXTEND(SP, 1);
4502           PUSHs(sv_2mortal(newSVpv(work, count)));
4503         }
4504         myfree(work);
4505
4506 void
4507 i_ft2_face_name(handle)
4508         Imager::Font::FT2 handle
4509       PREINIT:
4510         char name[255];
4511         int len;
4512       PPCODE:
4513         len = i_ft2_face_name(handle, name, sizeof(name));
4514         if (len) {
4515           EXTEND(SP, 1);
4516           PUSHs(sv_2mortal(newSVpv(name, 0)));
4517         }
4518
4519 undef_int
4520 i_ft2_can_face_name()
4521
4522 void
4523 i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
4524         Imager::Font::FT2 handle
4525         SV *text_sv
4526         int utf8
4527         int reliable_only
4528       PREINIT:
4529         char const *text;
4530         STRLEN work_len;
4531         int len;
4532         char name[255];
4533       PPCODE:
4534 #ifdef SvUTF8
4535         if (SvUTF8(text_sv))
4536           utf8 = 1;
4537 #endif
4538         text = SvPV(text_sv, work_len);
4539         len = work_len;
4540         while (len) {
4541           unsigned long ch;
4542           if (utf8) {
4543             ch = i_utf8_advance(&text, &len);
4544             if (ch == ~0UL) {
4545               i_push_error(0, "invalid UTF8 character");
4546               break;
4547             }
4548           }
4549           else {
4550             ch = *text++;
4551             --len;
4552           }
4553           EXTEND(SP, 1);
4554           if (i_ft2_glyph_name(handle, ch, name, sizeof(name), 
4555                                          reliable_only)) {
4556             PUSHs(sv_2mortal(newSVpv(name, 0)));
4557           }
4558           else {
4559             PUSHs(&PL_sv_undef);
4560           } 
4561         }
4562
4563 int
4564 i_ft2_can_do_glyph_names()
4565
4566 int
4567 i_ft2_face_has_glyph_names(handle)
4568         Imager::Font::FT2 handle
4569
4570 int
4571 i_ft2_is_multiple_master(handle)
4572         Imager::Font::FT2 handle
4573
4574 void
4575 i_ft2_get_multiple_masters(handle)
4576         Imager::Font::FT2 handle
4577       PREINIT:
4578         i_font_mm mm;
4579         int i;
4580       PPCODE:
4581         if (i_ft2_get_multiple_masters(handle, &mm)) {
4582           EXTEND(SP, 2+mm.num_axis);
4583           PUSHs(sv_2mortal(newSViv(mm.num_axis)));
4584           PUSHs(sv_2mortal(newSViv(mm.num_designs)));
4585           for (i = 0; i < mm.num_axis; ++i) {
4586             AV *av = newAV();
4587             SV *sv;
4588             av_extend(av, 3);
4589             sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name));
4590             SvREFCNT_inc(sv);
4591             av_store(av, 0, sv);
4592             sv = newSViv(mm.axis[i].minimum);
4593             SvREFCNT_inc(sv);
4594             av_store(av, 1, sv);
4595             sv = newSViv(mm.axis[i].maximum);
4596             SvREFCNT_inc(sv);
4597             av_store(av, 2, sv);
4598             PUSHs(newRV_noinc((SV *)av));
4599           }
4600         }
4601
4602 undef_int
4603 i_ft2_set_mm_coords(handle, ...)
4604         Imager::Font::FT2 handle
4605       PROTOTYPE: DISABLE
4606       PREINIT:
4607         long *coords;
4608         int ix_coords, i;
4609       CODE:
4610         /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so
4611            transfer the array manually */
4612         ix_coords = items-1;
4613         coords = mymalloc(sizeof(long) * ix_coords);
4614         for (i = 0; i < ix_coords; ++i) {
4615           coords[i] = (long)SvIV(ST(1+i));
4616         }
4617         RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords);
4618         myfree(coords);
4619       OUTPUT:
4620         RETVAL
4621
4622 #endif
4623
4624 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
4625
4626 void
4627 IFILL_DESTROY(fill)
4628         Imager::FillHandle fill
4629
4630 MODULE = Imager         PACKAGE = Imager
4631
4632 Imager::FillHandle
4633 i_new_fill_solid(cl, combine)
4634         Imager::Color cl
4635         int combine
4636
4637 Imager::FillHandle
4638 i_new_fill_solidf(cl, combine)
4639         Imager::Color::Float cl
4640         int combine
4641
4642 Imager::FillHandle
4643 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
4644         Imager::Color fg
4645         Imager::Color bg
4646         int combine
4647         int hatch
4648         int dx
4649         int dy
4650       PREINIT:
4651         unsigned char *cust_hatch;
4652         STRLEN len;
4653       CODE:
4654         if (SvOK(ST(4))) {
4655           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4656         }
4657         else
4658           cust_hatch = NULL;
4659         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
4660       OUTPUT:
4661         RETVAL
4662
4663 Imager::FillHandle
4664 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
4665         Imager::Color::Float fg
4666         Imager::Color::Float bg
4667         int combine
4668         int hatch
4669         int dx
4670         int dy
4671       PREINIT:
4672         unsigned char *cust_hatch;
4673         STRLEN len;
4674       CODE:
4675         if (SvOK(ST(4))) {
4676           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4677         }
4678         else
4679           cust_hatch = NULL;
4680         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
4681       OUTPUT:
4682         RETVAL
4683
4684 Imager::FillHandle
4685 i_new_fill_image(src, matrix, xoff, yoff, combine)
4686         Imager::ImgRaw src
4687         int xoff
4688         int yoff
4689         int combine
4690       PREINIT:
4691         double matrix[9];
4692         double *matrixp;
4693         AV *av;
4694         IV len;
4695         SV *sv1;
4696         int i;
4697       CODE:
4698         if (!SvOK(ST(1))) {
4699           matrixp = NULL;
4700         }
4701         else {
4702           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4703             croak("i_new_fill_image: parameter must be an arrayref");
4704           av=(AV*)SvRV(ST(1));
4705           len=av_len(av)+1;
4706           if (len > 9)
4707             len = 9;
4708           for (i = 0; i < len; ++i) {
4709             sv1=(*(av_fetch(av,i,0)));
4710             matrix[i] = SvNV(sv1);
4711           }
4712           for (; i < 9; ++i)
4713             matrix[i] = 0;
4714           matrixp = matrix;
4715         }
4716         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4717       OUTPUT:
4718         RETVAL
4719
4720 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
4721
4722 # this class is only exposed for testing
4723
4724 int
4725 i_int_hlines_testing()
4726
4727 #if i_int_hlines_testing()
4728
4729 Imager::Internal::Hlines
4730 i_int_hlines_new(start_y, count_y, start_x, count_x)
4731         int start_y
4732         int count_y
4733         int start_x
4734         int count_x
4735
4736 Imager::Internal::Hlines
4737 i_int_hlines_new_img(im)
4738         Imager::ImgRaw im
4739
4740 void
4741 i_int_hlines_add(hlines, y, minx, width)
4742         Imager::Internal::Hlines hlines
4743         int y
4744         int minx
4745         int width
4746
4747 void
4748 i_int_hlines_DESTROY(hlines)
4749         Imager::Internal::Hlines hlines
4750
4751 SV *
4752 i_int_hlines_dump(hlines)
4753         Imager::Internal::Hlines hlines
4754
4755 #endif
4756
4757 BOOT:
4758         PERL_SET_GLOBAL_CALLBACKS;