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