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