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