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