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