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