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