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