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