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