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