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