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