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