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