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