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