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