]> git.imager.perl.org - imager.git/blob - Imager.xs
66939fa4388b105aa1038d436de0fdac19bfada5
[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)
2039         Imager::IO     ig
2040                int     length
2041
2042 void
2043 i_readtiff_multi_wiol(ig, length)
2044         Imager::IO     ig
2045                int     length
2046       PREINIT:
2047         i_img **imgs;
2048         int count;
2049         int i;
2050       PPCODE:
2051         imgs = i_readtiff_multi_wiol(ig, length, &count);
2052         if (imgs) {
2053           EXTEND(SP, count);
2054           for (i = 0; i < count; ++i) {
2055             SV *sv = sv_newmortal();
2056             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2057             PUSHs(sv);
2058           }
2059           myfree(imgs);
2060         }
2061
2062
2063 undef_int
2064 i_writetiff_wiol(im, ig)
2065     Imager::ImgRaw     im
2066         Imager::IO     ig
2067
2068 undef_int
2069 i_writetiff_multi_wiol(ig, ...)
2070         Imager::IO     ig
2071       PREINIT:
2072         int i;
2073         int img_count;
2074         i_img **imgs;
2075       CODE:
2076         if (items < 2)
2077           croak("Usage: i_writetiff_multi_wiol(ig, images...)");
2078         img_count = items - 1;
2079         RETVAL = 1;
2080         if (img_count < 1) {
2081           RETVAL = 0;
2082           i_clear_error();
2083           i_push_error(0, "You need to specify images to save");
2084         }
2085         else {
2086           imgs = mymalloc(sizeof(i_img *) * img_count);
2087           for (i = 0; i < img_count; ++i) {
2088             SV *sv = ST(1+i);
2089             imgs[i] = NULL;
2090             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2091               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2092             }
2093             else {
2094               i_clear_error();
2095               i_push_error(0, "Only images can be saved");
2096               myfree(imgs);
2097               RETVAL = 0;
2098               break;
2099             }
2100           }
2101           if (RETVAL) {
2102             RETVAL = i_writetiff_multi_wiol(ig, imgs, img_count);
2103           }
2104           myfree(imgs);
2105         }
2106       OUTPUT:
2107         RETVAL
2108
2109 undef_int
2110 i_writetiff_wiol_faxable(im, ig, fine)
2111     Imager::ImgRaw     im
2112         Imager::IO     ig
2113                int     fine
2114
2115 undef_int
2116 i_writetiff_multi_wiol_faxable(ig, fine, ...)
2117         Imager::IO     ig
2118         int fine
2119       PREINIT:
2120         int i;
2121         int img_count;
2122         i_img **imgs;
2123       CODE:
2124         if (items < 3)
2125           croak("Usage: i_writetiff_multi_wiol_faxable(ig, fine, images...)");
2126         img_count = items - 2;
2127         RETVAL = 1;
2128         if (img_count < 1) {
2129           RETVAL = 0;
2130           i_clear_error();
2131           i_push_error(0, "You need to specify images to save");
2132         }
2133         else {
2134           imgs = mymalloc(sizeof(i_img *) * img_count);
2135           for (i = 0; i < img_count; ++i) {
2136             SV *sv = ST(2+i);
2137             imgs[i] = NULL;
2138             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2139               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2140             }
2141             else {
2142               i_clear_error();
2143               i_push_error(0, "Only images can be saved");
2144               myfree(imgs);
2145               RETVAL = 0;
2146               break;
2147             }
2148           }
2149           if (RETVAL) {
2150             RETVAL = i_writetiff_multi_wiol_faxable(ig, imgs, img_count, fine);
2151           }
2152           myfree(imgs);
2153         }
2154       OUTPUT:
2155         RETVAL
2156
2157
2158 #endif /* HAVE_LIBTIFF */
2159
2160
2161 #ifdef HAVE_LIBPNG
2162
2163 Imager::ImgRaw
2164 i_readpng_wiol(ig, length)
2165         Imager::IO     ig
2166                int     length
2167
2168
2169 undef_int
2170 i_writepng_wiol(im, ig)
2171     Imager::ImgRaw     im
2172         Imager::IO     ig
2173
2174
2175 #endif
2176
2177
2178 #ifdef HAVE_LIBGIF
2179
2180 void
2181 i_giflib_version()
2182         PPCODE:
2183           PUSHs(sv_2mortal(newSVnv(IM_GIFMAJOR+IM_GIFMINOR*0.1)));
2184
2185 undef_int
2186 i_writegif(im,fd,colors,pixdev,fixed)
2187     Imager::ImgRaw     im
2188                int     fd
2189                int     colors
2190                int     pixdev
2191              PREINIT:
2192              int     fixedlen;
2193              Imager__Color  fixed;
2194              Imager__Color  tmp;
2195              AV* av;
2196              SV* sv1;
2197              IV  Itmp;
2198              int i;
2199              CODE:
2200              if (!SvROK(ST(4))) croak("Imager: Parameter 4 must be a reference to an array\n");
2201              if (SvTYPE(SvRV(ST(4))) != SVt_PVAV) croak("Imager: Parameter 4 must be a reference to an array\n");
2202              av=(AV*)SvRV(ST(4));
2203              fixedlen=av_len(av)+1;
2204              fixed=mymalloc( fixedlen*sizeof(i_color) );
2205              for(i=0;i<fixedlen;i++) {
2206                sv1=(*(av_fetch(av,i,0)));
2207                if (sv_derived_from(sv1, "Imager::Color")) {
2208                  Itmp = SvIV((SV*)SvRV(sv1));
2209                  tmp = INT2PTR(i_color*, Itmp);
2210                } else croak("Imager: one of the elements of array ref is not of Imager::Color type\n");
2211                fixed[i]=*tmp;
2212              }
2213              RETVAL=i_writegif(im,fd,colors,pixdev,fixedlen,fixed);
2214              myfree(fixed);
2215              ST(0) = sv_newmortal();
2216              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2217              else sv_setiv(ST(0), (IV)RETVAL);
2218
2219
2220
2221
2222 undef_int
2223 i_writegifmc(im,fd,colors)
2224     Imager::ImgRaw    im
2225                int     fd
2226                int     colors
2227
2228
2229 undef_int
2230 i_writegif_gen(fd, ...)
2231                int     fd
2232       PROTOTYPE: $$@
2233       PREINIT:
2234         i_quantize quant;
2235         i_img **imgs = NULL;
2236         int img_count;
2237         int i;
2238         HV *hv;
2239       CODE:
2240         if (items < 3)
2241             croak("Usage: i_writegif_gen(fd,hashref, images...)");
2242         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2243             croak("i_writegif_gen: Second argument must be a hash ref");
2244         hv = (HV *)SvRV(ST(1));
2245         memset(&quant, 0, sizeof(quant));
2246         quant.mc_size = 256;
2247         handle_quant_opts(&quant, hv);
2248         img_count = items - 2;
2249         RETVAL = 1;
2250         if (img_count < 1) {
2251           RETVAL = 0;
2252           i_clear_error();
2253           i_push_error(0, "You need to specify images to save");
2254         }
2255         else {
2256           imgs = mymalloc(sizeof(i_img *) * img_count);
2257           for (i = 0; i < img_count; ++i) {
2258             SV *sv = ST(2+i);
2259             imgs[i] = NULL;
2260             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2261               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2262             }
2263             else {
2264               i_clear_error();
2265               i_push_error(0, "Only images can be saved");
2266               RETVAL = 0;
2267               break;
2268             }
2269           }
2270           if (RETVAL) {
2271             RETVAL = i_writegif_gen(&quant, fd, imgs, img_count);
2272           }
2273           myfree(imgs);
2274           if (RETVAL) {
2275             copy_colors_back(hv, &quant);
2276           }
2277         }
2278         ST(0) = sv_newmortal();
2279         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2280         else sv_setiv(ST(0), (IV)RETVAL);
2281         cleanup_quant_opts(&quant);
2282
2283
2284 undef_int
2285 i_writegif_callback(cb, maxbuffer,...)
2286         int maxbuffer;
2287       PREINIT:
2288         i_quantize quant;
2289         i_img **imgs = NULL;
2290         int img_count;
2291         int i;
2292         HV *hv;
2293         i_writer_data wd;
2294       CODE:
2295         if (items < 4)
2296             croak("Usage: i_writegif_callback(\\&callback,maxbuffer,hashref, images...)");
2297         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2298             croak("i_writegif_callback: Second argument must be a hash ref");
2299         hv = (HV *)SvRV(ST(2));
2300         memset(&quant, 0, sizeof(quant));
2301         quant.mc_size = 256;
2302         handle_quant_opts(&quant, hv);
2303         img_count = items - 3;
2304         RETVAL = 1;
2305         if (img_count < 1) {
2306           RETVAL = 0;
2307         }
2308         else {
2309           imgs = mymalloc(sizeof(i_img *) * img_count);
2310           for (i = 0; i < img_count; ++i) {
2311             SV *sv = ST(3+i);
2312             imgs[i] = NULL;
2313             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2314               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2315             }
2316             else {
2317               RETVAL = 0;
2318               break;
2319             }
2320           }
2321           if (RETVAL) {
2322             wd.sv = ST(0);
2323             RETVAL = i_writegif_callback(&quant, write_callback, (char *)&wd, maxbuffer, imgs, img_count);
2324           }
2325           myfree(imgs);
2326           if (RETVAL) {
2327             copy_colors_back(hv, &quant);
2328           }
2329         }
2330         ST(0) = sv_newmortal();
2331         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2332         else sv_setiv(ST(0), (IV)RETVAL);
2333         cleanup_quant_opts(&quant);
2334
2335 undef_int
2336 i_writegif_wiol(ig, opts,...)
2337         Imager::IO ig
2338       PREINIT:
2339         i_quantize quant;
2340         i_img **imgs = NULL;
2341         int img_count;
2342         int i;
2343         HV *hv;
2344       CODE:
2345         if (items < 3)
2346             croak("Usage: i_writegif_wiol(IO,hashref, images...)");
2347         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2348             croak("i_writegif_callback: Second argument must be a hash ref");
2349         hv = (HV *)SvRV(ST(1));
2350         memset(&quant, 0, sizeof(quant));
2351         quant.mc_size = 256;
2352         handle_quant_opts(&quant, hv);
2353         img_count = items - 2;
2354         RETVAL = 1;
2355         if (img_count < 1) {
2356           RETVAL = 0;
2357         }
2358         else {
2359           imgs = mymalloc(sizeof(i_img *) * img_count);
2360           for (i = 0; i < img_count; ++i) {
2361             SV *sv = ST(2+i);
2362             imgs[i] = NULL;
2363             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2364               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2365             }
2366             else {
2367               RETVAL = 0;
2368               break;
2369             }
2370           }
2371           if (RETVAL) {
2372             RETVAL = i_writegif_wiol(ig, &quant, imgs, img_count);
2373           }
2374           myfree(imgs);
2375           if (RETVAL) {
2376             copy_colors_back(hv, &quant);
2377           }
2378         }
2379         ST(0) = sv_newmortal();
2380         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2381         else sv_setiv(ST(0), (IV)RETVAL);
2382         cleanup_quant_opts(&quant);
2383
2384 void
2385 i_readgif(fd)
2386                int     fd
2387               PREINIT:
2388                 int*    colour_table;
2389                 int     colours, q, w;
2390               i_img*    rimg;
2391                  SV*    temp[3];
2392                  AV*    ct; 
2393                  SV*    r;
2394                PPCODE:
2395                colour_table = NULL;
2396                colours = 0;
2397
2398         if(GIMME_V == G_ARRAY) {
2399             rimg = i_readgif(fd,&colour_table,&colours);
2400         } else {
2401             /* don't waste time with colours if they aren't wanted */
2402             rimg = i_readgif(fd,NULL,NULL);
2403         }
2404         
2405         if (colour_table == NULL) {
2406             EXTEND(SP,1);
2407             r=sv_newmortal();
2408             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2409             PUSHs(r);
2410         } else {
2411             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2412             /* I don't know if I have the reference counts right or not :( */
2413             /* Neither do I :-) */
2414             /* No Idea here either */
2415
2416             ct=newAV();
2417             av_extend(ct, colours);
2418             for(q=0; q<colours; q++) {
2419                 for(w=0; w<3; w++)
2420                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2421                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2422             }
2423             myfree(colour_table);
2424
2425             EXTEND(SP,2);
2426             r = sv_newmortal();
2427             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2428             PUSHs(r);
2429             PUSHs(newRV_noinc((SV*)ct));
2430         }
2431
2432 void
2433 i_readgif_wiol(ig)
2434      Imager::IO         ig
2435               PREINIT:
2436                 int*    colour_table;
2437                 int     colours, q, w;
2438               i_img*    rimg;
2439                  SV*    temp[3];
2440                  AV*    ct; 
2441                  SV*    r;
2442                PPCODE:
2443                colour_table = NULL;
2444                colours = 0;
2445
2446         if(GIMME_V == G_ARRAY) {
2447             rimg = i_readgif_wiol(ig,&colour_table,&colours);
2448         } else {
2449             /* don't waste time with colours if they aren't wanted */
2450             rimg = i_readgif_wiol(ig,NULL,NULL);
2451         }
2452         
2453         if (colour_table == NULL) {
2454             EXTEND(SP,1);
2455             r=sv_newmortal();
2456             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2457             PUSHs(r);
2458         } else {
2459             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2460             /* I don't know if I have the reference counts right or not :( */
2461             /* Neither do I :-) */
2462             /* No Idea here either */
2463
2464             ct=newAV();
2465             av_extend(ct, colours);
2466             for(q=0; q<colours; q++) {
2467                 for(w=0; w<3; w++)
2468                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2469                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2470             }
2471             myfree(colour_table);
2472
2473             EXTEND(SP,2);
2474             r = sv_newmortal();
2475             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2476             PUSHs(r);
2477             PUSHs(newRV_noinc((SV*)ct));
2478         }
2479
2480 void
2481 i_readgif_scalar(...)
2482           PROTOTYPE: $
2483             PREINIT:
2484                char*    data;
2485              STRLEN     length;
2486                 int*    colour_table;
2487                 int     colours, q, w;
2488               i_img*    rimg;
2489                  SV*    temp[3];
2490                  AV*    ct; 
2491                  SV*    r;
2492                PPCODE:
2493         data = (char *)SvPV(ST(0), length);
2494         colour_table=NULL;
2495         colours=0;
2496
2497         if(GIMME_V == G_ARRAY) {  
2498             rimg=i_readgif_scalar(data,length,&colour_table,&colours);
2499         } else {
2500             /* don't waste time with colours if they aren't wanted */
2501             rimg=i_readgif_scalar(data,length,NULL,NULL);
2502         }
2503
2504         if (colour_table == NULL) {
2505             EXTEND(SP,1);
2506             r=sv_newmortal();
2507             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2508             PUSHs(r);
2509         } else {
2510             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2511             /* I don't know if I have the reference counts right or not :( */
2512             /* Neither do I :-) */
2513             ct=newAV();
2514             av_extend(ct, colours);
2515             for(q=0; q<colours; q++) {
2516                 for(w=0; w<3; w++)
2517                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2518                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2519             }
2520             myfree(colour_table);
2521             
2522             EXTEND(SP,2);
2523             r=sv_newmortal();
2524             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2525             PUSHs(r);
2526             PUSHs(newRV_noinc((SV*)ct));
2527         }
2528
2529 void
2530 i_readgif_callback(...)
2531           PROTOTYPE: &
2532             PREINIT:
2533                 int*    colour_table;
2534                 int     colours, q, w;
2535               i_img*    rimg;
2536                  SV*    temp[3];
2537                  AV*    ct; 
2538                  SV*    r;
2539        i_reader_data    rd;
2540                PPCODE:
2541         rd.sv = ST(0);
2542         colour_table=NULL;
2543         colours=0;
2544
2545         if(GIMME_V == G_ARRAY) {  
2546             rimg=i_readgif_callback(read_callback, (char *)&rd,&colour_table,&colours);
2547         } else {
2548             /* don't waste time with colours if they aren't wanted */
2549             rimg=i_readgif_callback(read_callback, (char *)&rd,NULL,NULL);
2550         }
2551
2552         if (colour_table == NULL) {
2553             EXTEND(SP,1);
2554             r=sv_newmortal();
2555             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2556             PUSHs(r);
2557         } else {
2558             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2559             /* I don't know if I have the reference counts right or not :( */
2560             /* Neither do I :-) */
2561             /* Neither do I - maybe I'll move this somewhere */
2562             ct=newAV();
2563             av_extend(ct, colours);
2564             for(q=0; q<colours; q++) {
2565                 for(w=0; w<3; w++)
2566                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2567                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2568             }
2569             myfree(colour_table);
2570             
2571             EXTEND(SP,2);
2572             r=sv_newmortal();
2573             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2574             PUSHs(r);
2575             PUSHs(newRV_noinc((SV*)ct));
2576         }
2577
2578 void
2579 i_readgif_multi(fd)
2580         int     fd
2581       PREINIT:
2582         i_img **imgs;
2583         int count;
2584         int i;
2585       PPCODE:
2586         imgs = i_readgif_multi(fd, &count);
2587         if (imgs) {
2588           EXTEND(SP, count);
2589           for (i = 0; i < count; ++i) {
2590             SV *sv = sv_newmortal();
2591             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2592             PUSHs(sv);
2593           }
2594           myfree(imgs);
2595         }
2596
2597 void
2598 i_readgif_multi_scalar(data)
2599       PREINIT:
2600         i_img **imgs;
2601         int count;
2602         char *data;
2603         STRLEN length;
2604         int i;
2605       PPCODE:
2606         data = (char *)SvPV(ST(0), length);
2607         imgs = i_readgif_multi_scalar(data, length, &count);
2608         if (imgs) {
2609           EXTEND(SP, count);
2610           for (i = 0; i < count; ++i) {
2611             SV *sv = sv_newmortal();
2612             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2613             PUSHs(sv);
2614           }
2615           myfree(imgs);
2616         }
2617
2618 void
2619 i_readgif_multi_callback(cb)
2620       PREINIT:
2621         i_reader_data rd;
2622         i_img **imgs;
2623         int count;
2624         int i;
2625       PPCODE:
2626         rd.sv = ST(0);
2627         imgs = i_readgif_multi_callback(read_callback, (char *)&rd, &count);
2628         if (imgs) {
2629           EXTEND(SP, count);
2630           for (i = 0; i < count; ++i) {
2631             SV *sv = sv_newmortal();
2632             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2633             PUSHs(sv);
2634           }
2635           myfree(imgs);
2636         }
2637
2638 void
2639 i_readgif_multi_wiol(ig)
2640         Imager::IO ig
2641       PREINIT:
2642         i_img **imgs;
2643         int count;
2644         int i;
2645       PPCODE:
2646         imgs = i_readgif_multi_wiol(ig, &count);
2647         if (imgs) {
2648           EXTEND(SP, count);
2649           for (i = 0; i < count; ++i) {
2650             SV *sv = sv_newmortal();
2651             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2652             PUSHs(sv);
2653           }
2654           myfree(imgs);
2655         }
2656
2657
2658 #endif
2659
2660
2661
2662 Imager::ImgRaw
2663 i_readpnm_wiol(ig, length)
2664         Imager::IO     ig
2665                int     length
2666
2667
2668 undef_int
2669 i_writeppm_wiol(im, ig)
2670     Imager::ImgRaw     im
2671         Imager::IO     ig
2672
2673
2674 Imager::ImgRaw
2675 i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
2676         Imager::IO     ig
2677                int     x
2678                int     y
2679                int     datachannels
2680                int     storechannels
2681                int     intrl
2682
2683 undef_int
2684 i_writeraw_wiol(im,ig)
2685     Imager::ImgRaw     im
2686         Imager::IO     ig
2687
2688 undef_int
2689 i_writebmp_wiol(im,ig)
2690     Imager::ImgRaw     im
2691         Imager::IO     ig
2692
2693 Imager::ImgRaw
2694 i_readbmp_wiol(ig)
2695         Imager::IO     ig
2696
2697
2698 undef_int
2699 i_writetga_wiol(im,ig, wierdpack, compress, idstring)
2700     Imager::ImgRaw     im
2701         Imager::IO     ig
2702                int     wierdpack
2703                int     compress
2704               char*    idstring
2705             PREINIT:
2706                 int idlen;
2707                CODE:
2708                 idlen  = SvCUR(ST(4));
2709                 RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
2710                 OUTPUT:
2711                 RETVAL
2712
2713
2714 Imager::ImgRaw
2715 i_readtga_wiol(ig, length)
2716         Imager::IO     ig
2717                int     length
2718
2719
2720 undef_int
2721 i_writergb_wiol(im,ig, wierdpack, compress, idstring)
2722     Imager::ImgRaw     im
2723         Imager::IO     ig
2724                int     wierdpack
2725                int     compress
2726               char*    idstring
2727             PREINIT:
2728                 int idlen;
2729                CODE:
2730                 idlen  = SvCUR(ST(4));
2731                 RETVAL = i_writergb_wiol(im, ig, wierdpack, compress, idstring, idlen);
2732                 OUTPUT:
2733                 RETVAL
2734
2735
2736 Imager::ImgRaw
2737 i_readrgb_wiol(ig, length)
2738         Imager::IO     ig
2739                int     length
2740
2741
2742
2743 Imager::ImgRaw
2744 i_scaleaxis(im,Value,Axis)
2745     Imager::ImgRaw     im
2746              float     Value
2747                int     Axis
2748
2749 Imager::ImgRaw
2750 i_scale_nn(im,scx,scy)
2751     Imager::ImgRaw     im
2752              float     scx
2753              float     scy
2754
2755 Imager::ImgRaw
2756 i_haar(im)
2757     Imager::ImgRaw     im
2758
2759 int
2760 i_count_colors(im,maxc)
2761     Imager::ImgRaw     im
2762                int     maxc
2763
2764
2765 Imager::ImgRaw
2766 i_transform(im,opx,opy,parm)
2767     Imager::ImgRaw     im
2768              PREINIT:
2769              double* parm;
2770              int*    opx;
2771              int*    opy;
2772              int     opxl;
2773              int     opyl;
2774              int     parmlen;
2775              AV* av;
2776              SV* sv1;
2777              int i;
2778              CODE:
2779              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
2780              if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n");
2781              if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n");
2782              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
2783              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n");
2784              if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n");
2785              av=(AV*)SvRV(ST(1));
2786              opxl=av_len(av)+1;
2787              opx=mymalloc( opxl*sizeof(int) );
2788              for(i=0;i<opxl;i++) {
2789                sv1=(*(av_fetch(av,i,0)));
2790                opx[i]=(int)SvIV(sv1);
2791              }
2792              av=(AV*)SvRV(ST(2));
2793              opyl=av_len(av)+1;
2794              opy=mymalloc( opyl*sizeof(int) );
2795              for(i=0;i<opyl;i++) {
2796                sv1=(*(av_fetch(av,i,0)));
2797                opy[i]=(int)SvIV(sv1);
2798              }
2799              av=(AV*)SvRV(ST(3));
2800              parmlen=av_len(av)+1;
2801              parm=mymalloc( parmlen*sizeof(double) );
2802              for(i=0;i<parmlen;i++) { /* FIXME: Bug? */
2803                sv1=(*(av_fetch(av,i,0)));
2804                parm[i]=(double)SvNV(sv1);
2805              }
2806              RETVAL=i_transform(im,opx,opxl,opy,opyl,parm,parmlen);
2807              myfree(parm);
2808              myfree(opy);
2809              myfree(opx);
2810              ST(0) = sv_newmortal();
2811              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2812              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2813
2814 Imager::ImgRaw
2815 i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
2816         SV *sv_width
2817         SV *sv_height
2818         SV *sv_ops
2819         AV *av_n_regs
2820         AV *av_c_regs
2821         AV *av_in_imgs
2822         int channels
2823              PREINIT:
2824              int width;
2825              int height;
2826              struct rm_op *ops;
2827              STRLEN ops_len;
2828              int ops_count;
2829              double *n_regs;
2830              int n_regs_count;
2831              i_color *c_regs;
2832              int c_regs_count;
2833              int in_imgs_count;
2834              i_img **in_imgs;
2835              SV *sv1;
2836              IV tmp;
2837              int i;
2838              CODE:
2839
2840              in_imgs_count = av_len(av_in_imgs)+1;
2841              for (i = 0; i < in_imgs_count; ++i) {
2842                sv1 = *av_fetch(av_in_imgs, i, 0);
2843                if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2844                  croak("sv_in_img must contain only images");
2845                }
2846              }
2847              if (in_imgs_count > 0) {
2848                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2849                for (i = 0; i < in_imgs_count; ++i) {              
2850                  sv1 = *av_fetch(av_in_imgs,i,0);
2851                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2852                    croak("Parameter 5 must contain only images");
2853                  }
2854                  tmp = SvIV((SV*)SvRV(sv1));
2855                  in_imgs[i] = INT2PTR(i_img*, tmp);
2856                }
2857              }
2858              else {
2859                /* no input images */
2860                in_imgs = NULL;
2861              }
2862              /* default the output size from the first input if possible */
2863              if (SvOK(sv_width))
2864                width = SvIV(sv_width);
2865              else if (in_imgs_count)
2866                width = in_imgs[0]->xsize;
2867              else
2868                croak("No output image width supplied");
2869
2870              if (SvOK(sv_height))
2871                height = SvIV(sv_height);
2872              else if (in_imgs_count)
2873                height = in_imgs[0]->ysize;
2874              else
2875                croak("No output image height supplied");
2876
2877              ops = (struct rm_op *)SvPV(sv_ops, ops_len);
2878              if (ops_len % sizeof(struct rm_op))
2879                  croak("Imager: Parameter 3 must be a bitmap of regops\n");
2880              ops_count = ops_len / sizeof(struct rm_op);
2881
2882              n_regs_count = av_len(av_n_regs)+1;
2883              n_regs = mymalloc(n_regs_count * sizeof(double));
2884              for (i = 0; i < n_regs_count; ++i) {
2885                sv1 = *av_fetch(av_n_regs,i,0);
2886                if (SvOK(sv1))
2887                  n_regs[i] = SvNV(sv1);
2888              }
2889              c_regs_count = av_len(av_c_regs)+1;
2890              c_regs = mymalloc(c_regs_count * sizeof(i_color));
2891              /* I don't bother initializing the colou?r registers */
2892
2893              RETVAL=i_transform2(width, height, channels, ops, ops_count, 
2894                                  n_regs, n_regs_count, 
2895                                  c_regs, c_regs_count, in_imgs, in_imgs_count);
2896              if (in_imgs)
2897                  myfree(in_imgs);
2898              myfree(n_regs);
2899              myfree(c_regs);
2900              ST(0) = sv_newmortal();
2901              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2902              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2903
2904
2905 void
2906 i_contrast(im,intensity)
2907     Imager::ImgRaw     im
2908              float     intensity
2909
2910 void
2911 i_hardinvert(im)
2912     Imager::ImgRaw     im
2913
2914 void
2915 i_noise(im,amount,type)
2916     Imager::ImgRaw     im
2917              float     amount
2918      unsigned char     type
2919
2920 void
2921 i_bumpmap(im,bump,channel,light_x,light_y,strength)
2922     Imager::ImgRaw     im
2923     Imager::ImgRaw     bump
2924                int     channel
2925                int     light_x
2926                int     light_y
2927                int     strength
2928
2929
2930 void
2931 i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
2932     Imager::ImgRaw     im
2933     Imager::ImgRaw     bump
2934                int     channel
2935                int     tx
2936                int     ty
2937              float     Lx
2938              float     Ly
2939              float     Lz
2940              float     cd
2941              float     cs
2942              float     n
2943      Imager::Color     Ia
2944      Imager::Color     Il
2945      Imager::Color     Is
2946
2947
2948
2949 void
2950 i_postlevels(im,levels)
2951     Imager::ImgRaw     im
2952              int       levels
2953
2954 void
2955 i_mosaic(im,size)
2956     Imager::ImgRaw     im
2957                int     size
2958
2959 void
2960 i_watermark(im,wmark,tx,ty,pixdiff)
2961     Imager::ImgRaw     im
2962     Imager::ImgRaw     wmark
2963                int     tx
2964                int     ty
2965                int     pixdiff
2966
2967
2968 void
2969 i_autolevels(im,lsat,usat,skew)
2970     Imager::ImgRaw     im
2971              float     lsat
2972              float     usat
2973              float     skew
2974
2975 void
2976 i_radnoise(im,xo,yo,rscale,ascale)
2977     Imager::ImgRaw     im
2978              float     xo
2979              float     yo
2980              float     rscale
2981              float     ascale
2982
2983 void
2984 i_turbnoise(im, xo, yo, scale)
2985     Imager::ImgRaw     im
2986              float     xo
2987              float     yo
2988              float     scale
2989
2990
2991 void
2992 i_gradgen(im, ...)
2993     Imager::ImgRaw     im
2994       PREINIT:
2995         int num;
2996         int *xo;
2997         int *yo;
2998         i_color *ival;
2999         int dmeasure;
3000         int i;
3001         SV *sv;
3002         AV *axx;
3003         AV *ayy;
3004         AV *ac;
3005       CODE:
3006         if (items != 5)
3007             croak("Usage: i_gradgen(im, xo, yo, ival, dmeasure)");
3008         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3009             croak("i_gradgen: Second argument must be an array ref");
3010         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
3011             croak("i_gradgen: Third argument must be an array ref");
3012         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
3013             croak("i_gradgen: Fourth argument must be an array ref");
3014         axx = (AV *)SvRV(ST(1));
3015         ayy = (AV *)SvRV(ST(2));
3016         ac  = (AV *)SvRV(ST(3));
3017         dmeasure = (int)SvIV(ST(4));
3018         
3019         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
3020         num = num <= av_len(ac) ? num : av_len(ac);
3021         num++; 
3022         if (num < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each");
3023         xo = mymalloc( sizeof(int) * num );
3024         yo = mymalloc( sizeof(int) * num );
3025         ival = mymalloc( sizeof(i_color) * num );
3026         for(i = 0; i<num; i++) {
3027           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
3028           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
3029           sv = *av_fetch(ac, i, 0);
3030           if ( !sv_derived_from(sv, "Imager::Color") ) {
3031             free(axx); free(ayy); free(ac);
3032             croak("i_gradgen: Element of fourth argument is not derived from Imager::Color");
3033           }
3034           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
3035         }
3036         i_gradgen(im, num, xo, yo, ival, dmeasure);
3037         myfree(xo);
3038         myfree(yo);
3039         myfree(ival);
3040
3041 Imager::ImgRaw
3042 i_diff_image(im, im2, mindist=0)
3043     Imager::ImgRaw     im
3044     Imager::ImgRaw     im2
3045                int     mindist
3046
3047 void
3048 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
3049     Imager::ImgRaw     im
3050             double     xa
3051             double     ya
3052             double     xb
3053             double     yb
3054                int     type
3055                int     repeat
3056                int     combine
3057                int     super_sample
3058             double     ssample_param
3059       PREINIT:
3060         AV *asegs;
3061         int count;
3062         i_fountain_seg *segs;
3063       CODE:
3064         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
3065             croak("i_fountain: argument 11 must be an array ref");
3066         
3067         asegs = (AV *)SvRV(ST(10));
3068         segs = load_fount_segs(asegs, &count);
3069         i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, 
3070                    ssample_param, count, segs);
3071         myfree(segs);
3072
3073 Imager::FillHandle
3074 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
3075             double     xa
3076             double     ya
3077             double     xb
3078             double     yb
3079                int     type
3080                int     repeat
3081                int     combine
3082                int     super_sample
3083             double     ssample_param
3084       PREINIT:
3085         AV *asegs;
3086         int count;
3087         i_fountain_seg *segs;
3088       CODE:
3089         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
3090             croak("i_fountain: argument 11 must be an array ref");
3091         
3092         asegs = (AV *)SvRV(ST(9));
3093         segs = load_fount_segs(asegs, &count);
3094         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
3095                                   super_sample, ssample_param, count, segs);
3096         myfree(segs);        
3097       OUTPUT:
3098         RETVAL
3099
3100 void
3101 i_errors()
3102       PREINIT:
3103         i_errmsg *errors;
3104         int i;
3105         AV *av;
3106         SV *sv;
3107       PPCODE:
3108         errors = i_errors();
3109         i = 0;
3110         while (errors[i].msg) {
3111           av = newAV();
3112           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
3113           if (!av_store(av, 0, sv)) {
3114             SvREFCNT_dec(sv);
3115           }
3116           sv = newSViv(errors[i].code);
3117           if (!av_store(av, 1, sv)) {
3118             SvREFCNT_dec(sv);
3119           }
3120           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
3121           ++i;
3122         }
3123
3124 void
3125 i_nearest_color(im, ...)
3126     Imager::ImgRaw     im
3127       PREINIT:
3128         int num;
3129         int *xo;
3130         int *yo;
3131         i_color *ival;
3132         int dmeasure;
3133         int i;
3134         SV *sv;
3135         AV *axx;
3136         AV *ayy;
3137         AV *ac;
3138       CODE:
3139         if (items != 5)
3140             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
3141         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3142             croak("i_nearest_color: Second argument must be an array ref");
3143         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
3144             croak("i_nearest_color: Third argument must be an array ref");
3145         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
3146             croak("i_nearest_color: Fourth argument must be an array ref");
3147         axx = (AV *)SvRV(ST(1));
3148         ayy = (AV *)SvRV(ST(2));
3149         ac  = (AV *)SvRV(ST(3));
3150         dmeasure = (int)SvIV(ST(4));
3151         
3152         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
3153         num = num <= av_len(ac) ? num : av_len(ac);
3154         num++; 
3155         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
3156         xo = mymalloc( sizeof(int) * num );
3157         yo = mymalloc( sizeof(int) * num );
3158         ival = mymalloc( sizeof(i_color) * num );
3159         for(i = 0; i<num; i++) {
3160           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
3161           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
3162           sv = *av_fetch(ac, i, 0);
3163           if ( !sv_derived_from(sv, "Imager::Color") ) {
3164             free(axx); free(ayy); free(ac);
3165             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
3166           }
3167           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
3168         }
3169         i_nearest_color(im, num, xo, yo, ival, dmeasure);
3170
3171
3172
3173
3174 void
3175 malloc_state()
3176
3177 void
3178 hashinfo(hv)
3179              PREINIT:
3180                HV* hv;
3181                int stuff;
3182              PPCODE:
3183                if (!SvROK(ST(0))) croak("Imager: Parameter 0 must be a reference to a hash\n");        
3184                hv=(HV*)SvRV(ST(0));
3185                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 0 must be a reference to a hash\n");
3186                if (getint(hv,"stuff",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
3187                if (getint(hv,"stuff2",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
3188                
3189 void
3190 DSO_open(filename)
3191              char*       filename
3192              PREINIT:
3193                void *rc;
3194                char *evstr;
3195              PPCODE:
3196                rc=DSO_open(filename,&evstr);
3197                if (rc!=NULL) {
3198                  if (evstr!=NULL) {
3199                    EXTEND(SP,2); 
3200                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3201                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
3202                  } else {
3203                    EXTEND(SP,1);
3204                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3205                  }
3206                }
3207
3208
3209 undef_int
3210 DSO_close(dso_handle)
3211              void*       dso_handle
3212
3213 void
3214 DSO_funclist(dso_handle_v)
3215              void*       dso_handle_v
3216              PREINIT:
3217                int i;
3218                DSO_handle *dso_handle;
3219              PPCODE:
3220                dso_handle=(DSO_handle*)dso_handle_v;
3221                i=0;
3222                while( dso_handle->function_list[i].name != NULL) {
3223                  EXTEND(SP,1);
3224                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i].name,0)));
3225                  EXTEND(SP,1);
3226                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i++].pcode,0)));
3227                }
3228
3229
3230 void
3231 DSO_call(handle,func_index,hv)
3232                void*  handle
3233                int    func_index
3234              PREINIT:
3235                HV* hv;
3236              PPCODE:
3237                if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
3238                hv=(HV*)SvRV(ST(2));
3239                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
3240                DSO_call( (DSO_handle *)handle,func_index,hv);
3241
3242
3243
3244 SV *
3245 i_get_pixel(im, x, y)
3246         Imager::ImgRaw im
3247         int x
3248         int y;
3249       PREINIT:
3250         i_color *color;
3251       CODE:
3252         color = (i_color *)mymalloc(sizeof(i_color));
3253         if (i_gpix(im, x, y, color) == 0) {
3254           RETVAL = NEWSV(0, 0);
3255           sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
3256         }
3257         else {
3258           myfree(color);
3259           RETVAL = &PL_sv_undef;
3260         }
3261       OUTPUT:
3262         RETVAL
3263         
3264
3265 int
3266 i_ppix(im, x, y, cl)
3267         Imager::ImgRaw im
3268         int x
3269         int y
3270         Imager::Color cl
3271
3272 Imager::ImgRaw
3273 i_img_pal_new(x, y, channels, maxpal)
3274         int     x
3275         int     y
3276         int     channels
3277         int     maxpal
3278
3279 Imager::ImgRaw
3280 i_img_to_pal(src, quant)
3281         Imager::ImgRaw src
3282       PREINIT:
3283         HV *hv;
3284         i_quantize quant;
3285       CODE:
3286         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3287           croak("i_img_to_pal: second argument must be a hash ref");
3288         hv = (HV *)SvRV(ST(1));
3289         memset(&quant, 0, sizeof(quant));
3290         quant.mc_size = 256;
3291         handle_quant_opts(&quant, hv);
3292         RETVAL = i_img_to_pal(src, &quant);
3293         if (RETVAL) {
3294           copy_colors_back(hv, &quant);
3295         }
3296         cleanup_quant_opts(&quant);
3297       OUTPUT:
3298         RETVAL
3299
3300 Imager::ImgRaw
3301 i_img_to_rgb(src)
3302         Imager::ImgRaw src
3303
3304 void
3305 i_gpal(im, l, r, y)
3306         Imager::ImgRaw  im
3307         int     l
3308         int     r
3309         int     y
3310       PREINIT:
3311         i_palidx *work;
3312         int count, i;
3313       PPCODE:
3314         if (l < r) {
3315           work = mymalloc((r-l) * sizeof(i_palidx));
3316           count = i_gpal(im, l, r, y, work);
3317           if (GIMME_V == G_ARRAY) {
3318             EXTEND(SP, count);
3319             for (i = 0; i < count; ++i) {
3320               PUSHs(sv_2mortal(newSViv(work[i])));
3321             }
3322           }
3323           else {
3324             EXTEND(SP, 1);
3325             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3326           }
3327           myfree(work);
3328         }
3329         else {
3330           if (GIMME_V != G_ARRAY) {
3331             EXTEND(SP, 1);
3332             PUSHs(&PL_sv_undef);
3333           }
3334         }
3335
3336 int
3337 i_ppal(im, l, y, ...)
3338         Imager::ImgRaw  im
3339         int     l
3340         int     y
3341       PREINIT:
3342         i_palidx *work;
3343         int i;
3344       CODE:
3345         if (items > 3) {
3346           work = mymalloc(sizeof(i_palidx) * (items-3));
3347           for (i=0; i < items-3; ++i) {
3348             work[i] = SvIV(ST(i+3));
3349           }
3350           RETVAL = i_ppal(im, l, l+items-3, y, work);
3351           myfree(work);
3352         }
3353         else {
3354           RETVAL = 0;
3355         }
3356       OUTPUT:
3357         RETVAL
3358
3359 SV *
3360 i_addcolors(im, ...)
3361         Imager::ImgRaw  im
3362       PREINIT:
3363         int index;
3364         i_color *colors;
3365         int i;
3366       CODE:
3367         if (items < 2)
3368           croak("i_addcolors: no colors to add");
3369         colors = mymalloc((items-1) * sizeof(i_color));
3370         for (i=0; i < items-1; ++i) {
3371           if (sv_isobject(ST(i+1)) 
3372               && sv_derived_from(ST(i+1), "Imager::Color")) {
3373             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3374             colors[i] = *INT2PTR(i_color *, tmp);
3375           }
3376           else {
3377             myfree(colors);
3378             croak("i_addcolor: pixels must be Imager::Color objects");
3379           }
3380         }
3381         index = i_addcolors(im, colors, items-1);
3382         myfree(colors);
3383         if (index == 0) {
3384           RETVAL = newSVpv("0 but true", 0);
3385         }
3386         else if (index == -1) {
3387           RETVAL = &PL_sv_undef;
3388         }
3389         else {
3390           RETVAL = newSViv(index);
3391         }
3392       OUTPUT:
3393         RETVAL
3394
3395 undef_int 
3396 i_setcolors(im, index, ...)
3397         Imager::ImgRaw  im
3398         int index
3399       PREINIT:
3400         i_color *colors;
3401         int i;
3402       CODE:
3403         if (items < 3)
3404           croak("i_setcolors: no colors to add");
3405         colors = mymalloc((items-2) * sizeof(i_color));
3406         for (i=0; i < items-2; ++i) {
3407           if (sv_isobject(ST(i+2)) 
3408               && sv_derived_from(ST(i+2), "Imager::Color")) {
3409             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3410             colors[i] = *INT2PTR(i_color *, tmp);
3411           }
3412           else {
3413             myfree(colors);
3414             croak("i_setcolors: pixels must be Imager::Color objects");
3415           }
3416         }
3417         RETVAL = i_setcolors(im, index, colors, items-2);
3418         myfree(colors);
3419       OUTPUT:
3420         RETVAL
3421
3422 void
3423 i_getcolors(im, index, ...)
3424         Imager::ImgRaw im
3425         int index
3426       PREINIT:
3427         i_color *colors;
3428         int count = 1;
3429         int i;
3430       PPCODE:
3431         if (items > 3)
3432           croak("i_getcolors: too many arguments");
3433         if (items == 3)
3434           count = SvIV(ST(2));
3435         if (count < 1)
3436           croak("i_getcolors: count must be positive");
3437         colors = mymalloc(sizeof(i_color) * count);
3438         if (i_getcolors(im, index, colors, count)) {
3439           for (i = 0; i < count; ++i) {
3440             i_color *pv;
3441             SV *sv = sv_newmortal();
3442             pv = mymalloc(sizeof(i_color));
3443             *pv = colors[i];
3444             sv_setref_pv(sv, "Imager::Color", (void *)pv);
3445             PUSHs(sv);
3446           }
3447         }
3448         myfree(colors);
3449
3450
3451 undef_neg_int
3452 i_colorcount(im)
3453         Imager::ImgRaw im
3454
3455 undef_neg_int
3456 i_maxcolors(im)
3457         Imager::ImgRaw im
3458
3459 SV *
3460 i_findcolor(im, color)
3461         Imager::ImgRaw im
3462         Imager::Color color
3463       PREINIT:
3464         i_palidx index;
3465       CODE:
3466         if (i_findcolor(im, color, &index)) {
3467           RETVAL = newSViv(index);
3468         }
3469         else {
3470           RETVAL = &PL_sv_undef;
3471         }
3472       OUTPUT:
3473         RETVAL
3474
3475 int
3476 i_img_bits(im)
3477         Imager::ImgRaw  im
3478
3479 int
3480 i_img_type(im)
3481         Imager::ImgRaw  im
3482
3483 int
3484 i_img_virtual(im)
3485         Imager::ImgRaw  im
3486
3487 void
3488 i_gsamp(im, l, r, y, ...)
3489         Imager::ImgRaw im
3490         int l
3491         int r
3492         int y
3493       PREINIT:
3494         int *chans;
3495         int chan_count;
3496         i_sample_t *data;
3497         int count, i;
3498       PPCODE:
3499         if (items < 5)
3500           croak("No channel numbers supplied to g_samp()");
3501         if (l < r) {
3502           chan_count = items - 4;
3503           chans = mymalloc(sizeof(int) * chan_count);
3504           for (i = 0; i < chan_count; ++i)
3505             chans[i] = SvIV(ST(i+4));
3506           data = mymalloc(sizeof(i_sample_t) * (r-l) * chan_count); /* XXX: memleak? */
3507           count = i_gsamp(im, l, r, y, data, chans, chan_count);
3508           myfree(chans);
3509           if (GIMME_V == G_ARRAY) {
3510             EXTEND(SP, count);
3511             for (i = 0; i < count; ++i)
3512               PUSHs(sv_2mortal(newSViv(data[i])));
3513           }
3514           else {
3515             EXTEND(SP, 1);
3516             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3517           }
3518           myfree(data);
3519         }
3520         else {
3521           if (GIMME_V != G_ARRAY) {
3522             EXTEND(SP, 1);
3523             PUSHs(&PL_sv_undef);
3524           }
3525         }
3526
3527
3528 Imager::ImgRaw
3529 i_img_masked_new(targ, mask, x, y, w, h)
3530         Imager::ImgRaw targ
3531         int x
3532         int y
3533         int w
3534         int h
3535       PREINIT:
3536         i_img *mask;
3537       CODE:
3538         if (SvOK(ST(1))) {
3539           if (!sv_isobject(ST(1)) 
3540               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3541             croak("i_img_masked_new: parameter 2 must undef or an image");
3542           }
3543           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3544         }
3545         else
3546           mask = NULL;
3547         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3548       OUTPUT:
3549         RETVAL
3550
3551 int
3552 i_plin(im, l, y, ...)
3553         Imager::ImgRaw  im
3554         int     l
3555         int     y
3556       PREINIT:
3557         i_color *work;
3558         int i;
3559         STRLEN len;
3560         int count;
3561       CODE:
3562         if (items > 3) {
3563           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3564             /* supplied as a byte string */
3565             work = (i_color *)SvPV(ST(3), len);
3566             count = len / sizeof(i_color);
3567             if (count * sizeof(i_color) != len) {
3568               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3569             }
3570             RETVAL = i_plin(im, l, l+count, y, work);
3571           }
3572           else {
3573             work = mymalloc(sizeof(i_color) * (items-3));
3574             for (i=0; i < items-3; ++i) {
3575               if (sv_isobject(ST(i+3)) 
3576                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3577                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3578                 work[i] = *INT2PTR(i_color *, tmp);
3579               }
3580               else {
3581                 myfree(work);
3582                 croak("i_plin: pixels must be Imager::Color objects");
3583               }
3584             }
3585             RETVAL = i_plin(im, l, l+items-3, y, work);
3586             myfree(work);
3587           }
3588         }
3589         else {
3590           RETVAL = 0;
3591         }
3592       OUTPUT:
3593         RETVAL
3594
3595 int
3596 i_ppixf(im, x, y, cl)
3597         Imager::ImgRaw im
3598         int x
3599         int y
3600         Imager::Color::Float cl
3601
3602 void
3603 i_gsampf(im, l, r, y, ...)
3604         Imager::ImgRaw im
3605         int l
3606         int r
3607         int y
3608       PREINIT:
3609         int *chans;
3610         int chan_count;
3611         i_fsample_t *data;
3612         int count, i;
3613       PPCODE:
3614         if (items < 5)
3615           croak("No channel numbers supplied to g_sampf()");
3616         if (l < r) {
3617           chan_count = items - 4;
3618           chans = mymalloc(sizeof(int) * chan_count);
3619           for (i = 0; i < chan_count; ++i)
3620             chans[i] = SvIV(ST(i+4));
3621           data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count);
3622           count = i_gsampf(im, l, r, y, data, chans, chan_count);
3623           if (GIMME_V == G_ARRAY) {
3624             EXTEND(SP, count);
3625             for (i = 0; i < count; ++i)
3626               PUSHs(sv_2mortal(newSVnv(data[i])));
3627           }
3628           else {
3629             EXTEND(SP, 1);
3630             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3631           }
3632         }
3633         else {
3634           if (GIMME_V != G_ARRAY) {
3635             EXTEND(SP, 1);
3636             PUSHs(&PL_sv_undef);
3637           }
3638         }
3639
3640 int
3641 i_plinf(im, l, y, ...)
3642         Imager::ImgRaw  im
3643         int     l
3644         int     y
3645       PREINIT:
3646         i_fcolor *work;
3647         int i;
3648         STRLEN len;
3649         int count;
3650       CODE:
3651         if (items > 3) {
3652           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3653             /* supplied as a byte string */
3654             work = (i_fcolor *)SvPV(ST(3), len);
3655             count = len / sizeof(i_fcolor);
3656             if (count * sizeof(i_fcolor) != len) {
3657               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3658             }
3659             RETVAL = i_plinf(im, l, l+count, y, work);
3660           }
3661           else {
3662             work = mymalloc(sizeof(i_fcolor) * (items-3));
3663             for (i=0; i < items-3; ++i) {
3664               if (sv_isobject(ST(i+3)) 
3665                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3666                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3667                 work[i] = *INT2PTR(i_fcolor *, tmp);
3668               }
3669               else {
3670                 myfree(work);
3671                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3672               }
3673             }
3674             /**(char *)0 = 1;*/
3675             RETVAL = i_plinf(im, l, l+items-3, y, work);
3676             myfree(work);
3677           }
3678         }
3679         else {
3680           RETVAL = 0;
3681         }
3682       OUTPUT:
3683         RETVAL
3684
3685 SV *
3686 i_gpixf(im, x, y)
3687         Imager::ImgRaw im
3688         int x
3689         int y;
3690       PREINIT:
3691         i_fcolor *color;
3692       CODE:
3693         color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3694         if (i_gpixf(im, x, y, color) == 0) {
3695           RETVAL = NEWSV(0,0);
3696           sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
3697         }
3698         else {
3699           myfree(color);
3700           RETVAL = &PL_sv_undef;
3701         }
3702       OUTPUT:
3703         RETVAL
3704
3705 void
3706 i_glin(im, l, r, y)
3707         Imager::ImgRaw im
3708         int l
3709         int r
3710         int y
3711       PREINIT:
3712         i_color *vals;
3713         int count, i;
3714       PPCODE:
3715         if (l < r) {
3716           vals = mymalloc((r-l) * sizeof(i_color));
3717           count = i_glin(im, l, r, y, vals);
3718           if (GIMME_V == G_ARRAY) {
3719             EXTEND(SP, count);
3720             for (i = 0; i < count; ++i) {
3721               SV *sv;
3722               i_color *col = mymalloc(sizeof(i_color));
3723               *col = vals[i];
3724               sv = sv_newmortal();
3725               sv_setref_pv(sv, "Imager::Color", (void *)col);
3726               PUSHs(sv);
3727             }
3728           }
3729           else if (count) {
3730             EXTEND(SP, 1);
3731             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3732           }
3733           myfree(vals);
3734         }
3735
3736 void
3737 i_glinf(im, l, r, y)
3738         Imager::ImgRaw im
3739         int l
3740         int r
3741         int y
3742       PREINIT:
3743         i_fcolor *vals;
3744         int count, i;
3745       PPCODE:
3746         if (l < r) {
3747           vals = mymalloc((r-l) * sizeof(i_fcolor));
3748           count = i_glinf(im, l, r, y, vals);
3749           if (GIMME_V == G_ARRAY) {
3750             EXTEND(SP, count);
3751             for (i = 0; i < count; ++i) {
3752               SV *sv;
3753               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3754               *col = vals[i];
3755               sv = sv_newmortal();
3756               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3757               PUSHs(sv);
3758             }
3759           }
3760           else if (count) {
3761             EXTEND(SP, 1);
3762             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3763           }
3764           myfree(vals);
3765         }
3766
3767 Imager::ImgRaw
3768 i_img_16_new(x, y, ch)
3769         int x
3770         int y
3771         int ch
3772
3773 Imager::ImgRaw
3774 i_img_double_new(x, y, ch)
3775         int x
3776         int y
3777         int ch
3778
3779 undef_int
3780 i_tags_addn(im, name, code, idata)
3781         Imager::ImgRaw im
3782         int     code
3783         int     idata
3784       PREINIT:
3785         char *name;
3786         STRLEN len;
3787       CODE:
3788         if (SvOK(ST(1)))
3789           name = SvPV(ST(1), len);
3790         else
3791           name = NULL;
3792         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3793       OUTPUT:
3794         RETVAL
3795
3796 undef_int
3797 i_tags_add(im, name, code, data, idata)
3798         Imager::ImgRaw  im
3799         int code
3800         int idata
3801       PREINIT:
3802         char *name;
3803         char *data;
3804         STRLEN len;
3805       CODE:
3806         if (SvOK(ST(1)))
3807           name = SvPV(ST(1), len);
3808         else
3809           name = NULL;
3810         if (SvOK(ST(3)))
3811           data = SvPV(ST(3), len);
3812         else {
3813           data = NULL;
3814           len = 0;
3815         }
3816         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3817       OUTPUT:
3818         RETVAL
3819
3820 SV *
3821 i_tags_find(im, name, start)
3822         Imager::ImgRaw  im
3823         char *name
3824         int start
3825       PREINIT:
3826         int entry;
3827       CODE:
3828         if (i_tags_find(&im->tags, name, start, &entry)) {
3829           if (entry == 0)
3830             RETVAL = newSVpv("0 but true", 0);
3831           else
3832             RETVAL = newSViv(entry);
3833         } else {
3834           RETVAL = &PL_sv_undef;
3835         }
3836       OUTPUT:
3837         RETVAL
3838
3839 SV *
3840 i_tags_findn(im, code, start)
3841         Imager::ImgRaw  im
3842         int             code
3843         int             start
3844       PREINIT:
3845         int entry;
3846       CODE:
3847         if (i_tags_findn(&im->tags, code, start, &entry)) {
3848           if (entry == 0)
3849             RETVAL = newSVpv("0 but true", 0);
3850           else
3851             RETVAL = newSViv(entry);
3852         }
3853         else {
3854           RETVAL = &PL_sv_undef;
3855         }
3856       OUTPUT:
3857         RETVAL
3858
3859 int
3860 i_tags_delete(im, entry)
3861         Imager::ImgRaw  im
3862         int             entry
3863       CODE:
3864         RETVAL = i_tags_delete(&im->tags, entry);
3865       OUTPUT:
3866         RETVAL
3867
3868 int
3869 i_tags_delbyname(im, name)
3870         Imager::ImgRaw  im
3871         char *          name
3872       CODE:
3873         RETVAL = i_tags_delbyname(&im->tags, name);
3874       OUTPUT:
3875         RETVAL
3876
3877 int
3878 i_tags_delbycode(im, code)
3879         Imager::ImgRaw  im
3880         int             code
3881       CODE:
3882         RETVAL = i_tags_delbycode(&im->tags, code);
3883       OUTPUT:
3884         RETVAL
3885
3886 void
3887 i_tags_get(im, index)
3888         Imager::ImgRaw  im
3889         int             index
3890       PPCODE:
3891         if (index >= 0 && index < im->tags.count) {
3892           i_img_tag *entry = im->tags.tags + index;
3893           EXTEND(SP, 5);
3894         
3895           if (entry->name) {
3896             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3897           }
3898           else {
3899             PUSHs(sv_2mortal(newSViv(entry->code)));
3900           }
3901           if (entry->data) {
3902             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3903           }
3904           else {
3905             PUSHs(sv_2mortal(newSViv(entry->idata)));
3906           }
3907         }
3908
3909 void
3910 i_tags_get_string(im, what_sv)
3911         Imager::ImgRaw  im
3912         SV *what_sv
3913       PREINIT:
3914         char const *name = NULL;
3915         int code;
3916         char buffer[200];
3917       PPCODE:
3918         if (SvIOK(what_sv)) {
3919           code = SvIV(what_sv);
3920           name = NULL;
3921         }
3922         else {
3923           name = SvPV_nolen(what_sv);
3924           code = 0;
3925         }
3926         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
3927           EXTEND(SP, 1);
3928           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
3929         }
3930
3931 int
3932 i_tags_count(im)
3933         Imager::ImgRaw  im
3934       CODE:
3935         RETVAL = im->tags.count;
3936       OUTPUT:
3937         RETVAL
3938
3939 #ifdef HAVE_WIN32
3940
3941 void
3942 i_wf_bbox(face, size, text)
3943         char *face
3944         int size
3945         char *text
3946       PREINIT:
3947         int cords[BOUNDING_BOX_COUNT];
3948         int rc, i;
3949       PPCODE:
3950         if (rc = i_wf_bbox(face, size, text, strlen(text), cords)) {
3951           EXTEND(SP, rc);  
3952           for (i = 0; i < rc; ++i) 
3953             PUSHs(sv_2mortal(newSViv(cords[i])));
3954         }
3955
3956 undef_int
3957 i_wf_text(face, im, tx, ty, cl, size, text, align, aa)
3958         char *face
3959         Imager::ImgRaw im
3960         int tx
3961         int ty
3962         Imager::Color cl
3963         int size
3964         char *text
3965         int align
3966         int aa
3967       CODE:
3968         RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text), 
3969                            align, aa);
3970       OUTPUT:
3971         RETVAL
3972
3973 undef_int
3974 i_wf_cp(face, im, tx, ty, channel, size, text, align, aa)
3975         char *face
3976         Imager::ImgRaw im
3977         int tx
3978         int ty
3979         int channel
3980         int size
3981         char *text
3982         int align
3983         int aa
3984       CODE:
3985         RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text), 
3986                          align, aa);
3987       OUTPUT:
3988         RETVAL
3989
3990 undef_int
3991 i_wf_addfont(font)
3992         char *font
3993
3994 #endif
3995
3996 #ifdef HAVE_FT2
3997
3998 MODULE = Imager         PACKAGE = Imager::Font::FT2     PREFIX=FT2_
3999
4000 #define FT2_DESTROY(font) i_ft2_destroy(font)
4001
4002 void
4003 FT2_DESTROY(font)
4004         Imager::Font::FT2 font
4005
4006 MODULE = Imager         PACKAGE = Imager::Font::FreeType2 
4007
4008 Imager::Font::FT2
4009 i_ft2_new(name, index)
4010         char *name
4011         int index
4012
4013 undef_int
4014 i_ft2_setdpi(font, xdpi, ydpi)
4015         Imager::Font::FT2 font
4016         int xdpi
4017         int ydpi
4018
4019 void
4020 i_ft2_getdpi(font)
4021         Imager::Font::FT2 font
4022       PREINIT:
4023         int xdpi, ydpi;
4024       CODE:
4025         if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
4026           EXTEND(SP, 2);
4027           PUSHs(sv_2mortal(newSViv(xdpi)));
4028           PUSHs(sv_2mortal(newSViv(ydpi)));
4029         }
4030
4031 undef_int
4032 i_ft2_sethinting(font, hinting)
4033         Imager::Font::FT2 font
4034         int hinting
4035
4036 undef_int
4037 i_ft2_settransform(font, matrix)
4038         Imager::Font::FT2 font
4039       PREINIT:
4040         double matrix[6];
4041         int len;
4042         AV *av;
4043         SV *sv1;
4044         int i;
4045       CODE:
4046         if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4047           croak("i_ft2_settransform: parameter 2 must be an array ref\n");
4048         av=(AV*)SvRV(ST(1));
4049         len=av_len(av)+1;
4050         if (len > 6)
4051           len = 6;
4052         for (i = 0; i < len; ++i) {
4053           sv1=(*(av_fetch(av,i,0)));
4054           matrix[i] = SvNV(sv1);
4055         }
4056         for (; i < 6; ++i)
4057           matrix[i] = 0;
4058         RETVAL = i_ft2_settransform(font, matrix);
4059       OUTPUT:
4060         RETVAL
4061
4062 void
4063 i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
4064         Imager::Font::FT2 font
4065         double cheight
4066         double cwidth
4067         SV *text_sv
4068         int utf8
4069       PREINIT:
4070         int bbox[BOUNDING_BOX_COUNT];
4071         int i;
4072         char *text;
4073         STRLEN text_len;
4074         int rc;
4075       PPCODE:
4076         text = SvPV(text_sv, text_len);
4077 #ifdef SvUTF8
4078         if (SvUTF8(text_sv))
4079           utf8 = 1;
4080 #endif
4081         rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8);
4082         if (rc) {
4083           EXTEND(SP, rc);
4084           for (i = 0; i < rc; ++i)
4085             PUSHs(sv_2mortal(newSViv(bbox[i])));
4086         }
4087
4088 void
4089 i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
4090         Imager::Font::FT2 font
4091         double cheight
4092         double cwidth
4093         char *text
4094         int vlayout
4095         int utf8
4096       PREINIT:
4097         int bbox[8];
4098         int i;
4099       PPCODE:
4100 #ifdef SvUTF8
4101         if (SvUTF8(ST(3)))
4102           utf8 = 1;
4103 #endif
4104         if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
4105                          utf8, bbox)) {
4106           EXTEND(SP, 8);
4107           for (i = 0; i < 8; ++i)
4108             PUSHs(sv_2mortal(newSViv(bbox[i])));
4109         }
4110
4111 undef_int
4112 i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
4113         Imager::Font::FT2 font
4114         Imager::ImgRaw im
4115         int tx
4116         int ty
4117         Imager::Color cl
4118         double cheight
4119         double cwidth
4120         int align
4121         int aa
4122         int vlayout
4123         int utf8
4124       PREINIT:
4125         char *text;
4126         STRLEN len;
4127       CODE:
4128 #ifdef SvUTF8
4129         if (SvUTF8(ST(7))) {
4130           utf8 = 1;
4131         }
4132 #endif
4133         text = SvPV(ST(7), len);
4134         RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
4135                             len, align, aa, vlayout, utf8);
4136       OUTPUT:
4137         RETVAL
4138
4139 undef_int
4140 i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8)
4141         Imager::Font::FT2 font
4142         Imager::ImgRaw im
4143         int tx
4144         int ty
4145         int channel
4146         double cheight
4147         double cwidth
4148         char *text
4149         int align
4150         int aa
4151         int vlayout
4152         int utf8
4153       CODE:
4154 #ifdef SvUTF8
4155         if (SvUTF8(ST(7)))
4156           utf8 = 1;
4157 #endif
4158         RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
4159                           strlen(text), align, aa, vlayout, 1);
4160       OUTPUT:
4161         RETVAL
4162
4163 void
4164 ft2_transform_box(font, x0, x1, x2, x3)
4165         Imager::Font::FT2 font
4166         int x0
4167         int x1
4168         int x2
4169         int x3
4170       PREINIT:
4171         int box[4];
4172       PPCODE:
4173         box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
4174         ft2_transform_box(font, box);
4175           EXTEND(SP, 4);
4176           PUSHs(sv_2mortal(newSViv(box[0])));
4177           PUSHs(sv_2mortal(newSViv(box[1])));
4178           PUSHs(sv_2mortal(newSViv(box[2])));
4179           PUSHs(sv_2mortal(newSViv(box[3])));
4180
4181 void
4182 i_ft2_has_chars(handle, text_sv, utf8)
4183         Imager::Font::FT2 handle
4184         SV  *text_sv
4185         int utf8
4186       PREINIT:
4187         char *text;
4188         STRLEN len;
4189         char *work;
4190         int count;
4191         int i;
4192       PPCODE:
4193 #ifdef SvUTF8
4194         if (SvUTF8(text_sv))
4195           utf8 = 1;
4196 #endif
4197         text = SvPV(text_sv, len);
4198         work = mymalloc(len);
4199         count = i_ft2_has_chars(handle, text, len, utf8, work);
4200         if (GIMME_V == G_ARRAY) {
4201           EXTEND(SP, count);
4202           for (i = 0; i < count; ++i) {
4203             PUSHs(sv_2mortal(newSViv(work[i])));
4204           }
4205         }
4206         else {
4207           EXTEND(SP, 1);
4208           PUSHs(sv_2mortal(newSVpv(work, count)));
4209         }
4210         myfree(work);
4211
4212 void
4213 i_ft2_face_name(handle)
4214         Imager::Font::FT2 handle
4215       PREINIT:
4216         char name[255];
4217         int len;
4218       PPCODE:
4219         len = i_ft2_face_name(handle, name, sizeof(name));
4220         if (len) {
4221           EXTEND(SP, 1);
4222           PUSHs(sv_2mortal(newSVpv(name, 0)));
4223         }
4224
4225 undef_int
4226 i_ft2_can_face_name()
4227
4228 void
4229 i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
4230         Imager::Font::FT2 handle
4231         SV *text_sv
4232         int utf8
4233         int reliable_only
4234       PREINIT:
4235         char const *text;
4236         STRLEN work_len;
4237         int len;
4238         int outsize;
4239         char name[255];
4240       PPCODE:
4241 #ifdef SvUTF8
4242         if (SvUTF8(text_sv))
4243           utf8 = 1;
4244 #endif
4245         text = SvPV(text_sv, work_len);
4246         len = work_len;
4247         while (len) {
4248           unsigned long ch;
4249           if (utf8) {
4250             ch = i_utf8_advance(&text, &len);
4251             if (ch == ~0UL) {
4252               i_push_error(0, "invalid UTF8 character");
4253               break;
4254             }
4255           }
4256           else {
4257             ch = *text++;
4258             --len;
4259           }
4260           EXTEND(SP, 1);
4261           if (outsize = i_ft2_glyph_name(handle, ch, name, sizeof(name), 
4262                                          reliable_only)) {
4263             PUSHs(sv_2mortal(newSVpv(name, 0)));
4264           }
4265           else {
4266             PUSHs(&PL_sv_undef);
4267           } 
4268         }
4269
4270 int
4271 i_ft2_can_do_glyph_names()
4272
4273 int
4274 i_ft2_face_has_glyph_names(handle)
4275         Imager::Font::FT2 handle
4276
4277 int
4278 i_ft2_is_multiple_master(handle)
4279         Imager::Font::FT2 handle
4280
4281 void
4282 i_ft2_get_multiple_masters(handle)
4283         Imager::Font::FT2 handle
4284       PREINIT:
4285         i_font_mm mm;
4286         int i;
4287       PPCODE:
4288         if (i_ft2_get_multiple_masters(handle, &mm)) {
4289           EXTEND(SP, 2+mm.num_axis);
4290           PUSHs(sv_2mortal(newSViv(mm.num_axis)));
4291           PUSHs(sv_2mortal(newSViv(mm.num_designs)));
4292           for (i = 0; i < mm.num_axis; ++i) {
4293             AV *av = newAV();
4294             SV *sv;
4295             av_extend(av, 3);
4296             sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name));
4297             SvREFCNT_inc(sv);
4298             av_store(av, 0, sv);
4299             sv = newSViv(mm.axis[i].minimum);
4300             SvREFCNT_inc(sv);
4301             av_store(av, 1, sv);
4302             sv = newSViv(mm.axis[i].maximum);
4303             SvREFCNT_inc(sv);
4304             av_store(av, 2, sv);
4305             PUSHs(newRV_noinc((SV *)av));
4306           }
4307         }
4308
4309 undef_int
4310 i_ft2_set_mm_coords(handle, ...)
4311         Imager::Font::FT2 handle
4312       PROTOTYPE: DISABLE
4313       PREINIT:
4314         long *coords;
4315         int ix_coords, i;
4316       CODE:
4317         /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so
4318            transfer the array manually */
4319         ix_coords = items-1;
4320         coords = mymalloc(sizeof(long) * ix_coords);
4321         for (i = 0; i < ix_coords; ++i) {
4322           coords[i] = (long)SvIV(ST(1+i));
4323         }
4324         RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords);
4325         myfree(coords);
4326       OUTPUT:
4327         RETVAL
4328
4329 #endif
4330
4331 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
4332
4333 void
4334 IFILL_DESTROY(fill)
4335         Imager::FillHandle fill
4336
4337 MODULE = Imager         PACKAGE = Imager
4338
4339 Imager::FillHandle
4340 i_new_fill_solid(cl, combine)
4341         Imager::Color cl
4342         int combine
4343
4344 Imager::FillHandle
4345 i_new_fill_solidf(cl, combine)
4346         Imager::Color::Float cl
4347         int combine
4348
4349 Imager::FillHandle
4350 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
4351         Imager::Color fg
4352         Imager::Color bg
4353         int combine
4354         int hatch
4355         int dx
4356         int dy
4357       PREINIT:
4358         unsigned char *cust_hatch;
4359         STRLEN len;
4360       CODE:
4361         if (SvOK(ST(4))) {
4362           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4363         }
4364         else
4365           cust_hatch = NULL;
4366         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
4367       OUTPUT:
4368         RETVAL
4369
4370 Imager::FillHandle
4371 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
4372         Imager::Color::Float fg
4373         Imager::Color::Float bg
4374         int combine
4375         int hatch
4376         int dx
4377         int dy
4378       PREINIT:
4379         unsigned char *cust_hatch;
4380         STRLEN len;
4381       CODE:
4382         if (SvOK(ST(4))) {
4383           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4384         }
4385         else
4386           cust_hatch = NULL;
4387         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
4388       OUTPUT:
4389         RETVAL
4390
4391 Imager::FillHandle
4392 i_new_fill_image(src, matrix, xoff, yoff, combine)
4393         Imager::ImgRaw src
4394         int xoff
4395         int yoff
4396         int combine
4397       PREINIT:
4398         double matrix[9];
4399         double *matrixp;
4400         AV *av;
4401         IV len;
4402         SV *sv1;
4403         int i;
4404       CODE:
4405         if (!SvOK(ST(1))) {
4406           matrixp = NULL;
4407         }
4408         else {
4409           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4410             croak("i_new_fill_image: parameter must be an arrayref");
4411           av=(AV*)SvRV(ST(1));
4412           len=av_len(av)+1;
4413           if (len > 9)
4414             len = 9;
4415           for (i = 0; i < len; ++i) {
4416             sv1=(*(av_fetch(av,i,0)));
4417             matrix[i] = SvNV(sv1);
4418           }
4419           for (; i < 9; ++i)
4420             matrix[i] = 0;
4421           matrixp = matrix;
4422         }
4423         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4424       OUTPUT:
4425         RETVAL
4426