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