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