hide or rename any symbols that are likely to conflict with other
[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(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 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 ? sv_2mortal(newSVpv(im->idata, im->bytes)) 
1248                      : &PL_sv_undef);
1249
1250
1251 void
1252 i_draw(im,x1,y1,x2,y2,val)
1253     Imager::ImgRaw     im
1254                int     x1
1255                int     y1
1256                int     x2
1257                int     y2
1258      Imager::Color     val
1259
1260 void
1261 i_line_aa(im,x1,y1,x2,y2,val)
1262     Imager::ImgRaw     im
1263                int     x1
1264                int     y1
1265                int     x2
1266                int     y2
1267      Imager::Color     val
1268
1269 void
1270 i_box(im,x1,y1,x2,y2,val)
1271     Imager::ImgRaw     im
1272                int     x1
1273                int     y1
1274                int     x2
1275                int     y2
1276      Imager::Color     val
1277
1278 void
1279 i_box_filled(im,x1,y1,x2,y2,val)
1280     Imager::ImgRaw     im
1281                int     x1
1282                int     y1
1283                int     x2
1284                int     y2
1285            Imager::Color    val
1286
1287 void
1288 i_box_cfill(im,x1,y1,x2,y2,fill)
1289     Imager::ImgRaw     im
1290                int     x1
1291                int     y1
1292                int     x2
1293                int     y2
1294            Imager::FillHandle    fill
1295
1296 void
1297 i_arc(im,x,y,rad,d1,d2,val)
1298     Imager::ImgRaw     im
1299                int     x
1300                int     y
1301              float     rad
1302              float     d1
1303              float     d2
1304            Imager::Color    val
1305
1306 void
1307 i_arc_cfill(im,x,y,rad,d1,d2,fill)
1308     Imager::ImgRaw     im
1309                int     x
1310                int     y
1311              float     rad
1312              float     d1
1313              float     d2
1314            Imager::FillHandle    fill
1315
1316
1317
1318 void
1319 i_circle_aa(im,x,y,rad,val)
1320     Imager::ImgRaw     im
1321              float     x
1322              float     y
1323              float     rad
1324            Imager::Color    val
1325
1326
1327
1328 void
1329 i_bezier_multi(im,xc,yc,val)
1330     Imager::ImgRaw     im
1331              Imager::Color  val
1332              PREINIT:
1333              double   *x,*y;
1334              int       len;
1335              AV       *av1;
1336              AV       *av2;
1337              SV       *sv1;
1338              SV       *sv2;
1339              int i;
1340              PPCODE:
1341              ICL_info(val);
1342              if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
1343              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
1344              if (!SvROK(ST(2))) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
1345              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
1346              av1=(AV*)SvRV(ST(1));
1347              av2=(AV*)SvRV(ST(2));
1348              if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
1349              len=av_len(av1)+1;
1350              x=mymalloc( len*sizeof(double) );
1351              y=mymalloc( len*sizeof(double) );
1352              for(i=0;i<len;i++) {
1353                sv1=(*(av_fetch(av1,i,0)));
1354                sv2=(*(av_fetch(av2,i,0)));
1355                x[i]=(double)SvNV(sv1);
1356                y[i]=(double)SvNV(sv2);
1357              }
1358              i_bezier_multi(im,len,x,y,val);
1359              myfree(x);
1360              myfree(y);
1361
1362
1363 void
1364 i_poly_aa(im,xc,yc,val)
1365     Imager::ImgRaw     im
1366              Imager::Color  val
1367              PREINIT:
1368              double   *x,*y;
1369              int       len;
1370              AV       *av1;
1371              AV       *av2;
1372              SV       *sv1;
1373              SV       *sv2;
1374              int i;
1375              PPCODE:
1376              ICL_info(val);
1377              if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1378              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1379              if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1380              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1381              av1=(AV*)SvRV(ST(1));
1382              av2=(AV*)SvRV(ST(2));
1383              if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_poly_aa must be equal length\n");
1384              len=av_len(av1)+1;
1385              x=mymalloc( len*sizeof(double) );
1386              y=mymalloc( len*sizeof(double) );
1387              for(i=0;i<len;i++) {
1388                sv1=(*(av_fetch(av1,i,0)));
1389                sv2=(*(av_fetch(av2,i,0)));
1390                x[i]=(double)SvNV(sv1);
1391                y[i]=(double)SvNV(sv2);
1392              }
1393              i_poly_aa(im,len,x,y,val);
1394              myfree(x);
1395              myfree(y);
1396
1397 void
1398 i_poly_aa_cfill(im,xc,yc,fill)
1399     Imager::ImgRaw     im
1400      Imager::FillHandle     fill
1401              PREINIT:
1402              double   *x,*y;
1403              int       len;
1404              AV       *av1;
1405              AV       *av2;
1406              SV       *sv1;
1407              SV       *sv2;
1408              int i;
1409              PPCODE:
1410              if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1411              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1412              if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1413              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1414              av1=(AV*)SvRV(ST(1));
1415              av2=(AV*)SvRV(ST(2));
1416              if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n");
1417              len=av_len(av1)+1;
1418              x=mymalloc( len*sizeof(double) );
1419              y=mymalloc( len*sizeof(double) );
1420              for(i=0;i<len;i++) {
1421                sv1=(*(av_fetch(av1,i,0)));
1422                sv2=(*(av_fetch(av2,i,0)));
1423                x[i]=(double)SvNV(sv1);
1424                y[i]=(double)SvNV(sv2);
1425              }
1426              i_poly_aa_cfill(im,len,x,y,fill);
1427              myfree(x);
1428              myfree(y);
1429
1430
1431
1432 void
1433 i_flood_fill(im,seedx,seedy,dcol)
1434     Imager::ImgRaw     im
1435                int     seedx
1436                int     seedy
1437      Imager::Color     dcol
1438
1439 void
1440 i_flood_cfill(im,seedx,seedy,fill)
1441     Imager::ImgRaw     im
1442                int     seedx
1443                int     seedy
1444      Imager::FillHandle     fill
1445
1446
1447 void
1448 i_copyto(im,src,x1,y1,x2,y2,tx,ty)
1449     Imager::ImgRaw     im
1450     Imager::ImgRaw     src
1451                int     x1
1452                int     y1
1453                int     x2
1454                int     y2
1455                int     tx
1456                int     ty
1457
1458
1459 void
1460 i_copyto_trans(im,src,x1,y1,x2,y2,tx,ty,trans)
1461     Imager::ImgRaw     im
1462     Imager::ImgRaw     src
1463                int     x1
1464                int     y1
1465                int     x2
1466                int     y2
1467                int     tx
1468                int     ty
1469      Imager::Color     trans
1470
1471 void
1472 i_copy(im,src)
1473     Imager::ImgRaw     im
1474     Imager::ImgRaw     src
1475
1476
1477 undef_int
1478 i_rubthru(im,src,tx,ty)
1479     Imager::ImgRaw     im
1480     Imager::ImgRaw     src
1481                int     tx
1482                int     ty
1483
1484 undef_int
1485 i_flipxy(im, direction)
1486     Imager::ImgRaw     im
1487                int     direction
1488
1489 Imager::ImgRaw
1490 i_rotate90(im, degrees)
1491     Imager::ImgRaw      im
1492                int      degrees
1493
1494 Imager::ImgRaw
1495 i_rotate_exact(im, amount)
1496     Imager::ImgRaw      im
1497             double      amount
1498
1499 Imager::ImgRaw
1500 i_matrix_transform(im, xsize, ysize, matrix)
1501     Imager::ImgRaw      im
1502                int      xsize
1503                int      ysize
1504       PREINIT:
1505         double matrix[9];
1506         AV *av;
1507         IV len;
1508         SV *sv1;
1509         int i;
1510       CODE:
1511         if (!SvROK(ST(3)) || SvTYPE(SvRV(ST(3))) != SVt_PVAV)
1512           croak("i_matrix_transform: parameter 4 must be an array ref\n");
1513         av=(AV*)SvRV(ST(3));
1514         len=av_len(av)+1;
1515         if (len > 9)
1516           len = 9;
1517         for (i = 0; i < len; ++i) {
1518           sv1=(*(av_fetch(av,i,0)));
1519           matrix[i] = SvNV(sv1);
1520         }
1521         for (; i < 9; ++i)
1522           matrix[i] = 0;
1523         RETVAL = i_matrix_transform(im, xsize, ysize, matrix);        
1524       OUTPUT:
1525         RETVAL
1526
1527 void
1528 i_gaussian(im,stdev)
1529     Imager::ImgRaw     im
1530              float     stdev
1531
1532 void
1533 i_unsharp_mask(im,stdev,scale)
1534     Imager::ImgRaw     im
1535              float     stdev
1536              double    scale
1537
1538 void
1539 i_conv(im,pcoef)
1540     Imager::ImgRaw     im
1541              PREINIT:
1542              float*    coeff;
1543              int     len;
1544              AV* av;
1545              SV* sv1;
1546              int i;
1547              PPCODE:
1548              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
1549              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
1550              av=(AV*)SvRV(ST(1));
1551              len=av_len(av)+1;
1552              coeff=mymalloc( len*sizeof(float) );
1553              for(i=0;i<len;i++) {
1554                sv1=(*(av_fetch(av,i,0)));
1555                coeff[i]=(float)SvNV(sv1);
1556              }
1557              i_conv(im,coeff,len);
1558              myfree(coeff);
1559
1560 undef_int
1561 i_convert(im, src, coeff)
1562     Imager::ImgRaw     im
1563     Imager::ImgRaw     src
1564         PREINIT:
1565           float *coeff;
1566           int outchan;
1567           int inchan;
1568           AV *avmain;
1569           SV **temp;
1570           SV *svsub;
1571           AV *avsub;
1572           int len;
1573           int i, j;
1574         CODE:
1575           if (!SvROK(ST(2)) || SvTYPE(SvRV(ST(2))) != SVt_PVAV)
1576             croak("i_convert: parameter 3 must be an arrayref\n");
1577           avmain = (AV*)SvRV(ST(2));
1578           outchan = av_len(avmain)+1;
1579           /* find the biggest */
1580           inchan = 0;
1581           for (j=0; j < outchan; ++j) {
1582             temp = av_fetch(avmain, j, 0);
1583             if (temp && SvROK(*temp) && SvTYPE(SvRV(*temp)) == SVt_PVAV) {
1584               avsub = (AV*)SvRV(*temp);
1585               len = av_len(avsub)+1;
1586               if (len > inchan)
1587                 inchan = len;
1588             }
1589           }
1590           coeff = mymalloc(sizeof(float) * outchan * inchan);
1591           for (j = 0; j < outchan; ++j) {
1592             avsub = (AV*)SvRV(*av_fetch(avmain, j, 0));
1593             len = av_len(avsub)+1;
1594             for (i = 0; i < len; ++i) {
1595               temp = av_fetch(avsub, i, 0);
1596               if (temp)
1597                 coeff[i+j*inchan] = SvNV(*temp);
1598               else
1599                 coeff[i+j*inchan] = 0;
1600             }
1601             while (i < inchan)
1602               coeff[i++ + j*inchan] = 0;
1603           }
1604           RETVAL = i_convert(im, src, coeff, outchan, inchan);
1605           myfree(coeff);
1606         OUTPUT:
1607           RETVAL
1608
1609
1610 void
1611 i_map(im, pmaps)
1612     Imager::ImgRaw     im
1613         PREINIT:
1614           unsigned int mask = 0;
1615           AV *avmain;
1616           AV *avsub;
1617           SV **temp;
1618           int len;
1619           int i, j;
1620           unsigned char (*maps)[256];
1621         CODE:
1622           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
1623             croak("i_map: parameter 2 must be an arrayref\n");
1624           avmain = (AV*)SvRV(ST(1));
1625           len = av_len(avmain)+1;
1626           if (im->channels < len) len = im->channels;
1627
1628           maps = mymalloc( len * sizeof(unsigned char [256]) );
1629
1630           for (j=0; j<len ; j++) {
1631             temp = av_fetch(avmain, j, 0);
1632             if (temp && SvROK(*temp) && (SvTYPE(SvRV(*temp)) == SVt_PVAV) ) {
1633               avsub = (AV*)SvRV(*temp);
1634               if(av_len(avsub) != 255) continue;
1635               mask |= 1<<j;
1636               for (i=0; i<256 ; i++) {
1637                 int val;
1638                 temp = av_fetch(avsub, i, 0);
1639                 val = temp ? SvIV(*temp) : 0;
1640                 if (val<0) val = 0;
1641                 if (val>255) val = 255;
1642                 maps[j][i] = val;
1643               }
1644             }
1645           }
1646           i_map(im, maps, mask);
1647           myfree(maps);
1648
1649
1650
1651 float
1652 i_img_diff(im1,im2)
1653     Imager::ImgRaw     im1
1654     Imager::ImgRaw     im2
1655
1656
1657
1658 undef_int         
1659 i_init_fonts(t1log=0)
1660     int t1log
1661
1662 #ifdef HAVE_LIBT1
1663
1664 void
1665 i_t1_set_aa(st)
1666                int     st
1667
1668 int
1669 i_t1_new(pfb,afm)
1670               char*    pfb
1671               char*    afm
1672
1673 int
1674 i_t1_destroy(font_id)
1675                int     font_id
1676
1677
1678 undef_int
1679 i_t1_cp(im,xb,yb,channel,fontnum,points,str,len,align)
1680     Imager::ImgRaw     im
1681                int     xb
1682                int     yb
1683                int     channel
1684                int     fontnum
1685              float     points
1686               char*    str
1687                int     len
1688                int     align
1689
1690 void
1691 i_t1_bbox(fontnum,point,str,len)
1692                int     fontnum
1693              float     point
1694               char*    str
1695                int     len
1696              PREINIT:
1697                int     cords[6];
1698              PPCODE:
1699                i_t1_bbox(fontnum,point,str,len,cords);
1700                EXTEND(SP, 4);
1701                PUSHs(sv_2mortal(newSViv(cords[0])));
1702                PUSHs(sv_2mortal(newSViv(cords[1])));
1703                PUSHs(sv_2mortal(newSViv(cords[2])));
1704                PUSHs(sv_2mortal(newSViv(cords[3])));
1705                PUSHs(sv_2mortal(newSViv(cords[4])));
1706                PUSHs(sv_2mortal(newSViv(cords[5])));
1707
1708
1709
1710 undef_int
1711 i_t1_text(im,xb,yb,cl,fontnum,points,str,len,align)
1712     Imager::ImgRaw     im
1713                int     xb
1714                int     yb
1715      Imager::Color    cl
1716                int     fontnum
1717              float     points
1718               char*    str
1719                int     len
1720                int     align
1721
1722 #endif 
1723
1724 #ifdef HAVE_LIBTT
1725
1726
1727 Imager::Font::TT
1728 i_tt_new(fontname)
1729               char*     fontname
1730
1731
1732 MODULE = Imager         PACKAGE = Imager::Font::TT      PREFIX=TT_
1733
1734 #define TT_DESTROY(handle) i_tt_destroy(handle)
1735
1736 void
1737 TT_DESTROY(handle)
1738      Imager::Font::TT   handle
1739
1740
1741 MODULE = Imager         PACKAGE = Imager
1742
1743
1744 undef_int
1745 i_tt_text(handle,im,xb,yb,cl,points,str,len,smooth)
1746   Imager::Font::TT     handle
1747     Imager::ImgRaw     im
1748                int     xb
1749                int     yb
1750      Imager::Color     cl
1751              float     points
1752               char*    str
1753                int     len
1754                int     smooth
1755
1756
1757 undef_int
1758 i_tt_cp(handle,im,xb,yb,channel,points,str,len,smooth)
1759   Imager::Font::TT     handle
1760     Imager::ImgRaw     im
1761                int     xb
1762                int     yb
1763                int     channel
1764              float     points
1765               char*    str
1766                int     len
1767                int     smooth
1768
1769
1770
1771 undef_int
1772 i_tt_bbox(handle,point,str,len)
1773   Imager::Font::TT     handle
1774              float     point
1775               char*    str
1776                int     len
1777              PREINIT:
1778                int     cords[6],rc;
1779              PPCODE:
1780                if ((rc=i_tt_bbox(handle,point,str,len,cords))) {
1781                  EXTEND(SP, 4);
1782                  PUSHs(sv_2mortal(newSViv(cords[0])));
1783                  PUSHs(sv_2mortal(newSViv(cords[1])));
1784                  PUSHs(sv_2mortal(newSViv(cords[2])));
1785                  PUSHs(sv_2mortal(newSViv(cords[3])));
1786                  PUSHs(sv_2mortal(newSViv(cords[4])));
1787                  PUSHs(sv_2mortal(newSViv(cords[5])));
1788                }
1789
1790
1791 #endif 
1792
1793
1794
1795
1796 #ifdef HAVE_LIBJPEG
1797 undef_int
1798 i_writejpeg_wiol(im, ig, qfactor)
1799     Imager::ImgRaw     im
1800         Imager::IO     ig
1801                int     qfactor
1802
1803
1804 void
1805 i_readjpeg_wiol(ig)
1806         Imager::IO     ig
1807              PREINIT:
1808               char*    iptc_itext;
1809                int     tlength;
1810              i_img*    rimg;
1811                 SV*    r;
1812              PPCODE:
1813               iptc_itext = NULL;
1814               rimg = i_readjpeg_wiol(ig,-1,&iptc_itext,&tlength);
1815               if (iptc_itext == NULL) {
1816                     r = sv_newmortal();
1817                     EXTEND(SP,1);
1818                     sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
1819                     PUSHs(r);
1820               } else {
1821                     r = sv_newmortal();
1822                     EXTEND(SP,2);
1823                     sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
1824                     PUSHs(r);
1825                     PUSHs(sv_2mortal(newSVpv(iptc_itext,tlength)));
1826                     myfree(iptc_itext);
1827               }
1828
1829
1830 #endif
1831
1832
1833
1834
1835 #ifdef HAVE_LIBTIFF
1836
1837 Imager::ImgRaw
1838 i_readtiff_wiol(ig, length)
1839         Imager::IO     ig
1840                int     length
1841
1842 void
1843 i_readtiff_multi_wiol(ig, length)
1844         Imager::IO     ig
1845                int     length
1846       PREINIT:
1847         i_img **imgs;
1848         int count;
1849         int i;
1850       PPCODE:
1851         imgs = i_readtiff_multi_wiol(ig, length, &count);
1852         if (imgs) {
1853           EXTEND(SP, count);
1854           for (i = 0; i < count; ++i) {
1855             SV *sv = sv_newmortal();
1856             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
1857             PUSHs(sv);
1858           }
1859           myfree(imgs);
1860         }
1861
1862
1863 undef_int
1864 i_writetiff_wiol(im, ig)
1865     Imager::ImgRaw     im
1866         Imager::IO     ig
1867
1868 undef_int
1869 i_writetiff_multi_wiol(ig, ...)
1870         Imager::IO     ig
1871       PREINIT:
1872         int i;
1873         int img_count;
1874         i_img **imgs;
1875       CODE:
1876         if (items < 2)
1877           croak("Usage: i_writetiff_multi_wiol(ig, images...)");
1878         img_count = items - 1;
1879         RETVAL = 1;
1880         if (img_count < 1) {
1881           RETVAL = 0;
1882           i_clear_error();
1883           i_push_error(0, "You need to specify images to save");
1884         }
1885         else {
1886           imgs = mymalloc(sizeof(i_img *) * img_count);
1887           for (i = 0; i < img_count; ++i) {
1888             SV *sv = ST(1+i);
1889             imgs[i] = NULL;
1890             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
1891               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
1892             }
1893             else {
1894               i_clear_error();
1895               i_push_error(0, "Only images can be saved");
1896               myfree(imgs);
1897               RETVAL = 0;
1898               break;
1899             }
1900           }
1901           if (RETVAL) {
1902             RETVAL = i_writetiff_multi_wiol(ig, imgs, img_count);
1903           }
1904           myfree(imgs);
1905         }
1906       OUTPUT:
1907         RETVAL
1908
1909 undef_int
1910 i_writetiff_wiol_faxable(im, ig, fine)
1911     Imager::ImgRaw     im
1912         Imager::IO     ig
1913                int     fine
1914
1915 undef_int
1916 i_writetiff_multi_wiol_faxable(ig, fine, ...)
1917         Imager::IO     ig
1918         int fine
1919       PREINIT:
1920         int i;
1921         int img_count;
1922         i_img **imgs;
1923       CODE:
1924         if (items < 3)
1925           croak("Usage: i_writetiff_multi_wiol_faxable(ig, fine, images...)");
1926         img_count = items - 2;
1927         RETVAL = 1;
1928         if (img_count < 1) {
1929           RETVAL = 0;
1930           i_clear_error();
1931           i_push_error(0, "You need to specify images to save");
1932         }
1933         else {
1934           imgs = mymalloc(sizeof(i_img *) * img_count);
1935           for (i = 0; i < img_count; ++i) {
1936             SV *sv = ST(2+i);
1937             imgs[i] = NULL;
1938             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
1939               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
1940             }
1941             else {
1942               i_clear_error();
1943               i_push_error(0, "Only images can be saved");
1944               myfree(imgs);
1945               RETVAL = 0;
1946               break;
1947             }
1948           }
1949           if (RETVAL) {
1950             RETVAL = i_writetiff_multi_wiol_faxable(ig, imgs, img_count, fine);
1951           }
1952           myfree(imgs);
1953         }
1954       OUTPUT:
1955         RETVAL
1956
1957
1958 #endif /* HAVE_LIBTIFF */
1959
1960
1961 #ifdef HAVE_LIBPNG
1962
1963 Imager::ImgRaw
1964 i_readpng_wiol(ig, length)
1965         Imager::IO     ig
1966                int     length
1967
1968
1969 undef_int
1970 i_writepng_wiol(im, ig)
1971     Imager::ImgRaw     im
1972         Imager::IO     ig
1973
1974
1975 #endif
1976
1977
1978 #ifdef HAVE_LIBGIF
1979
1980 void
1981 i_giflib_version()
1982         PPCODE:
1983           PUSHs(sv_2mortal(newSVnv(IM_GIFMAJOR+IM_GIFMINOR*0.1)));
1984
1985 undef_int
1986 i_writegif(im,fd,colors,pixdev,fixed)
1987     Imager::ImgRaw     im
1988                int     fd
1989                int     colors
1990                int     pixdev
1991              PREINIT:
1992              int     fixedlen;
1993              Imager__Color  fixed;
1994              Imager__Color  tmp;
1995              AV* av;
1996              SV* sv1;
1997              IV  Itmp;
1998              int i;
1999              CODE:
2000              if (!SvROK(ST(4))) croak("Imager: Parameter 4 must be a reference to an array\n");
2001              if (SvTYPE(SvRV(ST(4))) != SVt_PVAV) croak("Imager: Parameter 4 must be a reference to an array\n");
2002              av=(AV*)SvRV(ST(4));
2003              fixedlen=av_len(av)+1;
2004              fixed=mymalloc( fixedlen*sizeof(i_color) );
2005              for(i=0;i<fixedlen;i++) {
2006                sv1=(*(av_fetch(av,i,0)));
2007                if (sv_derived_from(sv1, "Imager::Color")) {
2008                  Itmp = SvIV((SV*)SvRV(sv1));
2009                  tmp = (i_color*) Itmp;
2010                } else croak("Imager: one of the elements of array ref is not of Imager::Color type\n");
2011                fixed[i]=*tmp;
2012              }
2013              RETVAL=i_writegif(im,fd,colors,pixdev,fixedlen,fixed);
2014              myfree(fixed);
2015              ST(0) = sv_newmortal();
2016              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2017              else sv_setiv(ST(0), (IV)RETVAL);
2018
2019
2020
2021
2022 undef_int
2023 i_writegifmc(im,fd,colors)
2024     Imager::ImgRaw    im
2025                int     fd
2026                int     colors
2027
2028
2029 undef_int
2030 i_writegif_gen(fd, ...)
2031                int     fd
2032       PROTOTYPE: $$@
2033       PREINIT:
2034         i_quantize quant;
2035         i_img **imgs = NULL;
2036         int img_count;
2037         int i;
2038         HV *hv;
2039       CODE:
2040         if (items < 3)
2041             croak("Usage: i_writegif_gen(fd,hashref, images...)");
2042         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2043             croak("i_writegif_gen: Second argument must be a hash ref");
2044         hv = (HV *)SvRV(ST(1));
2045         memset(&quant, 0, sizeof(quant));
2046         quant.mc_size = 256;
2047         handle_quant_opts(&quant, hv);
2048         img_count = items - 2;
2049         RETVAL = 1;
2050         if (img_count < 1) {
2051           RETVAL = 0;
2052           i_clear_error();
2053           i_push_error(0, "You need to specify images to save");
2054         }
2055         else {
2056           imgs = mymalloc(sizeof(i_img *) * img_count);
2057           for (i = 0; i < img_count; ++i) {
2058             SV *sv = ST(2+i);
2059             imgs[i] = NULL;
2060             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2061               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2062             }
2063             else {
2064               i_clear_error();
2065               i_push_error(0, "Only images can be saved");
2066               RETVAL = 0;
2067               break;
2068             }
2069           }
2070           if (RETVAL) {
2071             RETVAL = i_writegif_gen(&quant, fd, imgs, img_count);
2072           }
2073           myfree(imgs);
2074           if (RETVAL) {
2075             copy_colors_back(hv, &quant);
2076           }
2077         }
2078         ST(0) = sv_newmortal();
2079         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2080         else sv_setiv(ST(0), (IV)RETVAL);
2081         cleanup_quant_opts(&quant);
2082
2083
2084 undef_int
2085 i_writegif_callback(cb, maxbuffer,...)
2086         int maxbuffer;
2087       PREINIT:
2088         i_quantize quant;
2089         i_img **imgs = NULL;
2090         int img_count;
2091         int i;
2092         HV *hv;
2093         i_writer_data wd;
2094       CODE:
2095         if (items < 4)
2096             croak("Usage: i_writegif_callback(\\&callback,maxbuffer,hashref, images...)");
2097         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2098             croak("i_writegif_callback: Second argument must be a hash ref");
2099         hv = (HV *)SvRV(ST(2));
2100         memset(&quant, 0, sizeof(quant));
2101         quant.mc_size = 256;
2102         handle_quant_opts(&quant, hv);
2103         img_count = items - 3;
2104         RETVAL = 1;
2105         if (img_count < 1) {
2106           RETVAL = 0;
2107         }
2108         else {
2109           imgs = mymalloc(sizeof(i_img *) * img_count);
2110           for (i = 0; i < img_count; ++i) {
2111             SV *sv = ST(3+i);
2112             imgs[i] = NULL;
2113             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2114               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2115             }
2116             else {
2117               RETVAL = 0;
2118               break;
2119             }
2120           }
2121           if (RETVAL) {
2122             wd.sv = ST(0);
2123             RETVAL = i_writegif_callback(&quant, write_callback, (char *)&wd, maxbuffer, imgs, img_count);
2124           }
2125           myfree(imgs);
2126           if (RETVAL) {
2127             copy_colors_back(hv, &quant);
2128           }
2129         }
2130         ST(0) = sv_newmortal();
2131         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2132         else sv_setiv(ST(0), (IV)RETVAL);
2133         cleanup_quant_opts(&quant);
2134
2135 undef_int
2136 i_writegif_wiol(ig, opts,...)
2137         Imager::IO ig
2138       PREINIT:
2139         i_quantize quant;
2140         i_img **imgs = NULL;
2141         int img_count;
2142         int i;
2143         HV *hv;
2144       CODE:
2145         if (items < 3)
2146             croak("Usage: i_writegif_wiol(IO,hashref, images...)");
2147         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2148             croak("i_writegif_callback: Second argument must be a hash ref");
2149         hv = (HV *)SvRV(ST(1));
2150         memset(&quant, 0, sizeof(quant));
2151         quant.mc_size = 256;
2152         handle_quant_opts(&quant, hv);
2153         img_count = items - 2;
2154         RETVAL = 1;
2155         if (img_count < 1) {
2156           RETVAL = 0;
2157         }
2158         else {
2159           imgs = mymalloc(sizeof(i_img *) * img_count);
2160           for (i = 0; i < img_count; ++i) {
2161             SV *sv = ST(2+i);
2162             imgs[i] = NULL;
2163             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2164               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2165             }
2166             else {
2167               RETVAL = 0;
2168               break;
2169             }
2170           }
2171           if (RETVAL) {
2172             RETVAL = i_writegif_wiol(ig, &quant, imgs, img_count);
2173           }
2174           myfree(imgs);
2175           if (RETVAL) {
2176             copy_colors_back(hv, &quant);
2177           }
2178         }
2179         ST(0) = sv_newmortal();
2180         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2181         else sv_setiv(ST(0), (IV)RETVAL);
2182         cleanup_quant_opts(&quant);
2183
2184 void
2185 i_readgif(fd)
2186                int     fd
2187               PREINIT:
2188                 int*    colour_table;
2189                 int     colours, q, w;
2190               i_img*    rimg;
2191                  SV*    temp[3];
2192                  AV*    ct; 
2193                  SV*    r;
2194                PPCODE:
2195                colour_table = NULL;
2196                colours = 0;
2197
2198         if(GIMME_V == G_ARRAY) {
2199             rimg = i_readgif(fd,&colour_table,&colours);
2200         } else {
2201             /* don't waste time with colours if they aren't wanted */
2202             rimg = i_readgif(fd,NULL,NULL);
2203         }
2204         
2205         if (colour_table == NULL) {
2206             EXTEND(SP,1);
2207             r=sv_newmortal();
2208             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2209             PUSHs(r);
2210         } else {
2211             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2212             /* I don't know if I have the reference counts right or not :( */
2213             /* Neither do I :-) */
2214             /* No Idea here either */
2215
2216             ct=newAV();
2217             av_extend(ct, colours);
2218             for(q=0; q<colours; q++) {
2219                 for(w=0; w<3; w++)
2220                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2221                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2222             }
2223             myfree(colour_table);
2224
2225             EXTEND(SP,2);
2226             r = sv_newmortal();
2227             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2228             PUSHs(r);
2229             PUSHs(newRV_noinc((SV*)ct));
2230         }
2231
2232 void
2233 i_readgif_wiol(ig)
2234      Imager::IO         ig
2235               PREINIT:
2236                 int*    colour_table;
2237                 int     colours, q, w;
2238               i_img*    rimg;
2239                  SV*    temp[3];
2240                  AV*    ct; 
2241                  SV*    r;
2242                PPCODE:
2243                colour_table = NULL;
2244                colours = 0;
2245
2246         if(GIMME_V == G_ARRAY) {
2247             rimg = i_readgif_wiol(ig,&colour_table,&colours);
2248         } else {
2249             /* don't waste time with colours if they aren't wanted */
2250             rimg = i_readgif_wiol(ig,NULL,NULL);
2251         }
2252         
2253         if (colour_table == NULL) {
2254             EXTEND(SP,1);
2255             r=sv_newmortal();
2256             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2257             PUSHs(r);
2258         } else {
2259             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2260             /* I don't know if I have the reference counts right or not :( */
2261             /* Neither do I :-) */
2262             /* No Idea here either */
2263
2264             ct=newAV();
2265             av_extend(ct, colours);
2266             for(q=0; q<colours; q++) {
2267                 for(w=0; w<3; w++)
2268                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2269                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2270             }
2271             myfree(colour_table);
2272
2273             EXTEND(SP,2);
2274             r = sv_newmortal();
2275             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2276             PUSHs(r);
2277             PUSHs(newRV_noinc((SV*)ct));
2278         }
2279
2280 void
2281 i_readgif_scalar(...)
2282           PROTOTYPE: $
2283             PREINIT:
2284                char*    data;
2285        unsigned int     length;
2286                 int*    colour_table;
2287                 int     colours, q, w;
2288               i_img*    rimg;
2289                  SV*    temp[3];
2290                  AV*    ct; 
2291                  SV*    r;
2292                PPCODE:
2293         data = (char *)SvPV(ST(0), length);
2294         colour_table=NULL;
2295         colours=0;
2296
2297         if(GIMME_V == G_ARRAY) {  
2298             rimg=i_readgif_scalar(data,length,&colour_table,&colours);
2299         } else {
2300             /* don't waste time with colours if they aren't wanted */
2301             rimg=i_readgif_scalar(data,length,NULL,NULL);
2302         }
2303
2304         if (colour_table == NULL) {
2305             EXTEND(SP,1);
2306             r=sv_newmortal();
2307             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2308             PUSHs(r);
2309         } else {
2310             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2311             /* I don't know if I have the reference counts right or not :( */
2312             /* Neither do I :-) */
2313             ct=newAV();
2314             av_extend(ct, colours);
2315             for(q=0; q<colours; q++) {
2316                 for(w=0; w<3; w++)
2317                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2318                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2319             }
2320             myfree(colour_table);
2321             
2322             EXTEND(SP,2);
2323             r=sv_newmortal();
2324             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2325             PUSHs(r);
2326             PUSHs(newRV_noinc((SV*)ct));
2327         }
2328
2329 void
2330 i_readgif_callback(...)
2331           PROTOTYPE: &
2332             PREINIT:
2333                char*    data;
2334                 int     length;
2335                 int*    colour_table;
2336                 int     colours, q, w;
2337               i_img*    rimg;
2338                  SV*    temp[3];
2339                  AV*    ct; 
2340                  SV*    r;
2341        i_reader_data    rd;
2342                PPCODE:
2343         rd.sv = ST(0);
2344         colour_table=NULL;
2345         colours=0;
2346
2347         if(GIMME_V == G_ARRAY) {  
2348             rimg=i_readgif_callback(read_callback, (char *)&rd,&colour_table,&colours);
2349         } else {
2350             /* don't waste time with colours if they aren't wanted */
2351             rimg=i_readgif_callback(read_callback, (char *)&rd,NULL,NULL);
2352         }
2353
2354         if (colour_table == NULL) {
2355             EXTEND(SP,1);
2356             r=sv_newmortal();
2357             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2358             PUSHs(r);
2359         } else {
2360             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2361             /* I don't know if I have the reference counts right or not :( */
2362             /* Neither do I :-) */
2363             /* Neither do I - maybe I'll move this somewhere */
2364             ct=newAV();
2365             av_extend(ct, colours);
2366             for(q=0; q<colours; q++) {
2367                 for(w=0; w<3; w++)
2368                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2369                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2370             }
2371             myfree(colour_table);
2372             
2373             EXTEND(SP,2);
2374             r=sv_newmortal();
2375             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2376             PUSHs(r);
2377             PUSHs(newRV_noinc((SV*)ct));
2378         }
2379
2380 void
2381 i_readgif_multi(fd)
2382         int     fd
2383       PREINIT:
2384         i_img **imgs;
2385         int count;
2386         int i;
2387       PPCODE:
2388         imgs = i_readgif_multi(fd, &count);
2389         if (imgs) {
2390           EXTEND(SP, count);
2391           for (i = 0; i < count; ++i) {
2392             SV *sv = sv_newmortal();
2393             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2394             PUSHs(sv);
2395           }
2396           myfree(imgs);
2397         }
2398
2399 void
2400 i_readgif_multi_scalar(data)
2401       PREINIT:
2402         i_img **imgs;
2403         int count;
2404         char *data;
2405         unsigned int length;
2406         int i;
2407       PPCODE:
2408         data = (char *)SvPV(ST(0), length);
2409         imgs = i_readgif_multi_scalar(data, length, &count);
2410         if (imgs) {
2411           EXTEND(SP, count);
2412           for (i = 0; i < count; ++i) {
2413             SV *sv = sv_newmortal();
2414             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2415             PUSHs(sv);
2416           }
2417           myfree(imgs);
2418         }
2419
2420 void
2421 i_readgif_multi_callback(cb)
2422       PREINIT:
2423         i_reader_data rd;
2424         i_img **imgs;
2425         int count;
2426         int i;
2427       PPCODE:
2428         rd.sv = ST(0);
2429         imgs = i_readgif_multi_callback(read_callback, (char *)&rd, &count);
2430         if (imgs) {
2431           EXTEND(SP, count);
2432           for (i = 0; i < count; ++i) {
2433             SV *sv = sv_newmortal();
2434             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2435             PUSHs(sv);
2436           }
2437           myfree(imgs);
2438         }
2439
2440 void
2441 i_readgif_multi_wiol(ig)
2442         Imager::IO ig
2443       PREINIT:
2444         i_img **imgs;
2445         int count;
2446         int i;
2447       PPCODE:
2448         imgs = i_readgif_multi_wiol(ig, &count);
2449         if (imgs) {
2450           EXTEND(SP, count);
2451           for (i = 0; i < count; ++i) {
2452             SV *sv = sv_newmortal();
2453             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2454             PUSHs(sv);
2455           }
2456           myfree(imgs);
2457         }
2458
2459
2460 #endif
2461
2462
2463
2464 Imager::ImgRaw
2465 i_readpnm_wiol(ig, length)
2466         Imager::IO     ig
2467                int     length
2468
2469
2470 undef_int
2471 i_writeppm_wiol(im, ig)
2472     Imager::ImgRaw     im
2473         Imager::IO     ig
2474
2475
2476 Imager::ImgRaw
2477 i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
2478         Imager::IO     ig
2479                int     x
2480                int     y
2481                int     datachannels
2482                int     storechannels
2483                int     intrl
2484
2485 undef_int
2486 i_writeraw_wiol(im,ig)
2487     Imager::ImgRaw     im
2488         Imager::IO     ig
2489
2490 undef_int
2491 i_writebmp_wiol(im,ig)
2492     Imager::ImgRaw     im
2493         Imager::IO     ig
2494
2495 Imager::ImgRaw
2496 i_readbmp_wiol(ig)
2497         Imager::IO     ig
2498
2499
2500 undef_int
2501 i_writetga_wiol(im,ig, wierdpack, compress, idstring)
2502     Imager::ImgRaw     im
2503         Imager::IO     ig
2504                int     wierdpack
2505                int     compress
2506               char*    idstring
2507             PREINIT:
2508                 SV* sv1;
2509                 int rc;
2510                 int idlen;
2511                CODE:
2512                 idlen  = SvCUR(ST(4));
2513                 RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
2514                 OUTPUT:
2515                 RETVAL
2516
2517
2518 Imager::ImgRaw
2519 i_readtga_wiol(ig, length)
2520         Imager::IO     ig
2521                int     length
2522
2523
2524 undef_int
2525 i_writergb_wiol(im,ig, wierdpack, compress, idstring)
2526     Imager::ImgRaw     im
2527         Imager::IO     ig
2528                int     wierdpack
2529                int     compress
2530               char*    idstring
2531             PREINIT:
2532                 SV* sv1;
2533                 int rc;
2534                 int idlen;
2535                CODE:
2536                 idlen  = SvCUR(ST(4));
2537                 RETVAL = i_writergb_wiol(im, ig, wierdpack, compress, idstring, idlen);
2538                 OUTPUT:
2539                 RETVAL
2540
2541
2542 Imager::ImgRaw
2543 i_readrgb_wiol(ig, length)
2544         Imager::IO     ig
2545                int     length
2546
2547
2548
2549 Imager::ImgRaw
2550 i_scaleaxis(im,Value,Axis)
2551     Imager::ImgRaw     im
2552              float     Value
2553                int     Axis
2554
2555 Imager::ImgRaw
2556 i_scale_nn(im,scx,scy)
2557     Imager::ImgRaw     im
2558              float     scx
2559              float     scy
2560
2561 Imager::ImgRaw
2562 i_haar(im)
2563     Imager::ImgRaw     im
2564
2565 int
2566 i_count_colors(im,maxc)
2567     Imager::ImgRaw     im
2568                int     maxc
2569
2570
2571 Imager::ImgRaw
2572 i_transform(im,opx,opy,parm)
2573     Imager::ImgRaw     im
2574              PREINIT:
2575              double* parm;
2576              int*    opx;
2577              int*    opy;
2578              int     opxl;
2579              int     opyl;
2580              int     parmlen;
2581              AV* av;
2582              SV* sv1;
2583              int i;
2584              CODE:
2585              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
2586              if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n");
2587              if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n");
2588              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
2589              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n");
2590              if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n");
2591              av=(AV*)SvRV(ST(1));
2592              opxl=av_len(av)+1;
2593              opx=mymalloc( opxl*sizeof(int) );
2594              for(i=0;i<opxl;i++) {
2595                sv1=(*(av_fetch(av,i,0)));
2596                opx[i]=(int)SvIV(sv1);
2597              }
2598              av=(AV*)SvRV(ST(2));
2599              opyl=av_len(av)+1;
2600              opy=mymalloc( opyl*sizeof(int) );
2601              for(i=0;i<opyl;i++) {
2602                sv1=(*(av_fetch(av,i,0)));
2603                opy[i]=(int)SvIV(sv1);
2604              }
2605              av=(AV*)SvRV(ST(3));
2606              parmlen=av_len(av)+1;
2607              parm=mymalloc( parmlen*sizeof(double) );
2608              for(i=0;i<parmlen;i++) { /* FIXME: Bug? */
2609                sv1=(*(av_fetch(av,i,0)));
2610                parm[i]=(double)SvNV(sv1);
2611              }
2612              RETVAL=i_transform(im,opx,opxl,opy,opyl,parm,parmlen);
2613              myfree(parm);
2614              myfree(opy);
2615              myfree(opx);
2616              ST(0) = sv_newmortal();
2617              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2618              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2619
2620 Imager::ImgRaw
2621 i_transform2(width,height,ops,n_regs,c_regs,in_imgs)
2622              PREINIT:
2623              int width;
2624              int height;
2625              double* parm;
2626              struct rm_op *ops;
2627              STRLEN ops_len;
2628              int ops_count;
2629              double *n_regs;
2630              int n_regs_count;
2631              i_color *c_regs;
2632              int c_regs_count;
2633              int in_imgs_count;
2634              i_img **in_imgs;
2635              AV* av;
2636              SV* sv1;
2637              IV tmp;
2638              int i;
2639              CODE:
2640              if (!SvROK(ST(3))) croak("Imager: Parameter 4 must be a reference to an array\n");
2641              if (!SvROK(ST(4))) croak("Imager: Parameter 5 must be a reference to an array\n");
2642              if (!SvROK(ST(5))) croak("Imager: Parameter 6 must be a reference to an array of images\n");
2643              if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 4 must be a reference to an array\n");
2644              if (SvTYPE(SvRV(ST(4))) != SVt_PVAV) croak("Imager: Parameter 5 must be a reference to an array\n");
2645
2646         /*if (SvTYPE(SvRV(ST(5))) != SVt_PVAV) croak("Imager: Parameter 6 must be a reference to an array\n");*/
2647
2648              if (SvTYPE(SvRV(ST(5))) == SVt_PVAV) {
2649                av = (AV*)SvRV(ST(5));
2650                in_imgs_count = av_len(av)+1;
2651                for (i = 0; i < in_imgs_count; ++i) {
2652                  sv1 = *av_fetch(av, i, 0);
2653                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2654                    croak("Parameter 5 must contain only images");
2655                  }
2656                }
2657              }
2658              else {
2659                in_imgs_count = 0;
2660              }
2661              if (in_imgs_count > 0) {
2662                av = (AV*)SvRV(ST(5));
2663                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2664                for (i = 0; i < in_imgs_count; ++i) {              
2665                  sv1 = *av_fetch(av,i,0);
2666                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2667                    croak("Parameter 5 must contain only images");
2668                  }
2669                  tmp = SvIV((SV*)SvRV(sv1));
2670                  in_imgs[i] = INT2PTR(i_img*, tmp);
2671                }
2672              }
2673              else {
2674                /* no input images */
2675                in_imgs = NULL;
2676              }
2677              /* default the output size from the first input if possible */
2678              if (SvOK(ST(0)))
2679                width = SvIV(ST(0));
2680              else if (in_imgs_count)
2681                width = in_imgs[0]->xsize;
2682              else
2683                croak("No output image width supplied");
2684
2685              if (SvOK(ST(1)))
2686                height = SvIV(ST(1));
2687              else if (in_imgs_count)
2688                height = in_imgs[0]->ysize;
2689              else
2690                croak("No output image height supplied");
2691
2692              ops = (struct rm_op *)SvPV(ST(2), ops_len);
2693              if (ops_len % sizeof(struct rm_op))
2694                  croak("Imager: Parameter 3 must be a bitmap of regops\n");
2695              ops_count = ops_len / sizeof(struct rm_op);
2696              av = (AV*)SvRV(ST(3));
2697              n_regs_count = av_len(av)+1;
2698              n_regs = mymalloc(n_regs_count * sizeof(double));
2699              for (i = 0; i < n_regs_count; ++i) {
2700                sv1 = *av_fetch(av,i,0);
2701                if (SvOK(sv1))
2702                  n_regs[i] = SvNV(sv1);
2703              }
2704              av = (AV*)SvRV(ST(4));
2705              c_regs_count = av_len(av)+1;
2706              c_regs = mymalloc(c_regs_count * sizeof(i_color));
2707              /* I don't bother initializing the colou?r registers */
2708
2709              RETVAL=i_transform2(width, height, 3, ops, ops_count, 
2710                                  n_regs, n_regs_count, 
2711                                  c_regs, c_regs_count, in_imgs, in_imgs_count);
2712              if (in_imgs)
2713                  myfree(in_imgs);
2714              myfree(n_regs);
2715              myfree(c_regs);
2716              ST(0) = sv_newmortal();
2717              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2718              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2719
2720
2721 void
2722 i_contrast(im,intensity)
2723     Imager::ImgRaw     im
2724              float     intensity
2725
2726 void
2727 i_hardinvert(im)
2728     Imager::ImgRaw     im
2729
2730 void
2731 i_noise(im,amount,type)
2732     Imager::ImgRaw     im
2733              float     amount
2734      unsigned char     type
2735
2736 void
2737 i_bumpmap(im,bump,channel,light_x,light_y,strength)
2738     Imager::ImgRaw     im
2739     Imager::ImgRaw     bump
2740                int     channel
2741                int     light_x
2742                int     light_y
2743                int     strength
2744
2745
2746 void
2747 i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
2748     Imager::ImgRaw     im
2749     Imager::ImgRaw     bump
2750                int     channel
2751                int     tx
2752                int     ty
2753              float     Lx
2754              float     Ly
2755              float     Lz
2756              float     cd
2757              float     cs
2758              float     n
2759      Imager::Color     Ia
2760      Imager::Color     Il
2761      Imager::Color     Is
2762
2763
2764
2765 void
2766 i_postlevels(im,levels)
2767     Imager::ImgRaw     im
2768              int       levels
2769
2770 void
2771 i_mosaic(im,size)
2772     Imager::ImgRaw     im
2773                int     size
2774
2775 void
2776 i_watermark(im,wmark,tx,ty,pixdiff)
2777     Imager::ImgRaw     im
2778     Imager::ImgRaw     wmark
2779                int     tx
2780                int     ty
2781                int     pixdiff
2782
2783
2784 void
2785 i_autolevels(im,lsat,usat,skew)
2786     Imager::ImgRaw     im
2787              float     lsat
2788              float     usat
2789              float     skew
2790
2791 void
2792 i_radnoise(im,xo,yo,rscale,ascale)
2793     Imager::ImgRaw     im
2794              float     xo
2795              float     yo
2796              float     rscale
2797              float     ascale
2798
2799 void
2800 i_turbnoise(im, xo, yo, scale)
2801     Imager::ImgRaw     im
2802              float     xo
2803              float     yo
2804              float     scale
2805
2806
2807 void
2808 i_gradgen(im, ...)
2809     Imager::ImgRaw     im
2810       PREINIT:
2811         int num;
2812         int *xo;
2813         int *yo;
2814         i_color *ival;
2815         int dmeasure;
2816         int i;
2817         SV *sv;
2818         AV *axx;
2819         AV *ayy;
2820         AV *ac;
2821       CODE:
2822         if (items != 5)
2823             croak("Usage: i_gradgen(im, xo, yo, ival, dmeasure)");
2824         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2825             croak("i_gradgen: Second argument must be an array ref");
2826         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2827             croak("i_gradgen: Third argument must be an array ref");
2828         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2829             croak("i_gradgen: Fourth argument must be an array ref");
2830         axx = (AV *)SvRV(ST(1));
2831         ayy = (AV *)SvRV(ST(2));
2832         ac  = (AV *)SvRV(ST(3));
2833         dmeasure = (int)SvIV(ST(4));
2834         
2835         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2836         num = num <= av_len(ac) ? num : av_len(ac);
2837         num++; 
2838         if (num < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each");
2839         xo = mymalloc( sizeof(int) * num );
2840         yo = mymalloc( sizeof(int) * num );
2841         ival = mymalloc( sizeof(i_color) * num );
2842         for(i = 0; i<num; i++) {
2843           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
2844           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
2845           sv = *av_fetch(ac, i, 0);
2846           if ( !sv_derived_from(sv, "Imager::Color") ) {
2847             free(axx); free(ayy); free(ac);
2848             croak("i_gradgen: Element of fourth argument is not derived from Imager::Color");
2849           }
2850           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
2851         }
2852         i_gradgen(im, num, xo, yo, ival, dmeasure);
2853         myfree(xo);
2854         myfree(yo);
2855         myfree(ival);
2856
2857 Imager::ImgRaw
2858 i_diff_image(im, im2, mindist=0)
2859     Imager::ImgRaw     im
2860     Imager::ImgRaw     im2
2861                int     mindist
2862
2863 void
2864 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2865     Imager::ImgRaw     im
2866             double     xa
2867             double     ya
2868             double     xb
2869             double     yb
2870                int     type
2871                int     repeat
2872                int     combine
2873                int     super_sample
2874             double     ssample_param
2875       PREINIT:
2876         AV *asegs;
2877         int count;
2878         i_fountain_seg *segs;
2879       CODE:
2880         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
2881             croak("i_fountain: argument 11 must be an array ref");
2882         
2883         asegs = (AV *)SvRV(ST(10));
2884         segs = load_fount_segs(asegs, &count);
2885         i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, 
2886                    ssample_param, count, segs);
2887         myfree(segs);
2888
2889 Imager::FillHandle
2890 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2891             double     xa
2892             double     ya
2893             double     xb
2894             double     yb
2895                int     type
2896                int     repeat
2897                int     combine
2898                int     super_sample
2899             double     ssample_param
2900       PREINIT:
2901         AV *asegs;
2902         int count;
2903         i_fountain_seg *segs;
2904       CODE:
2905         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
2906             croak("i_fountain: argument 11 must be an array ref");
2907         
2908         asegs = (AV *)SvRV(ST(9));
2909         segs = load_fount_segs(asegs, &count);
2910         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
2911                                   super_sample, ssample_param, count, segs);
2912         myfree(segs);        
2913       OUTPUT:
2914         RETVAL
2915
2916 void
2917 i_errors()
2918       PREINIT:
2919         i_errmsg *errors;
2920         int i;
2921         AV *av;
2922         SV *ref;
2923         SV *sv;
2924       PPCODE:
2925         errors = i_errors();
2926         i = 0;
2927         while (errors[i].msg) {
2928           av = newAV();
2929           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
2930           if (!av_store(av, 0, sv)) {
2931             SvREFCNT_dec(sv);
2932           }
2933           sv = newSViv(errors[i].code);
2934           if (!av_store(av, 1, sv)) {
2935             SvREFCNT_dec(sv);
2936           }
2937           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
2938           ++i;
2939         }
2940
2941 void
2942 i_nearest_color(im, ...)
2943     Imager::ImgRaw     im
2944       PREINIT:
2945         int num;
2946         int *xo;
2947         int *yo;
2948         i_color *ival;
2949         int dmeasure;
2950         int i;
2951         SV *sv;
2952         AV *axx;
2953         AV *ayy;
2954         AV *ac;
2955       CODE:
2956         if (items != 5)
2957             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
2958         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2959             croak("i_nearest_color: Second argument must be an array ref");
2960         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2961             croak("i_nearest_color: Third argument must be an array ref");
2962         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2963             croak("i_nearest_color: Fourth argument must be an array ref");
2964         axx = (AV *)SvRV(ST(1));
2965         ayy = (AV *)SvRV(ST(2));
2966         ac  = (AV *)SvRV(ST(3));
2967         dmeasure = (int)SvIV(ST(4));
2968         
2969         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2970         num = num <= av_len(ac) ? num : av_len(ac);
2971         num++; 
2972         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
2973         xo = mymalloc( sizeof(int) * num );
2974         yo = mymalloc( sizeof(int) * num );
2975         ival = mymalloc( sizeof(i_color) * num );
2976         for(i = 0; i<num; i++) {
2977           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
2978           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
2979           sv = *av_fetch(ac, i, 0);
2980           if ( !sv_derived_from(sv, "Imager::Color") ) {
2981             free(axx); free(ayy); free(ac);
2982             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
2983           }
2984           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
2985         }
2986         i_nearest_color(im, num, xo, yo, ival, dmeasure);
2987
2988
2989
2990
2991 void
2992 malloc_state()
2993
2994 void
2995 hashinfo(hv)
2996              PREINIT:
2997                HV* hv;
2998                int stuff;
2999              PPCODE:
3000                if (!SvROK(ST(0))) croak("Imager: Parameter 0 must be a reference to a hash\n");        
3001                hv=(HV*)SvRV(ST(0));
3002                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 0 must be a reference to a hash\n");
3003                if (getint(hv,"stuff",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
3004                if (getint(hv,"stuff2",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
3005                
3006 void
3007 DSO_open(filename)
3008              char*       filename
3009              PREINIT:
3010                void *rc;
3011                char *evstr;
3012              PPCODE:
3013                rc=DSO_open(filename,&evstr);
3014                if (rc!=NULL) {
3015                  if (evstr!=NULL) {
3016                    EXTEND(SP,2); 
3017                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3018                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
3019                  } else {
3020                    EXTEND(SP,1);
3021                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3022                  }
3023                }
3024
3025
3026 undef_int
3027 DSO_close(dso_handle)
3028              void*       dso_handle
3029
3030 void
3031 DSO_funclist(dso_handle_v)
3032              void*       dso_handle_v
3033              PREINIT:
3034                int i;
3035                DSO_handle *dso_handle;
3036              PPCODE:
3037                dso_handle=(DSO_handle*)dso_handle_v;
3038                i=0;
3039                while( dso_handle->function_list[i].name != NULL) {
3040                  EXTEND(SP,1);
3041                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i].name,0)));
3042                  EXTEND(SP,1);
3043                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i++].pcode,0)));
3044                }
3045
3046
3047 void
3048 DSO_call(handle,func_index,hv)
3049                void*  handle
3050                int    func_index
3051              PREINIT:
3052                HV* hv;
3053              PPCODE:
3054                if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
3055                hv=(HV*)SvRV(ST(2));
3056                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
3057                DSO_call( (DSO_handle *)handle,func_index,hv);
3058
3059
3060
3061 # this is mostly for testing...
3062 SV *
3063 i_get_pixel(im, x, y)
3064         Imager::ImgRaw im
3065         int x
3066         int y;
3067       PREINIT:
3068         i_color *color;
3069       CODE:
3070         color = (i_color *)mymalloc(sizeof(i_color));
3071         if (i_gpix(im, x, y, color) == 0) {
3072           ST(0) = sv_newmortal();
3073           sv_setref_pv(ST(0), "Imager::Color", (void *)color);
3074         }
3075         else {
3076           myfree(color);
3077           ST(0) = &PL_sv_undef;
3078         }
3079         
3080
3081 int
3082 i_ppix(im, x, y, cl)
3083         Imager::ImgRaw im
3084         int x
3085         int y
3086         Imager::Color cl
3087
3088 Imager::ImgRaw
3089 i_img_pal_new(x, y, channels, maxpal)
3090         int     x
3091         int     y
3092         int     channels
3093         int     maxpal
3094
3095 Imager::ImgRaw
3096 i_img_to_pal(src, quant)
3097         Imager::ImgRaw src
3098       PREINIT:
3099         HV *hv;
3100         i_quantize quant;
3101       CODE:
3102         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3103           croak("i_img_to_pal: second argument must be a hash ref");
3104         hv = (HV *)SvRV(ST(1));
3105         memset(&quant, 0, sizeof(quant));
3106         quant.mc_size = 256;
3107         handle_quant_opts(&quant, hv);
3108         RETVAL = i_img_to_pal(src, &quant);
3109         if (RETVAL) {
3110           copy_colors_back(hv, &quant);
3111         }
3112         cleanup_quant_opts(&quant);
3113       OUTPUT:
3114         RETVAL
3115
3116 Imager::ImgRaw
3117 i_img_to_rgb(src)
3118         Imager::ImgRaw src
3119
3120 void
3121 i_gpal(im, l, r, y)
3122         Imager::ImgRaw  im
3123         int     l
3124         int     r
3125         int     y
3126       PREINIT:
3127         i_palidx *work;
3128         int count, i;
3129       PPCODE:
3130         if (l < r) {
3131           work = mymalloc((r-l) * sizeof(i_palidx));
3132           count = i_gpal(im, l, r, y, work);
3133           if (GIMME_V == G_ARRAY) {
3134             EXTEND(SP, count);
3135             for (i = 0; i < count; ++i) {
3136               PUSHs(sv_2mortal(newSViv(work[i])));
3137             }
3138           }
3139           else {
3140             EXTEND(SP, 1);
3141             PUSHs(sv_2mortal(newSVpv(work, count * sizeof(i_palidx))));
3142           }
3143           myfree(work);
3144         }
3145         else {
3146           if (GIMME_V != G_ARRAY) {
3147             EXTEND(SP, 1);
3148             PUSHs(&PL_sv_undef);
3149           }
3150         }
3151
3152 int
3153 i_ppal(im, l, y, ...)
3154         Imager::ImgRaw  im
3155         int     l
3156         int     y
3157       PREINIT:
3158         i_palidx *work;
3159         int count, i;
3160       CODE:
3161         if (items > 3) {
3162           work = mymalloc(sizeof(i_palidx) * (items-3));
3163           for (i=0; i < items-3; ++i) {
3164             work[i] = SvIV(ST(i+3));
3165           }
3166           RETVAL = i_ppal(im, l, l+items-3, y, work);
3167           myfree(work);
3168         }
3169         else {
3170           RETVAL = 0;
3171         }
3172       OUTPUT:
3173         RETVAL
3174
3175 SV *
3176 i_addcolors(im, ...)
3177         Imager::ImgRaw  im
3178       PREINIT:
3179         int index;
3180         i_color *colors;
3181         int i;
3182       CODE:
3183         if (items < 2)
3184           croak("i_addcolors: no colors to add");
3185         colors = mymalloc((items-1) * sizeof(i_color));
3186         for (i=0; i < items-1; ++i) {
3187           if (sv_isobject(ST(i+1)) 
3188               && sv_derived_from(ST(i+1), "Imager::Color")) {
3189             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3190             colors[i] = *INT2PTR(i_color *, tmp);
3191           }
3192           else {
3193             myfree(colors);
3194             croak("i_plin: pixels must be Imager::Color objects");
3195           }
3196         }
3197         index = i_addcolors(im, colors, items-1);
3198         myfree(colors);
3199         if (index == 0) {
3200           ST(0) = sv_2mortal(newSVpv("0 but true", 0));
3201         }
3202         else if (index == -1) {
3203           ST(0) = &PL_sv_undef;
3204         }
3205         else {
3206           ST(0) = sv_2mortal(newSViv(index));
3207         }
3208
3209 int 
3210 i_setcolors(im, index, ...)
3211         Imager::ImgRaw  im
3212         int index
3213       PREINIT:
3214         i_color *colors;
3215         int i;
3216       CODE:
3217         if (items < 3)
3218           croak("i_setcolors: no colors to add");
3219         colors = mymalloc((items-2) * sizeof(i_color));
3220         for (i=0; i < items-2; ++i) {
3221           if (sv_isobject(ST(i+2)) 
3222               && sv_derived_from(ST(i+2), "Imager::Color")) {
3223             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3224             colors[i] = *INT2PTR(i_color *, tmp);
3225           }
3226           else {
3227             myfree(colors);
3228             croak("i_setcolors: pixels must be Imager::Color objects");
3229           }
3230         }
3231         RETVAL = i_setcolors(im, index, colors, items-2);
3232         myfree(colors);
3233
3234 void
3235 i_getcolors(im, index, ...)
3236         Imager::ImgRaw im
3237         int index
3238       PREINIT:
3239         i_color *colors;
3240         int count = 1;
3241         int i;
3242       PPCODE:
3243         if (items > 3)
3244           croak("i_getcolors: too many arguments");
3245         if (items == 3)
3246           count = SvIV(ST(2));
3247         if (count < 1)
3248           croak("i_getcolors: count must be positive");
3249         colors = mymalloc(sizeof(i_color) * count);
3250         if (i_getcolors(im, index, colors, count)) {
3251           for (i = 0; i < count; ++i) {
3252             i_color *pv;
3253             SV *sv = sv_newmortal();
3254             pv = mymalloc(sizeof(i_color));
3255             *pv = colors[i];
3256             sv_setref_pv(sv, "Imager::Color", (void *)pv);
3257             PUSHs(sv);
3258           }
3259         }
3260         myfree(colors);
3261
3262
3263 SV *
3264 i_colorcount(im)
3265         Imager::ImgRaw im
3266       PREINIT:
3267         int count;
3268       CODE:
3269         count = i_colorcount(im);
3270         if (count >= 0) {
3271           ST(0) = sv_2mortal(newSViv(count));
3272         }
3273         else {
3274           ST(0) = &PL_sv_undef;
3275         }
3276
3277 SV *
3278 i_maxcolors(im)
3279         Imager::ImgRaw im
3280       PREINIT:
3281         int count;
3282       CODE:
3283         count = i_maxcolors(im);
3284         if (count >= 0) {
3285           ST(0) = sv_2mortal(newSViv(count));
3286         }
3287         else {
3288           ST(0) = &PL_sv_undef;
3289         }
3290
3291 SV *
3292 i_findcolor(im, color)
3293         Imager::ImgRaw im
3294         Imager::Color color
3295       PREINIT:
3296         i_palidx index;
3297       CODE:
3298         if (i_findcolor(im, color, &index)) {
3299           ST(0) = sv_2mortal(newSViv(index));
3300         }
3301         else {
3302           ST(0) = &PL_sv_undef;
3303         }
3304
3305 int
3306 i_img_bits(im)
3307         Imager::ImgRaw  im
3308
3309 int
3310 i_img_type(im)
3311         Imager::ImgRaw  im
3312
3313 int
3314 i_img_virtual(im)
3315         Imager::ImgRaw  im
3316
3317 void
3318 i_gsamp(im, l, r, y, ...)
3319         Imager::ImgRaw im
3320         int l
3321         int r
3322         int y
3323       PREINIT:
3324         int *chans;
3325         int chan_count;
3326         i_sample_t *data;
3327         int count, i;
3328       PPCODE:
3329         if (items < 5)
3330           croak("No channel numbers supplied to g_samp()");
3331         if (l < r) {
3332           chan_count = items - 4;
3333           chans = mymalloc(sizeof(int) * chan_count);
3334           for (i = 0; i < chan_count; ++i)
3335             chans[i] = SvIV(ST(i+4));
3336           data = mymalloc(sizeof(i_sample_t) * (r-l) * chan_count); /* XXX: memleak? */
3337           count = i_gsamp(im, l, r, y, data, chans, chan_count);
3338           myfree(chans);
3339           if (GIMME_V == G_ARRAY) {
3340             EXTEND(SP, count);
3341             for (i = 0; i < count; ++i)
3342               PUSHs(sv_2mortal(newSViv(data[i])));
3343           }
3344           else {
3345             EXTEND(SP, 1);
3346             PUSHs(sv_2mortal(newSVpv(data, count * sizeof(i_sample_t))));
3347           }
3348           myfree(data);
3349         }
3350         else {
3351           if (GIMME_V != G_ARRAY) {
3352             EXTEND(SP, 1);
3353             PUSHs(&PL_sv_undef);
3354           }
3355         }
3356
3357
3358 Imager::ImgRaw
3359 i_img_masked_new(targ, mask, x, y, w, h)
3360         Imager::ImgRaw targ
3361         int x
3362         int y
3363         int w
3364         int h
3365       PREINIT:
3366         i_img *mask;
3367       CODE:
3368         if (SvOK(ST(1))) {
3369           if (!sv_isobject(ST(1)) 
3370               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3371             croak("i_img_masked_new: parameter 2 must undef or an image");
3372           }
3373           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3374         }
3375         else
3376           mask = NULL;
3377         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3378       OUTPUT:
3379         RETVAL
3380
3381 int
3382 i_plin(im, l, y, ...)
3383         Imager::ImgRaw  im
3384         int     l
3385         int     y
3386       PREINIT:
3387         i_color *work;
3388         int count, i;
3389       CODE:
3390         if (items > 3) {
3391           work = mymalloc(sizeof(i_color) * (items-3));
3392           for (i=0; i < items-3; ++i) {
3393             if (sv_isobject(ST(i+3)) 
3394                 && sv_derived_from(ST(i+3), "Imager::Color")) {
3395               IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3396               work[i] = *INT2PTR(i_color *, tmp);
3397             }
3398             else {
3399               myfree(work);
3400               croak("i_plin: pixels must be Imager::Color objects");
3401             }
3402           }
3403           /**(char *)0 = 1;*/
3404           RETVAL = i_plin(im, l, l+items-3, y, work);
3405           myfree(work);
3406         }
3407         else {
3408           RETVAL = 0;
3409         }
3410       OUTPUT:
3411         RETVAL
3412
3413 int
3414 i_ppixf(im, x, y, cl)
3415         Imager::ImgRaw im
3416         int x
3417         int y
3418         Imager::Color::Float cl
3419
3420 void
3421 i_gsampf(im, l, r, y, ...)
3422         Imager::ImgRaw im
3423         int l
3424         int r
3425         int y
3426       PREINIT:
3427         int *chans;
3428         int chan_count;
3429         i_fsample_t *data;
3430         int count, i;
3431       PPCODE:
3432         if (items < 5)
3433           croak("No channel numbers supplied to g_sampf()");
3434         if (l < r) {
3435           chan_count = items - 4;
3436           chans = mymalloc(sizeof(int) * chan_count);
3437           for (i = 0; i < chan_count; ++i)
3438             chans[i] = SvIV(ST(i+4));
3439           data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count);
3440           count = i_gsampf(im, l, r, y, data, chans, chan_count);
3441           if (GIMME_V == G_ARRAY) {
3442             EXTEND(SP, count);
3443             for (i = 0; i < count; ++i)
3444               PUSHs(sv_2mortal(newSVnv(data[i])));
3445           }
3446           else {
3447             EXTEND(SP, 1);
3448             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3449           }
3450         }
3451         else {
3452           if (GIMME_V != G_ARRAY) {
3453             EXTEND(SP, 1);
3454             PUSHs(&PL_sv_undef);
3455           }
3456         }
3457
3458 int
3459 i_plinf(im, l, y, ...)
3460         Imager::ImgRaw  im
3461         int     l
3462         int     y
3463       PREINIT:
3464         i_fcolor *work;
3465         int count, i;
3466       CODE:
3467         if (items > 3) {
3468           work = mymalloc(sizeof(i_fcolor) * (items-3));
3469           for (i=0; i < items-3; ++i) {
3470             if (sv_isobject(ST(i+3)) 
3471                 && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3472               IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3473               work[i] = *INT2PTR(i_fcolor *, tmp);
3474             }
3475             else {
3476               myfree(work);
3477               croak("i_plin: pixels must be Imager::Color::Float objects");
3478             }
3479           }
3480           /**(char *)0 = 1;*/
3481           RETVAL = i_plinf(im, l, l+items-3, y, work);
3482           myfree(work);
3483         }
3484         else {
3485           RETVAL = 0;
3486         }
3487       OUTPUT:
3488         RETVAL
3489
3490 SV *
3491 i_gpixf(im, x, y)
3492         Imager::ImgRaw im
3493         int x
3494         int y;
3495       PREINIT:
3496         i_fcolor *color;
3497       CODE:
3498         color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3499         if (i_gpixf(im, x, y, color) == 0) {
3500           ST(0) = sv_newmortal();
3501           sv_setref_pv(ST(0), "Imager::Color::Float", (void *)color);
3502         }
3503         else {
3504           myfree(color);
3505           ST(0) = &PL_sv_undef;
3506         }
3507         
3508 void
3509 i_glin(im, l, r, y)
3510         Imager::ImgRaw im
3511         int l
3512         int r
3513         int y
3514       PREINIT:
3515         i_color *vals;
3516         int count, i;
3517       PPCODE:
3518         if (l < r) {
3519           vals = mymalloc((r-l) * sizeof(i_color));
3520           count = i_glin(im, l, r, y, vals);
3521           EXTEND(SP, count);
3522           for (i = 0; i < count; ++i) {
3523             SV *sv;
3524             i_color *col = mymalloc(sizeof(i_color));
3525             sv = sv_newmortal();
3526             sv_setref_pv(sv, "Imager::Color", (void *)col);
3527             PUSHs(sv);
3528           }
3529           myfree(vals);
3530         }
3531
3532 void
3533 i_glinf(im, l, r, y)
3534         Imager::ImgRaw im
3535         int l
3536         int r
3537         int y
3538       PREINIT:
3539         i_fcolor *vals;
3540         int count, i;
3541       PPCODE:
3542         if (l < r) {
3543           vals = mymalloc((r-l) * sizeof(i_fcolor));
3544           count = i_glinf(im, l, r, y, vals);
3545           EXTEND(SP, count);
3546           for (i = 0; i < count; ++i) {
3547             SV *sv;
3548             i_fcolor *col = mymalloc(sizeof(i_fcolor));
3549             *col = vals[i];
3550             sv = sv_newmortal();
3551             sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3552             PUSHs(sv);
3553           }
3554           myfree(vals);
3555         }
3556
3557 Imager::ImgRaw
3558 i_img_16_new(x, y, ch)
3559         int x
3560         int y
3561         int ch
3562
3563 Imager::ImgRaw
3564 i_img_double_new(x, y, ch)
3565         int x
3566         int y
3567         int ch
3568
3569 undef_int
3570 i_tags_addn(im, name, code, idata)
3571         Imager::ImgRaw im
3572         int     code
3573         int     idata
3574       PREINIT:
3575         char *name;
3576         STRLEN len;
3577       CODE:
3578         if (SvOK(ST(1)))
3579           name = SvPV(ST(1), len);
3580         else
3581           name = NULL;
3582         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3583       OUTPUT:
3584         RETVAL
3585
3586 undef_int
3587 i_tags_add(im, name, code, data, idata)
3588         Imager::ImgRaw  im
3589         int code
3590         int idata
3591       PREINIT:
3592         char *name;
3593         char *data;
3594         STRLEN len;
3595       CODE:
3596         if (SvOK(ST(1)))
3597           name = SvPV(ST(1), len);
3598         else
3599           name = NULL;
3600         if (SvOK(ST(3)))
3601           data = SvPV(ST(3), len);
3602         else {
3603           data = NULL;
3604           len = 0;
3605         }
3606         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3607       OUTPUT:
3608         RETVAL
3609
3610 SV *
3611 i_tags_find(im, name, start)
3612         Imager::ImgRaw  im
3613         char *name
3614         int start
3615       PREINIT:
3616         int entry;
3617       CODE:
3618         if (i_tags_find(&im->tags, name, start, &entry)) {
3619           if (entry == 0)
3620             ST(0) = sv_2mortal(newSVpv("0 but true", 0));
3621           else
3622             ST(0) = sv_2mortal(newSViv(entry));
3623         } else {
3624           ST(0) = &PL_sv_undef;
3625         }
3626
3627 SV *
3628 i_tags_findn(im, code, start)
3629         Imager::ImgRaw  im
3630         int             code
3631         int             start
3632       PREINIT:
3633         int entry;
3634       CODE:
3635         if (i_tags_findn(&im->tags, code, start, &entry)) {
3636           if (entry == 0)
3637             ST(0) = sv_2mortal(newSVpv("0 but true", 0));
3638           else
3639             ST(0) = sv_2mortal(newSViv(entry));
3640         }
3641         else
3642           ST(0) = &PL_sv_undef;
3643
3644 int
3645 i_tags_delete(im, entry)
3646         Imager::ImgRaw  im
3647         int             entry
3648       CODE:
3649         RETVAL = i_tags_delete(&im->tags, entry);
3650       OUTPUT:
3651         RETVAL
3652
3653 int
3654 i_tags_delbyname(im, name)
3655         Imager::ImgRaw  im
3656         char *          name
3657       CODE:
3658         RETVAL = i_tags_delbyname(&im->tags, name);
3659       OUTPUT:
3660         RETVAL
3661
3662 int
3663 i_tags_delbycode(im, code)
3664         Imager::ImgRaw  im
3665         int             code
3666       CODE:
3667         RETVAL = i_tags_delbycode(&im->tags, code);
3668       OUTPUT:
3669         RETVAL
3670
3671 void
3672 i_tags_get(im, index)
3673         Imager::ImgRaw  im
3674         int             index
3675       PPCODE:
3676         if (index >= 0 && index < im->tags.count) {
3677           i_img_tag *entry = im->tags.tags + index;
3678           EXTEND(SP, 5);
3679         
3680           if (entry->name) {
3681             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3682           }
3683           else {
3684             PUSHs(sv_2mortal(newSViv(entry->code)));
3685           }
3686           if (entry->data) {
3687             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3688           }
3689           else {
3690             PUSHs(sv_2mortal(newSViv(entry->idata)));
3691           }
3692         }
3693
3694 int
3695 i_tags_count(im)
3696         Imager::ImgRaw  im
3697       CODE:
3698         RETVAL = im->tags.count;
3699       OUTPUT:
3700         RETVAL
3701
3702 #ifdef HAVE_WIN32
3703
3704 void
3705 i_wf_bbox(face, size, text)
3706         char *face
3707         int size
3708         char *text
3709       PREINIT:
3710         int cords[6];
3711       PPCODE:
3712         if (i_wf_bbox(face, size, text, strlen(text), cords)) {
3713           EXTEND(SP, 6);  
3714           PUSHs(sv_2mortal(newSViv(cords[0])));
3715           PUSHs(sv_2mortal(newSViv(cords[1])));
3716           PUSHs(sv_2mortal(newSViv(cords[2])));
3717           PUSHs(sv_2mortal(newSViv(cords[3])));
3718           PUSHs(sv_2mortal(newSViv(cords[4])));
3719           PUSHs(sv_2mortal(newSViv(cords[5])));
3720         }
3721
3722 undef_int
3723 i_wf_text(face, im, tx, ty, cl, size, text, align, aa)
3724         char *face
3725         Imager::ImgRaw im
3726         int tx
3727         int ty
3728         Imager::Color cl
3729         int size
3730         char *text
3731         int align
3732         int aa
3733       CODE:
3734         RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text), 
3735                            align, aa);
3736       OUTPUT:
3737         RETVAL
3738
3739 undef_int
3740 i_wf_cp(face, im, tx, ty, channel, size, text, align, aa)
3741         char *face
3742         Imager::ImgRaw im
3743         int tx
3744         int ty
3745         int channel
3746         int size
3747         char *text
3748         int align
3749         int aa
3750       CODE:
3751         RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text), 
3752                          align, aa);
3753       OUTPUT:
3754         RETVAL
3755
3756
3757 #endif
3758
3759 #ifdef HAVE_FT2
3760
3761 MODULE = Imager         PACKAGE = Imager::Font::FT2     PREFIX=FT2_
3762
3763 #define FT2_DESTROY(font) i_ft2_destroy(font)
3764
3765 void
3766 FT2_DESTROY(font)
3767         Imager::Font::FT2 font
3768
3769 MODULE = Imager         PACKAGE = Imager::Font::FreeType2 
3770
3771 Imager::Font::FT2
3772 i_ft2_new(name, index)
3773         char *name
3774         int index
3775
3776 undef_int
3777 i_ft2_setdpi(font, xdpi, ydpi)
3778         Imager::Font::FT2 font
3779         int xdpi
3780         int ydpi
3781
3782 void
3783 i_ft2_getdpi(font)
3784         Imager::Font::FT2 font
3785       PREINIT:
3786         int xdpi, ydpi;
3787       CODE:
3788         if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
3789           EXTEND(SP, 2);
3790           PUSHs(sv_2mortal(newSViv(xdpi)));
3791           PUSHs(sv_2mortal(newSViv(ydpi)));
3792         }
3793
3794 undef_int
3795 i_ft2_sethinting(font, hinting)
3796         Imager::Font::FT2 font
3797         int hinting
3798
3799 undef_int
3800 i_ft2_settransform(font, matrix)
3801         Imager::Font::FT2 font
3802       PREINIT:
3803         double matrix[6];
3804         int len;
3805         AV *av;
3806         SV *sv1;
3807         int i;
3808       CODE:
3809         if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
3810           croak("i_ft2_settransform: parameter 2 must be an array ref\n");
3811         av=(AV*)SvRV(ST(1));
3812         len=av_len(av)+1;
3813         if (len > 6)
3814           len = 6;
3815         for (i = 0; i < len; ++i) {
3816           sv1=(*(av_fetch(av,i,0)));
3817           matrix[i] = SvNV(sv1);
3818         }
3819         for (; i < 6; ++i)
3820           matrix[i] = 0;
3821         RETVAL = i_ft2_settransform(font, matrix);
3822       OUTPUT:
3823         RETVAL
3824
3825 void
3826 i_ft2_bbox(font, cheight, cwidth, text, utf8)
3827         Imager::Font::FT2 font
3828         double cheight
3829         double cwidth
3830         char *text
3831         int utf8
3832       PREINIT:
3833         int bbox[6];
3834         int i;
3835       PPCODE:
3836 #ifdef SvUTF8
3837         if (SvUTF8(ST(3)))
3838           utf8 = 1;
3839 #endif
3840         if (i_ft2_bbox(font, cheight, cwidth, text, strlen(text), bbox, utf8)) {
3841           EXTEND(SP, 6);
3842           for (i = 0; i < 6; ++i)
3843             PUSHs(sv_2mortal(newSViv(bbox[i])));
3844         }
3845
3846 void
3847 i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
3848         Imager::Font::FT2 font
3849         double cheight
3850         double cwidth
3851         char *text
3852         int vlayout
3853         int utf8
3854       PREINIT:
3855         int bbox[8];
3856         int i;
3857       PPCODE:
3858 #ifdef SvUTF8
3859         if (SvUTF8(ST(3)))
3860           utf8 = 1;
3861 #endif
3862         if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
3863                          utf8, bbox)) {
3864           EXTEND(SP, 8);
3865           for (i = 0; i < 8; ++i)
3866             PUSHs(sv_2mortal(newSViv(bbox[i])));
3867         }
3868
3869 undef_int
3870 i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
3871         Imager::Font::FT2 font
3872         Imager::ImgRaw im
3873         int tx
3874         int ty
3875         Imager::Color cl
3876         double cheight
3877         double cwidth
3878         int align
3879         int aa
3880         int vlayout
3881         int utf8
3882       PREINIT:
3883         char *text;
3884         STRLEN len;
3885       CODE:
3886 #ifdef SvUTF8
3887         if (SvUTF8(ST(7))) {
3888           utf8 = 1;
3889         }
3890 #endif
3891         text = SvPV(ST(7), len);
3892         RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
3893                             len, align, aa, vlayout, utf8);
3894       OUTPUT:
3895         RETVAL
3896
3897 undef_int
3898 i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8)
3899         Imager::Font::FT2 font
3900         Imager::ImgRaw im
3901         int tx
3902         int ty
3903         int channel
3904         double cheight
3905         double cwidth
3906         char *text
3907         int align
3908         int aa
3909         int vlayout
3910         int utf8
3911       CODE:
3912 #ifdef SvUTF8
3913         if (SvUTF8(ST(7)))
3914           utf8 = 1;
3915 #endif
3916         RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
3917                           strlen(text), align, aa, vlayout, 1);
3918       OUTPUT:
3919         RETVAL
3920
3921 void
3922 ft2_transform_box(font, x0, x1, x2, x3)
3923         Imager::Font::FT2 font
3924         int x0
3925         int x1
3926         int x2
3927         int x3
3928       PREINIT:
3929         int box[4];
3930       PPCODE:
3931         box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
3932         ft2_transform_box(font, box);
3933           EXTEND(SP, 4);
3934           PUSHs(sv_2mortal(newSViv(box[0])));
3935           PUSHs(sv_2mortal(newSViv(box[1])));
3936           PUSHs(sv_2mortal(newSViv(box[2])));
3937           PUSHs(sv_2mortal(newSViv(box[3])));
3938
3939 void
3940 i_ft2_has_chars(handle, text, utf8)
3941         Imager::Font::FT2 handle
3942         int utf8
3943       PREINIT:
3944         char *text;
3945         STRLEN len;
3946         char *work;
3947         int count;
3948         int i;
3949       PPCODE:
3950 #ifdef SvUTF8
3951         if (SvUTF8(ST(7)))
3952           utf8 = 1;
3953 #endif
3954         text = SvPV(ST(1), len);
3955         work = mymalloc(len);
3956         count = i_ft2_has_chars(handle, text, len, utf8, work);
3957         if (GIMME_V == G_ARRAY) {
3958           EXTEND(SP, count);
3959           for (i = 0; i < count; ++i) {
3960             PUSHs(sv_2mortal(newSViv(work[i])));
3961           }
3962         }
3963         else {
3964           EXTEND(SP, 1);
3965           PUSHs(sv_2mortal(newSVpv(work, count)));
3966         }
3967         myfree(work);
3968
3969 #endif
3970
3971 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
3972
3973 void
3974 IFILL_DESTROY(fill)
3975         Imager::FillHandle fill
3976
3977 MODULE = Imager         PACKAGE = Imager
3978
3979 Imager::FillHandle
3980 i_new_fill_solid(cl, combine)
3981         Imager::Color cl
3982         int combine
3983
3984 Imager::FillHandle
3985 i_new_fill_solidf(cl, combine)
3986         Imager::Color::Float cl
3987         int combine
3988
3989 Imager::FillHandle
3990 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
3991         Imager::Color fg
3992         Imager::Color bg
3993         int combine
3994         int hatch
3995         int dx
3996         int dy
3997       PREINIT:
3998         unsigned char *cust_hatch;
3999         STRLEN len;
4000       CODE:
4001         if (SvOK(ST(4))) {
4002           cust_hatch = SvPV(ST(4), len);
4003         }
4004         else
4005           cust_hatch = NULL;
4006         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
4007       OUTPUT:
4008         RETVAL
4009
4010 Imager::FillHandle
4011 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
4012         Imager::Color::Float fg
4013         Imager::Color::Float bg
4014         int combine
4015         int hatch
4016         int dx
4017         int dy
4018       PREINIT:
4019         unsigned char *cust_hatch;
4020         STRLEN len;
4021       CODE:
4022         if (SvOK(ST(4))) {
4023           cust_hatch = SvPV(ST(4), len);
4024         }
4025         else
4026           cust_hatch = NULL;
4027         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
4028       OUTPUT:
4029         RETVAL
4030
4031 Imager::FillHandle
4032 i_new_fill_image(src, matrix, xoff, yoff, combine)
4033         Imager::ImgRaw src
4034         int xoff
4035         int yoff
4036         int combine
4037       PREINIT:
4038         double matrix[9];
4039         double *matrixp;
4040         AV *av;
4041         IV len;
4042         SV *sv1;
4043         int i;
4044       CODE:
4045         if (!SvOK(ST(1))) {
4046           matrixp = NULL;
4047         }
4048         else {
4049           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4050             croak("i_new_fill_image: parameter must be an arrayref");
4051           av=(AV*)SvRV(ST(1));
4052           len=av_len(av)+1;
4053           if (len > 9)
4054             len = 9;
4055           for (i = 0; i < len; ++i) {
4056             sv1=(*(av_fetch(av,i,0)));
4057             matrix[i] = SvNV(sv1);
4058           }
4059           for (; i < 9; ++i)
4060             matrix[i] = 0;
4061           matrixp = matrix;
4062         }
4063         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4064       OUTPUT:
4065         RETVAL