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