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