]> git.imager.perl.org - imager.git/blob - Imager.xs
f0afbe57aa7843ebfe2119584c48fcc73dd5ddaf
[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 #if i_int_hlines_testing()
866
867 typedef i_int_hlines *Imager__Internal__Hlines;
868
869 static i_int_hlines *
870 i_int_hlines_new(int start_y, int count_y, int start_x, int count_x) {
871   i_int_hlines *result = mymalloc(sizeof(i_int_hlines));
872   i_int_init_hlines(result, start_y, count_y, start_x, count_x);
873
874   return result;
875 }
876
877 static i_int_hlines *
878 i_int_hlines_new_img(i_img *im) {
879   i_int_hlines *result = mymalloc(sizeof(i_int_hlines));
880   i_int_init_hlines_img(result, im);
881
882   return result;
883 }
884
885 static void
886 i_int_hlines_DESTROY(i_int_hlines *hlines) {
887   i_int_hlines_destroy(hlines);
888   myfree(hlines);
889 }
890
891 #define i_int_hlines_CLONE_SKIP(cls) 1
892
893 static int seg_compare(const void *vleft, const void *vright) {
894   const i_int_hline_seg *left = vleft;
895   const i_int_hline_seg *right = vright;
896
897   return left->minx - right->minx;
898 }
899
900 static SV *
901 i_int_hlines_dump(i_int_hlines *hlines) {
902   dTHX;
903   SV *dump = newSVpvf("start_y: %d limit_y: %d start_x: %d limit_x: %d\n",
904         hlines->start_y, hlines->limit_y, hlines->start_x, hlines->limit_x);
905   int y;
906   
907   for (y = hlines->start_y; y < hlines->limit_y; ++y) {
908     i_int_hline_entry *entry = hlines->entries[y-hlines->start_y];
909     if (entry) {
910       int i;
911       /* sort the segments, if any */
912       if (entry->count)
913         qsort(entry->segs, entry->count, sizeof(i_int_hline_seg), seg_compare);
914
915       sv_catpvf(dump, " %d (%d):", y, entry->count);
916       for (i = 0; i < entry->count; ++i) {
917         sv_catpvf(dump, " [%d, %d)", entry->segs[i].minx, 
918                   entry->segs[i].x_limit);
919       }
920       sv_catpv(dump, "\n");
921     }
922   }
923
924   return dump;
925 }
926
927 #endif
928
929 static im_pl_ext_funcs im_perl_funcs =
930 {
931   IMAGER_PL_API_VERSION,
932   IMAGER_PL_API_LEVEL,
933   ip_handle_quant_opts,
934   ip_cleanup_quant_opts,
935   ip_copy_colors_back
936 };
937
938 #define PERL_PL_SET_GLOBAL_CALLBACKS \
939   sv_setiv(get_sv(PERL_PL_FUNCTION_TABLE_NAME, 1), PTR2IV(&im_perl_funcs));
940
941 #ifdef IMEXIF_ENABLE
942 #define i_exif_enabled() 1
943 #else
944 #define i_exif_enabled() 0
945 #endif
946
947 /* trying to use more C style names, map them here */
948 #define i_io_DESTROY(ig) io_glue_destroy(ig)
949
950 #define i_img_get_width(im) ((im)->xsize)
951 #define i_img_get_height(im) ((im)->ysize)
952
953 #define i_img_epsilonf() (DBL_EPSILON * 4)
954
955 MODULE = Imager         PACKAGE = Imager::Color PREFIX = ICL_
956
957 Imager::Color
958 ICL_new_internal(r,g,b,a)
959                unsigned char     r
960                unsigned char     g
961                unsigned char     b
962                unsigned char     a
963
964 void
965 ICL_DESTROY(cl)
966                Imager::Color    cl
967
968
969 void
970 ICL_set_internal(cl,r,g,b,a)
971                Imager::Color    cl
972                unsigned char     r
973                unsigned char     g
974                unsigned char     b
975                unsigned char     a
976            PPCODE:
977                ICL_set_internal(cl, r, g, b, a);
978                EXTEND(SP, 1);
979                PUSHs(ST(0));
980
981 void
982 ICL_info(cl)
983                Imager::Color    cl
984
985
986 void
987 ICL_rgba(cl)
988               Imager::Color     cl
989             PPCODE:
990                 EXTEND(SP, 4);
991                 PUSHs(sv_2mortal(newSVnv(cl->rgba.r)));
992                 PUSHs(sv_2mortal(newSVnv(cl->rgba.g)));
993                 PUSHs(sv_2mortal(newSVnv(cl->rgba.b)));
994                 PUSHs(sv_2mortal(newSVnv(cl->rgba.a)));
995
996 Imager::Color
997 i_hsv_to_rgb(c)
998         Imager::Color c
999       CODE:
1000         RETVAL = mymalloc(sizeof(i_color));
1001         *RETVAL = *c;
1002         i_hsv_to_rgb(RETVAL);
1003       OUTPUT:
1004         RETVAL
1005         
1006 Imager::Color
1007 i_rgb_to_hsv(c)
1008         Imager::Color c
1009       CODE:
1010         RETVAL = mymalloc(sizeof(i_color));
1011         *RETVAL = *c;
1012         i_rgb_to_hsv(RETVAL);
1013       OUTPUT:
1014         RETVAL
1015         
1016
1017
1018 MODULE = Imager        PACKAGE = Imager::Color::Float  PREFIX=ICLF_
1019
1020 Imager::Color::Float
1021 ICLF_new_internal(r, g, b, a)
1022         double r
1023         double g
1024         double b
1025         double a
1026
1027 void
1028 ICLF_DESTROY(cl)
1029         Imager::Color::Float    cl
1030
1031 void
1032 ICLF_rgba(cl)
1033         Imager::Color::Float    cl
1034       PREINIT:
1035         int ch;
1036       PPCODE:
1037         EXTEND(SP, MAXCHANNELS);
1038         for (ch = 0; ch < MAXCHANNELS; ++ch) {
1039         /* printf("%d: %g\n", ch, cl->channel[ch]); */
1040           PUSHs(sv_2mortal(newSVnv(cl->channel[ch])));
1041         }
1042
1043 void
1044 ICLF_set_internal(cl,r,g,b,a)
1045         Imager::Color::Float    cl
1046         double     r
1047         double     g
1048         double     b
1049         double     a
1050       PPCODE:
1051         cl->rgba.r = r;
1052         cl->rgba.g = g;
1053         cl->rgba.b = b;
1054         cl->rgba.a = a;                
1055         EXTEND(SP, 1);
1056         PUSHs(ST(0));
1057
1058 Imager::Color::Float
1059 i_hsv_to_rgb(c)
1060         Imager::Color::Float c
1061       CODE:
1062         RETVAL = mymalloc(sizeof(i_fcolor));
1063         *RETVAL = *c;
1064         i_hsv_to_rgbf(RETVAL);
1065       OUTPUT:
1066         RETVAL
1067         
1068 Imager::Color::Float
1069 i_rgb_to_hsv(c)
1070         Imager::Color::Float c
1071       CODE:
1072         RETVAL = mymalloc(sizeof(i_fcolor));
1073         *RETVAL = *c;
1074         i_rgb_to_hsvf(RETVAL);
1075       OUTPUT:
1076         RETVAL
1077
1078 MODULE = Imager         PACKAGE = Imager::ImgRaw        PREFIX = IIM_
1079
1080 Imager::ImgRaw
1081 IIM_new(x,y,ch)
1082                int     x
1083                int     y
1084                int     ch
1085
1086 void
1087 IIM_DESTROY(im)
1088                Imager::ImgRaw    im
1089
1090
1091
1092 MODULE = Imager         PACKAGE = Imager
1093
1094 PROTOTYPES: ENABLE
1095
1096
1097 Imager::IO
1098 io_new_fd(fd)
1099                          int     fd
1100
1101 Imager::IO
1102 io_new_bufchain()
1103
1104
1105 Imager::IO
1106 io_new_buffer(data)
1107           char   *data
1108         PREINIT:
1109           size_t length;
1110         CODE:
1111           SvPV(ST(0), length);
1112           SvREFCNT_inc(ST(0));
1113           RETVAL = io_new_buffer(data, length, my_SvREFCNT_dec, ST(0));
1114         OUTPUT:
1115           RETVAL
1116
1117 Imager::IO
1118 io_new_cb(writecb, readcb, seekcb, closecb, maxwrite = CBDATA_BUFSIZE)
1119         SV *writecb;
1120         SV *readcb;
1121         SV *seekcb;
1122         SV *closecb;
1123         int maxwrite;
1124       PREINIT:
1125         struct cbdata *cbd;
1126       CODE:
1127         cbd = mymalloc(sizeof(struct cbdata));
1128         SvREFCNT_inc(writecb);
1129         cbd->writecb = writecb;
1130         SvREFCNT_inc(readcb);
1131         cbd->readcb = readcb;
1132         SvREFCNT_inc(seekcb);
1133         cbd->seekcb = seekcb;
1134         SvREFCNT_inc(closecb);
1135         cbd->closecb = closecb;
1136         cbd->reading = cbd->writing = cbd->where = cbd->used = 0;
1137         if (maxwrite > CBDATA_BUFSIZE)
1138           maxwrite = CBDATA_BUFSIZE;
1139         cbd->maxlength = maxwrite;
1140         RETVAL = io_new_cb(cbd, io_reader, io_writer, io_seeker, io_closer, 
1141                            io_destroyer);
1142       OUTPUT:
1143         RETVAL
1144
1145 void
1146 io_slurp(ig)
1147         Imager::IO     ig
1148              PREINIT:
1149               unsigned char*    data;
1150               size_t    tlength;
1151              PPCODE:
1152               data    = NULL;
1153               tlength = io_slurp(ig, &data);
1154               EXTEND(SP,1);
1155               PUSHs(sv_2mortal(newSVpv((char *)data,tlength)));
1156               myfree(data);
1157
1158
1159 undef_int
1160 i_set_image_file_limits(width, height, bytes)
1161         int width
1162         int height
1163         int bytes
1164
1165 void
1166 i_get_image_file_limits()
1167       PREINIT:
1168         int width, height, bytes;
1169       PPCODE:
1170         if (i_get_image_file_limits(&width, &height, &bytes)) {
1171           EXTEND(SP, 3);
1172           PUSHs(sv_2mortal(newSViv(width)));
1173           PUSHs(sv_2mortal(newSViv(height)));
1174           PUSHs(sv_2mortal(newSViv(bytes)));
1175         }
1176
1177 MODULE = Imager         PACKAGE = Imager::IO    PREFIX = i_io_
1178
1179 int
1180 i_io_write(ig, data_sv)
1181         Imager::IO ig
1182         SV *data_sv
1183       PREINIT:
1184         void *data;
1185         STRLEN size;
1186       CODE:
1187 #ifdef SvUTF8
1188         if (SvUTF8(data_sv)) {
1189           data_sv = sv_2mortal(newSVsv(data_sv));
1190           /* yes, we want this to croak() if the SV can't be downgraded */
1191           sv_utf8_downgrade(data_sv, FALSE);
1192         }
1193 #endif        
1194         data = SvPV(data_sv, size);
1195         RETVAL = i_io_write(ig, data, size);
1196       OUTPUT:
1197         RETVAL
1198
1199 void
1200 i_io_read(ig, buffer_sv, size)
1201         Imager::IO ig
1202         SV *buffer_sv
1203         int size
1204       PREINIT:
1205         void *buffer;
1206         int result;
1207       PPCODE:
1208         if (size <= 0)
1209           croak("size negative in call to i_io_read()");
1210         /* prevent an undefined value warning if they supplied an 
1211            undef buffer.
1212            Orginally conditional on !SvOK(), but this will prevent the
1213            downgrade from croaking */
1214         sv_setpvn(buffer_sv, "", 0);
1215 #ifdef SvUTF8
1216         if (SvUTF8(buffer_sv))
1217           sv_utf8_downgrade(buffer_sv, FALSE);
1218 #endif
1219         buffer = SvGROW(buffer_sv, size+1);
1220         result = i_io_read(ig, buffer, size);
1221         if (result >= 0) {
1222           SvCUR_set(buffer_sv, result);
1223           *SvEND(buffer_sv) = '\0';
1224           SvPOK_only(buffer_sv);
1225           EXTEND(SP, 1);
1226           PUSHs(sv_2mortal(newSViv(result)));
1227         }
1228         ST(1) = buffer_sv;
1229         SvSETMAGIC(ST(1));
1230
1231 void
1232 i_io_read2(ig, size)
1233         Imager::IO ig
1234         int size
1235       PREINIT:
1236         SV *buffer_sv;
1237         void *buffer;
1238         int result;
1239       PPCODE:
1240         if (size <= 0)
1241           croak("size negative in call to i_io_read2()");
1242         buffer_sv = newSV(size);
1243         buffer = SvGROW(buffer_sv, size+1);
1244         result = i_io_read(ig, buffer, size);
1245         if (result >= 0) {
1246           SvCUR_set(buffer_sv, result);
1247           *SvEND(buffer_sv) = '\0';
1248           SvPOK_only(buffer_sv);
1249           EXTEND(SP, 1);
1250           PUSHs(sv_2mortal(buffer_sv));
1251         }
1252         else {
1253           /* discard it */
1254           SvREFCNT_dec(buffer_sv);
1255         }
1256
1257 int
1258 i_io_seek(ig, position, whence)
1259         Imager::IO ig
1260         long position
1261         int whence
1262
1263 int
1264 i_io_close(ig)
1265         Imager::IO ig
1266
1267 void
1268 i_io_DESTROY(ig)
1269         Imager::IO     ig
1270
1271 int
1272 i_io_CLONE_SKIP(...)
1273     CODE:
1274         RETVAL = 1;
1275     OUTPUT:
1276         RETVAL
1277
1278 MODULE = Imager         PACKAGE = Imager
1279
1280 PROTOTYPES: ENABLE
1281
1282 void
1283 i_list_formats()
1284              PREINIT:
1285               char*    item;
1286                int     i;
1287              PPCODE:
1288                i=0;
1289                while( (item=i_format_list[i++]) != NULL ) {
1290                       EXTEND(SP, 1);
1291                       PUSHs(sv_2mortal(newSVpv(item,0)));
1292                }
1293
1294 Imager::ImgRaw
1295 i_img_new()
1296
1297 Imager::ImgRaw
1298 i_img_empty(im,x,y)
1299     Imager::ImgRaw     im
1300                int     x
1301                int     y
1302
1303 Imager::ImgRaw
1304 i_img_empty_ch(im,x,y,ch)
1305     Imager::ImgRaw     im
1306                int     x
1307                int     y
1308                int     ch
1309
1310 Imager::ImgRaw
1311 i_sametype(im, x, y)
1312     Imager::ImgRaw im
1313                int x
1314                int y
1315
1316 Imager::ImgRaw
1317 i_sametype_chans(im, x, y, channels)
1318     Imager::ImgRaw im
1319                int x
1320                int y
1321                int channels
1322
1323 void
1324 i_init_log(name_sv,level)
1325               SV*    name_sv
1326                int     level
1327         PREINIT:
1328           const char *name = SvOK(name_sv) ? SvPV_nolen(name_sv) : NULL;
1329         CODE:
1330           i_init_log(name, level);
1331
1332 void
1333 i_log_entry(string,level)
1334               char*    string
1335                int     level
1336
1337
1338 void
1339 i_img_exorcise(im)
1340     Imager::ImgRaw     im
1341
1342 void
1343 i_img_destroy(im)
1344     Imager::ImgRaw     im
1345
1346 void
1347 i_img_info(im)
1348     Imager::ImgRaw     im
1349              PREINIT:
1350                int     info[4];
1351              PPCODE:
1352                i_img_info(im,info);
1353                EXTEND(SP, 4);
1354                PUSHs(sv_2mortal(newSViv(info[0])));
1355                PUSHs(sv_2mortal(newSViv(info[1])));
1356                PUSHs(sv_2mortal(newSViv(info[2])));
1357                PUSHs(sv_2mortal(newSViv(info[3])));
1358
1359
1360
1361
1362 void
1363 i_img_setmask(im,ch_mask)
1364     Imager::ImgRaw     im
1365                int     ch_mask
1366
1367 int
1368 i_img_getmask(im)
1369     Imager::ImgRaw     im
1370
1371 int
1372 i_img_getchannels(im)
1373     Imager::ImgRaw     im
1374
1375 void
1376 i_img_getdata(im)
1377     Imager::ImgRaw     im
1378              PPCODE:
1379                EXTEND(SP, 1);
1380                PUSHs(im->idata ? 
1381                      sv_2mortal(newSVpv((char *)im->idata, im->bytes)) 
1382                      : &PL_sv_undef);
1383
1384 IV
1385 i_img_get_width(im)
1386     Imager::ImgRaw      im
1387
1388 IV
1389 i_img_get_height(im)
1390     Imager::ImgRaw      im
1391
1392
1393 void
1394 i_img_is_monochrome(im)
1395         Imager::ImgRaw im
1396       PREINIT:
1397         int zero_is_white;
1398         int result;
1399       PPCODE:
1400         result = i_img_is_monochrome(im, &zero_is_white);
1401         if (result) {
1402           if (GIMME_V == G_ARRAY) {
1403             EXTEND(SP, 2);
1404             PUSHs(&PL_sv_yes);
1405             PUSHs(sv_2mortal(newSViv(zero_is_white)));
1406           }
1407           else {
1408             EXTEND(SP, 1);
1409             PUSHs(&PL_sv_yes);
1410           }
1411         }
1412
1413 void
1414 i_line(im,x1,y1,x2,y2,val,endp)
1415     Imager::ImgRaw     im
1416                int     x1
1417                int     y1
1418                int     x2
1419                int     y2
1420      Imager::Color     val
1421                int     endp
1422
1423 void
1424 i_line_aa(im,x1,y1,x2,y2,val,endp)
1425     Imager::ImgRaw     im
1426                int     x1
1427                int     y1
1428                int     x2
1429                int     y2
1430      Imager::Color     val
1431                int     endp
1432
1433 void
1434 i_box(im,x1,y1,x2,y2,val)
1435     Imager::ImgRaw     im
1436                int     x1
1437                int     y1
1438                int     x2
1439                int     y2
1440      Imager::Color     val
1441
1442 void
1443 i_box_filled(im,x1,y1,x2,y2,val)
1444     Imager::ImgRaw     im
1445                int     x1
1446                int     y1
1447                int     x2
1448                int     y2
1449            Imager::Color    val
1450
1451 int
1452 i_box_filledf(im,x1,y1,x2,y2,val)
1453     Imager::ImgRaw     im
1454                int     x1
1455                int     y1
1456                int     x2
1457                int     y2
1458            Imager::Color::Float    val
1459
1460 void
1461 i_box_cfill(im,x1,y1,x2,y2,fill)
1462     Imager::ImgRaw     im
1463                int     x1
1464                int     y1
1465                int     x2
1466                int     y2
1467            Imager::FillHandle    fill
1468
1469 void
1470 i_arc(im,x,y,rad,d1,d2,val)
1471     Imager::ImgRaw     im
1472                int     x
1473                int     y
1474              float     rad
1475              float     d1
1476              float     d2
1477            Imager::Color    val
1478
1479 void
1480 i_arc_aa(im,x,y,rad,d1,d2,val)
1481     Imager::ImgRaw     im
1482             double     x
1483             double     y
1484             double     rad
1485             double     d1
1486             double     d2
1487            Imager::Color    val
1488
1489 void
1490 i_arc_cfill(im,x,y,rad,d1,d2,fill)
1491     Imager::ImgRaw     im
1492                int     x
1493                int     y
1494              float     rad
1495              float     d1
1496              float     d2
1497            Imager::FillHandle    fill
1498
1499 void
1500 i_arc_aa_cfill(im,x,y,rad,d1,d2,fill)
1501     Imager::ImgRaw     im
1502             double     x
1503             double     y
1504             double     rad
1505             double     d1
1506             double     d2
1507            Imager::FillHandle   fill
1508
1509
1510 void
1511 i_circle_aa(im,x,y,rad,val)
1512     Imager::ImgRaw     im
1513              float     x
1514              float     y
1515              float     rad
1516            Imager::Color    val
1517
1518 int
1519 i_circle_out(im,x,y,rad,val)
1520     Imager::ImgRaw     im
1521              i_img_dim     x
1522              i_img_dim     y
1523              i_img_dim     rad
1524            Imager::Color    val
1525
1526 int
1527 i_circle_out_aa(im,x,y,rad,val)
1528     Imager::ImgRaw     im
1529              i_img_dim     x
1530              i_img_dim     y
1531              i_img_dim     rad
1532            Imager::Color    val
1533
1534 int
1535 i_arc_out(im,x,y,rad,d1,d2,val)
1536     Imager::ImgRaw     im
1537              i_img_dim     x
1538              i_img_dim     y
1539              i_img_dim     rad
1540              float d1
1541              float d2
1542            Imager::Color    val
1543
1544 int
1545 i_arc_out_aa(im,x,y,rad,d1,d2,val)
1546     Imager::ImgRaw     im
1547              i_img_dim     x
1548              i_img_dim     y
1549              i_img_dim     rad
1550              float d1
1551              float d2
1552            Imager::Color    val
1553
1554
1555 void
1556 i_bezier_multi(im,xc,yc,val)
1557     Imager::ImgRaw     im
1558              Imager::Color  val
1559              PREINIT:
1560              double   *x,*y;
1561              int       len;
1562              AV       *av1;
1563              AV       *av2;
1564              SV       *sv1;
1565              SV       *sv2;
1566              int i;
1567              PPCODE:
1568              ICL_info(val);
1569              if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
1570              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
1571              if (!SvROK(ST(2))) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
1572              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
1573              av1=(AV*)SvRV(ST(1));
1574              av2=(AV*)SvRV(ST(2));
1575              if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
1576              len=av_len(av1)+1;
1577              x=mymalloc( len*sizeof(double) );
1578              y=mymalloc( len*sizeof(double) );
1579              for(i=0;i<len;i++) {
1580                sv1=(*(av_fetch(av1,i,0)));
1581                sv2=(*(av_fetch(av2,i,0)));
1582                x[i]=(double)SvNV(sv1);
1583                y[i]=(double)SvNV(sv2);
1584              }
1585              i_bezier_multi(im,len,x,y,val);
1586              myfree(x);
1587              myfree(y);
1588
1589
1590 int
1591 i_poly_aa(im,xc,yc,val)
1592     Imager::ImgRaw     im
1593              Imager::Color  val
1594              PREINIT:
1595              double   *x,*y;
1596              int       len;
1597              AV       *av1;
1598              AV       *av2;
1599              SV       *sv1;
1600              SV       *sv2;
1601              int i;
1602              CODE:
1603              ICL_info(val);
1604              if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1605              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1606              if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1607              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1608              av1=(AV*)SvRV(ST(1));
1609              av2=(AV*)SvRV(ST(2));
1610              if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_poly_aa must be equal length\n");
1611              len=av_len(av1)+1;
1612              x=mymalloc( len*sizeof(double) );
1613              y=mymalloc( len*sizeof(double) );
1614              for(i=0;i<len;i++) {
1615                sv1=(*(av_fetch(av1,i,0)));
1616                sv2=(*(av_fetch(av2,i,0)));
1617                x[i]=(double)SvNV(sv1);
1618                y[i]=(double)SvNV(sv2);
1619              }
1620              RETVAL = i_poly_aa(im,len,x,y,val);
1621              myfree(x);
1622              myfree(y);
1623              OUTPUT:
1624                RETVAL
1625
1626 int
1627 i_poly_aa_cfill(im,xc,yc,fill)
1628     Imager::ImgRaw     im
1629      Imager::FillHandle     fill
1630              PREINIT:
1631              double   *x,*y;
1632              int       len;
1633              AV       *av1;
1634              AV       *av2;
1635              SV       *sv1;
1636              SV       *sv2;
1637              int i;
1638              CODE:
1639              if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1640              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1641              if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1642              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1643              av1=(AV*)SvRV(ST(1));
1644              av2=(AV*)SvRV(ST(2));
1645              if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n");
1646              len=av_len(av1)+1;
1647              x=mymalloc( len*sizeof(double) );
1648              y=mymalloc( len*sizeof(double) );
1649              for(i=0;i<len;i++) {
1650                sv1=(*(av_fetch(av1,i,0)));
1651                sv2=(*(av_fetch(av2,i,0)));
1652                x[i]=(double)SvNV(sv1);
1653                y[i]=(double)SvNV(sv2);
1654              }
1655              RETVAL = i_poly_aa_cfill(im,len,x,y,fill);
1656              myfree(x);
1657              myfree(y);
1658              OUTPUT:
1659                RETVAL
1660
1661
1662
1663 undef_int
1664 i_flood_fill(im,seedx,seedy,dcol)
1665     Imager::ImgRaw     im
1666                int     seedx
1667                int     seedy
1668      Imager::Color     dcol
1669
1670 undef_int
1671 i_flood_cfill(im,seedx,seedy,fill)
1672     Imager::ImgRaw     im
1673                int     seedx
1674                int     seedy
1675      Imager::FillHandle     fill
1676
1677 undef_int
1678 i_flood_fill_border(im,seedx,seedy,dcol, border)
1679     Imager::ImgRaw     im
1680                int     seedx
1681                int     seedy
1682      Imager::Color     dcol
1683      Imager::Color     border
1684
1685 undef_int
1686 i_flood_cfill_border(im,seedx,seedy,fill, border)
1687     Imager::ImgRaw     im
1688                int     seedx
1689                int     seedy
1690      Imager::FillHandle     fill
1691      Imager::Color     border
1692
1693
1694 void
1695 i_copyto(im,src,x1,y1,x2,y2,tx,ty)
1696     Imager::ImgRaw     im
1697     Imager::ImgRaw     src
1698                int     x1
1699                int     y1
1700                int     x2
1701                int     y2
1702                int     tx
1703                int     ty
1704
1705
1706 void
1707 i_copyto_trans(im,src,x1,y1,x2,y2,tx,ty,trans)
1708     Imager::ImgRaw     im
1709     Imager::ImgRaw     src
1710                int     x1
1711                int     y1
1712                int     x2
1713                int     y2
1714                int     tx
1715                int     ty
1716      Imager::Color     trans
1717
1718 Imager::ImgRaw
1719 i_copy(src)
1720     Imager::ImgRaw     src
1721
1722
1723 undef_int
1724 i_rubthru(im,src,tx,ty,src_minx,src_miny,src_maxx,src_maxy)
1725     Imager::ImgRaw     im
1726     Imager::ImgRaw     src
1727                int     tx
1728                int     ty
1729                int     src_minx
1730                int     src_miny
1731                int     src_maxx
1732                int     src_maxy
1733
1734 undef_int
1735 i_compose(out, src, out_left, out_top, src_left, src_top, width, height, combine = ic_normal, opacity = 0.0)
1736     Imager::ImgRaw out
1737     Imager::ImgRaw src
1738         int out_left
1739         int out_top
1740         int src_left
1741         int src_top
1742         int width
1743         int height
1744         int combine
1745         double opacity
1746
1747 undef_int
1748 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)
1749     Imager::ImgRaw out
1750     Imager::ImgRaw src
1751     Imager::ImgRaw mask
1752         int out_left
1753         int out_top
1754         int src_left
1755         int src_top
1756         int mask_left
1757         int mask_top
1758         int width
1759         int height
1760         int combine
1761         double opacity
1762
1763 Imager::ImgRaw
1764 i_combine(src_av, channels_av = NULL)
1765         AV *src_av
1766         AV *channels_av
1767   PREINIT:
1768         i_img **imgs = NULL;
1769         STRLEN in_count;
1770         int *channels = NULL;
1771         int i;
1772         SV **psv;
1773         IV tmp;
1774   CODE:
1775         in_count = av_len(src_av) + 1;
1776         if (in_count > 0) {
1777           imgs = mymalloc(sizeof(i_img*) * in_count);
1778           channels = mymalloc(sizeof(int) * in_count);
1779           for (i = 0; i < in_count; ++i) {
1780             psv = av_fetch(src_av, i, 0);
1781             if (!psv || !*psv || !sv_derived_from(*psv, "Imager::ImgRaw")) {
1782               myfree(imgs);
1783               myfree(channels);
1784               croak("imgs must contain only images");
1785             }
1786             tmp = SvIV((SV*)SvRV(*psv));
1787             imgs[i] = INT2PTR(i_img*, tmp);
1788             if (channels_av &&
1789                 (psv = av_fetch(channels_av, i, 0)) != NULL &&
1790                 *psv) {
1791               channels[i] = SvIV(*psv);
1792             }
1793             else {
1794               channels[i] = 0;
1795             }
1796           }
1797         }
1798         RETVAL = i_combine(imgs, channels, in_count);
1799         myfree(imgs);
1800         myfree(channels);
1801   OUTPUT:
1802         RETVAL
1803
1804 undef_int
1805 i_flipxy(im, direction)
1806     Imager::ImgRaw     im
1807                int     direction
1808
1809 Imager::ImgRaw
1810 i_rotate90(im, degrees)
1811     Imager::ImgRaw      im
1812                int      degrees
1813
1814 Imager::ImgRaw
1815 i_rotate_exact(im, amount, ...)
1816     Imager::ImgRaw      im
1817             double      amount
1818       PREINIT:
1819         i_color *backp = NULL;
1820         i_fcolor *fbackp = NULL;
1821         int i;
1822         SV * sv1;
1823       CODE:
1824         /* extract the bg colors if any */
1825         /* yes, this is kind of strange */
1826         for (i = 2; i < items; ++i) {
1827           sv1 = ST(i);
1828           if (sv_derived_from(sv1, "Imager::Color")) {
1829             IV tmp = SvIV((SV*)SvRV(sv1));
1830             backp = INT2PTR(i_color *, tmp);
1831           }
1832           else if (sv_derived_from(sv1, "Imager::Color::Float")) {
1833             IV tmp = SvIV((SV*)SvRV(sv1));
1834             fbackp = INT2PTR(i_fcolor *, tmp);
1835           }
1836         }
1837         RETVAL = i_rotate_exact_bg(im, amount, backp, fbackp);
1838       OUTPUT:
1839         RETVAL
1840
1841 Imager::ImgRaw
1842 i_matrix_transform(im, xsize, ysize, matrix, ...)
1843     Imager::ImgRaw      im
1844                int      xsize
1845                int      ysize
1846       PREINIT:
1847         double matrix[9];
1848         AV *av;
1849         IV len;
1850         SV *sv1;
1851         int i;
1852         i_color *backp = NULL;
1853         i_fcolor *fbackp = NULL;
1854       CODE:
1855         if (!SvROK(ST(3)) || SvTYPE(SvRV(ST(3))) != SVt_PVAV)
1856           croak("i_matrix_transform: parameter 4 must be an array ref\n");
1857         av=(AV*)SvRV(ST(3));
1858         len=av_len(av)+1;
1859         if (len > 9)
1860           len = 9;
1861         for (i = 0; i < len; ++i) {
1862           sv1=(*(av_fetch(av,i,0)));
1863           matrix[i] = SvNV(sv1);
1864         }
1865         for (; i < 9; ++i)
1866           matrix[i] = 0;
1867         /* extract the bg colors if any */
1868         /* yes, this is kind of strange */
1869         for (i = 4; i < items; ++i) {
1870           sv1 = ST(i);
1871           if (sv_derived_from(sv1, "Imager::Color")) {
1872             IV tmp = SvIV((SV*)SvRV(sv1));
1873             backp = INT2PTR(i_color *, tmp);
1874           }
1875           else if (sv_derived_from(sv1, "Imager::Color::Float")) {
1876             IV tmp = SvIV((SV*)SvRV(sv1));
1877             fbackp = INT2PTR(i_fcolor *, tmp);
1878           }
1879         }
1880         RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp);
1881       OUTPUT:
1882         RETVAL
1883
1884 undef_int
1885 i_gaussian(im,stdev)
1886     Imager::ImgRaw     im
1887             double     stdev
1888
1889 void
1890 i_unsharp_mask(im,stdev,scale)
1891     Imager::ImgRaw     im
1892              float     stdev
1893              double    scale
1894
1895 int
1896 i_conv(im,coef)
1897         Imager::ImgRaw     im
1898         AV *coef
1899      PREINIT:
1900         double*    c_coef;
1901         int     len;
1902         SV* sv1;
1903         int i;
1904     CODE:
1905         len = av_len(coef) + 1;
1906         c_coef=mymalloc( len * sizeof(double) );
1907         for(i = 0; i  < len; i++) {
1908           sv1 = (*(av_fetch(coef, i, 0)));
1909           c_coef[i] = (double)SvNV(sv1);
1910         }
1911         RETVAL = i_conv(im, c_coef, len);
1912         myfree(c_coef);
1913     OUTPUT:
1914         RETVAL
1915
1916 Imager::ImgRaw
1917 i_convert(src, avmain)
1918     Imager::ImgRaw     src
1919     AV *avmain
1920         PREINIT:
1921           double *coeff;
1922           int outchan;
1923           int inchan;
1924           SV **temp;
1925           AV *avsub;
1926           int len;
1927           int i, j;
1928         CODE:
1929           outchan = av_len(avmain)+1;
1930           /* find the biggest */
1931           inchan = 0;
1932           for (j=0; j < outchan; ++j) {
1933             temp = av_fetch(avmain, j, 0);
1934             if (temp && SvROK(*temp) && SvTYPE(SvRV(*temp)) == SVt_PVAV) {
1935               avsub = (AV*)SvRV(*temp);
1936               len = av_len(avsub)+1;
1937               if (len > inchan)
1938                 inchan = len;
1939             }
1940           }
1941           coeff = mymalloc(sizeof(double) * outchan * inchan);
1942           for (j = 0; j < outchan; ++j) {
1943             avsub = (AV*)SvRV(*av_fetch(avmain, j, 0));
1944             len = av_len(avsub)+1;
1945             for (i = 0; i < len; ++i) {
1946               temp = av_fetch(avsub, i, 0);
1947               if (temp)
1948                 coeff[i+j*inchan] = SvNV(*temp);
1949               else
1950                 coeff[i+j*inchan] = 0;
1951             }
1952             while (i < inchan)
1953               coeff[i++ + j*inchan] = 0;
1954           }
1955           RETVAL = i_convert(src, coeff, outchan, inchan);
1956           myfree(coeff);
1957         OUTPUT:
1958           RETVAL
1959
1960
1961 void
1962 i_map(im, pmaps)
1963     Imager::ImgRaw     im
1964         PREINIT:
1965           unsigned int mask = 0;
1966           AV *avmain;
1967           AV *avsub;
1968           SV **temp;
1969           int len;
1970           int i, j;
1971           unsigned char (*maps)[256];
1972         CODE:
1973           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
1974             croak("i_map: parameter 2 must be an arrayref\n");
1975           avmain = (AV*)SvRV(ST(1));
1976           len = av_len(avmain)+1;
1977           if (im->channels < len) len = im->channels;
1978
1979           maps = mymalloc( len * sizeof(unsigned char [256]) );
1980
1981           for (j=0; j<len ; j++) {
1982             temp = av_fetch(avmain, j, 0);
1983             if (temp && SvROK(*temp) && (SvTYPE(SvRV(*temp)) == SVt_PVAV) ) {
1984               avsub = (AV*)SvRV(*temp);
1985               if(av_len(avsub) != 255) continue;
1986               mask |= 1<<j;
1987               for (i=0; i<256 ; i++) {
1988                 int val;
1989                 temp = av_fetch(avsub, i, 0);
1990                 val = temp ? SvIV(*temp) : 0;
1991                 if (val<0) val = 0;
1992                 if (val>255) val = 255;
1993                 maps[j][i] = val;
1994               }
1995             }
1996           }
1997           i_map(im, maps, mask);
1998           myfree(maps);
1999
2000
2001
2002 float
2003 i_img_diff(im1,im2)
2004     Imager::ImgRaw     im1
2005     Imager::ImgRaw     im2
2006
2007 double
2008 i_img_diffd(im1,im2)
2009     Imager::ImgRaw     im1
2010     Imager::ImgRaw     im2
2011
2012 int
2013 i_img_samef(im1, im2, epsilon = i_img_epsilonf(), what=NULL)
2014     Imager::ImgRaw    im1
2015     Imager::ImgRaw    im2
2016     double epsilon
2017     const char *what
2018
2019 double
2020 i_img_epsilonf()
2021
2022 bool
2023 _is_color_object(sv)
2024         SV* sv
2025     CODE:
2026         SvGETMAGIC(sv);
2027         RETVAL = SvOK(sv) && SvROK(sv) &&
2028            (sv_derived_from(sv, "Imager::Color")
2029           || sv_derived_from(sv, "Imager::Color::Float"));
2030     OUTPUT:
2031         RETVAL
2032
2033 #ifdef HAVE_LIBT1
2034 #endif 
2035
2036 #ifdef HAVE_LIBTT
2037
2038
2039 Imager::Font::TT
2040 i_tt_new(fontname)
2041               char*     fontname
2042
2043
2044 MODULE = Imager         PACKAGE = Imager::Font::TT      PREFIX=TT_
2045
2046 #define TT_DESTROY(handle) i_tt_destroy(handle)
2047
2048 void
2049 TT_DESTROY(handle)
2050      Imager::Font::TT   handle
2051
2052 int
2053 TT_CLONE_SKIP(...)
2054     CODE:
2055         RETVAL = 1;
2056     OUTPUT:
2057         RETVAL
2058
2059
2060 MODULE = Imager         PACKAGE = Imager
2061
2062
2063 undef_int
2064 i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1)
2065   Imager::Font::TT     handle
2066     Imager::ImgRaw     im
2067                int     xb
2068                int     yb
2069      Imager::Color     cl
2070              float     points
2071               SV *     str_sv
2072                int     smooth
2073                int     utf8
2074                int     align
2075              PREINIT:
2076                char *str;
2077                STRLEN len;
2078              CODE:
2079 #ifdef SvUTF8
2080                if (SvUTF8(str_sv))
2081                  utf8 = 1;
2082 #endif
2083                str = SvPV(str_sv, len);
2084                RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, 
2085                                   len, smooth, utf8, align);
2086              OUTPUT:
2087                RETVAL                
2088
2089
2090 undef_int
2091 i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1)
2092   Imager::Font::TT     handle
2093     Imager::ImgRaw     im
2094                int     xb
2095                int     yb
2096                int     channel
2097              float     points
2098               SV *     str_sv
2099                int     smooth
2100                int     utf8
2101                int     align
2102              PREINIT:
2103                char *str;
2104                STRLEN len;
2105              CODE:
2106 #ifdef SvUTF8
2107                if (SvUTF8(str_sv))
2108                  utf8 = 1;
2109 #endif
2110                str = SvPV(str_sv, len);
2111                RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len,
2112                                 smooth, utf8, align);
2113              OUTPUT:
2114                 RETVAL
2115
2116
2117 void
2118 i_tt_bbox(handle,point,str_sv,len_ignored, utf8)
2119   Imager::Font::TT     handle
2120              float     point
2121                SV*    str_sv
2122                int     utf8
2123              PREINIT:
2124                int     cords[BOUNDING_BOX_COUNT],rc;
2125                char *  str;
2126                STRLEN len;
2127                int i;
2128              PPCODE:
2129 #ifdef SvUTF8
2130                if (SvUTF8(ST(2)))
2131                  utf8 = 1;
2132 #endif
2133                str = SvPV(str_sv, len);
2134                if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) {
2135                  EXTEND(SP, rc);
2136                  for (i = 0; i < rc; ++i) {
2137                    PUSHs(sv_2mortal(newSViv(cords[i])));
2138                  }
2139                }
2140
2141 void
2142 i_tt_has_chars(handle, text_sv, utf8)
2143         Imager::Font::TT handle
2144         SV  *text_sv
2145         int utf8
2146       PREINIT:
2147         char const *text;
2148         STRLEN len;
2149         char *work;
2150         int count;
2151         int i;
2152       PPCODE:
2153 #ifdef SvUTF8
2154         if (SvUTF8(text_sv))
2155           utf8 = 1;
2156 #endif
2157         text = SvPV(text_sv, len);
2158         work = mymalloc(len);
2159         count = i_tt_has_chars(handle, text, len, utf8, work);
2160         if (GIMME_V == G_ARRAY) {
2161           EXTEND(SP, count);
2162           for (i = 0; i < count; ++i) {
2163             PUSHs(sv_2mortal(newSViv(work[i])));
2164           }
2165         }
2166         else {
2167           EXTEND(SP, 1);
2168           PUSHs(sv_2mortal(newSVpv(work, count)));
2169         }
2170         myfree(work);
2171
2172 void
2173 i_tt_dump_names(handle)
2174         Imager::Font::TT handle
2175
2176 void
2177 i_tt_face_name(handle)
2178         Imager::Font::TT handle
2179       PREINIT:
2180         char name[255];
2181         int len;
2182       PPCODE:
2183         len = i_tt_face_name(handle, name, sizeof(name));
2184         if (len) {
2185           EXTEND(SP, 1);
2186           PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
2187         }
2188
2189 void
2190 i_tt_glyph_name(handle, text_sv, utf8 = 0)
2191         Imager::Font::TT handle
2192         SV *text_sv
2193         int utf8
2194       PREINIT:
2195         char const *text;
2196         STRLEN work_len;
2197         size_t len;
2198         int outsize;
2199         char name[255];
2200       PPCODE:
2201 #ifdef SvUTF8
2202         if (SvUTF8(text_sv))
2203           utf8 = 1;
2204 #endif
2205         text = SvPV(text_sv, work_len);
2206         len = work_len;
2207         while (len) {
2208           unsigned long ch;
2209           if (utf8) {
2210             ch = i_utf8_advance(&text, &len);
2211             if (ch == ~0UL) {
2212               i_push_error(0, "invalid UTF8 character");
2213               break;
2214             }
2215           }
2216           else {
2217             ch = *text++;
2218             --len;
2219           }
2220           EXTEND(SP, 1);
2221           if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
2222             PUSHs(sv_2mortal(newSVpv(name, 0)));
2223           }
2224           else {
2225             PUSHs(&PL_sv_undef);
2226           } 
2227         }
2228
2229 #endif 
2230
2231 const char *
2232 i_test_format_probe(ig, length)
2233         Imager::IO     ig
2234                int     length
2235
2236 Imager::ImgRaw
2237 i_readpnm_wiol(ig, allow_incomplete)
2238         Imager::IO     ig
2239                int     allow_incomplete
2240
2241
2242 void
2243 i_readpnm_multi_wiol(ig, allow_incomplete)
2244         Imager::IO ig
2245                int     allow_incomplete
2246       PREINIT:
2247         i_img **imgs;
2248         int count=0;
2249         int i;
2250       PPCODE:
2251         imgs = i_readpnm_multi_wiol(ig, &count, allow_incomplete);
2252         if (imgs) {
2253           EXTEND(SP, count);
2254           for (i = 0; i < count; ++i) {
2255             SV *sv = sv_newmortal();
2256             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2257             PUSHs(sv);
2258           }
2259           myfree(imgs);
2260         }
2261
2262 undef_int
2263 i_writeppm_wiol(im, ig)
2264     Imager::ImgRaw     im
2265         Imager::IO     ig
2266
2267
2268
2269
2270
2271 Imager::ImgRaw
2272 i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
2273         Imager::IO     ig
2274                int     x
2275                int     y
2276                int     datachannels
2277                int     storechannels
2278                int     intrl
2279
2280 undef_int
2281 i_writeraw_wiol(im,ig)
2282     Imager::ImgRaw     im
2283         Imager::IO     ig
2284
2285 undef_int
2286 i_writebmp_wiol(im,ig)
2287     Imager::ImgRaw     im
2288         Imager::IO     ig
2289
2290 Imager::ImgRaw
2291 i_readbmp_wiol(ig, allow_incomplete=0)
2292         Imager::IO     ig
2293         int            allow_incomplete
2294
2295
2296 undef_int
2297 i_writetga_wiol(im,ig, wierdpack, compress, idstring)
2298     Imager::ImgRaw     im
2299         Imager::IO     ig
2300                int     wierdpack
2301                int     compress
2302               char*    idstring
2303             PREINIT:
2304                 int idlen;
2305                CODE:
2306                 idlen  = SvCUR(ST(4));
2307                 RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
2308                 OUTPUT:
2309                 RETVAL
2310
2311
2312 Imager::ImgRaw
2313 i_readtga_wiol(ig, length)
2314         Imager::IO     ig
2315                int     length
2316
2317
2318
2319
2320 Imager::ImgRaw
2321 i_scaleaxis(im,Value,Axis)
2322     Imager::ImgRaw     im
2323              float     Value
2324                int     Axis
2325
2326 Imager::ImgRaw
2327 i_scale_nn(im,scx,scy)
2328     Imager::ImgRaw     im
2329              float     scx
2330              float     scy
2331
2332 Imager::ImgRaw
2333 i_scale_mixing(im, width, height)
2334     Imager::ImgRaw     im
2335                int     width
2336                int     height
2337
2338 Imager::ImgRaw
2339 i_haar(im)
2340     Imager::ImgRaw     im
2341
2342 int
2343 i_count_colors(im,maxc)
2344     Imager::ImgRaw     im
2345                int     maxc
2346
2347 void
2348 i_get_anonymous_color_histo(im, maxc = 0x40000000)
2349    Imager::ImgRaw  im
2350    int maxc
2351     PREINIT:
2352         int i;
2353         unsigned int * col_usage = NULL;
2354         int col_cnt;
2355     PPCODE:
2356         col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc);
2357         EXTEND(SP, col_cnt);
2358         for (i = 0; i < col_cnt; i++)  {
2359             PUSHs(sv_2mortal(newSViv( col_usage[i])));
2360         }
2361         myfree(col_usage);
2362         XSRETURN(col_cnt);
2363
2364
2365 Imager::ImgRaw
2366 i_transform(im,opx,opy,parm)
2367     Imager::ImgRaw     im
2368              PREINIT:
2369              double* parm;
2370              int*    opx;
2371              int*    opy;
2372              int     opxl;
2373              int     opyl;
2374              int     parmlen;
2375              AV* av;
2376              SV* sv1;
2377              int i;
2378              CODE:
2379              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
2380              if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n");
2381              if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n");
2382              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
2383              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n");
2384              if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n");
2385              av=(AV*)SvRV(ST(1));
2386              opxl=av_len(av)+1;
2387              opx=mymalloc( opxl*sizeof(int) );
2388              for(i=0;i<opxl;i++) {
2389                sv1=(*(av_fetch(av,i,0)));
2390                opx[i]=(int)SvIV(sv1);
2391              }
2392              av=(AV*)SvRV(ST(2));
2393              opyl=av_len(av)+1;
2394              opy=mymalloc( opyl*sizeof(int) );
2395              for(i=0;i<opyl;i++) {
2396                sv1=(*(av_fetch(av,i,0)));
2397                opy[i]=(int)SvIV(sv1);
2398              }
2399              av=(AV*)SvRV(ST(3));
2400              parmlen=av_len(av)+1;
2401              parm=mymalloc( parmlen*sizeof(double) );
2402              for(i=0;i<parmlen;i++) { /* FIXME: Bug? */
2403                sv1=(*(av_fetch(av,i,0)));
2404                parm[i]=(double)SvNV(sv1);
2405              }
2406              RETVAL=i_transform(im,opx,opxl,opy,opyl,parm,parmlen);
2407              myfree(parm);
2408              myfree(opy);
2409              myfree(opx);
2410              ST(0) = sv_newmortal();
2411              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2412              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2413
2414 Imager::ImgRaw
2415 i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
2416         SV *sv_width
2417         SV *sv_height
2418         SV *sv_ops
2419         AV *av_n_regs
2420         AV *av_c_regs
2421         AV *av_in_imgs
2422         int channels
2423              PREINIT:
2424              int width;
2425              int height;
2426              struct rm_op *ops;
2427              STRLEN ops_len;
2428              int ops_count;
2429              double *n_regs;
2430              int n_regs_count;
2431              i_color *c_regs;
2432              int c_regs_count;
2433              int in_imgs_count;
2434              i_img **in_imgs;
2435              SV *sv1;
2436              IV tmp;
2437              int i;
2438              CODE:
2439
2440              in_imgs_count = av_len(av_in_imgs)+1;
2441              for (i = 0; i < in_imgs_count; ++i) {
2442                sv1 = *av_fetch(av_in_imgs, i, 0);
2443                if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2444                  croak("sv_in_img must contain only images");
2445                }
2446              }
2447              if (in_imgs_count > 0) {
2448                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2449                for (i = 0; i < in_imgs_count; ++i) {              
2450                  sv1 = *av_fetch(av_in_imgs,i,0);
2451                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2452                    croak("Parameter 5 must contain only images");
2453                  }
2454                  tmp = SvIV((SV*)SvRV(sv1));
2455                  in_imgs[i] = INT2PTR(i_img*, tmp);
2456                }
2457              }
2458              else {
2459                /* no input images */
2460                in_imgs = NULL;
2461              }
2462              /* default the output size from the first input if possible */
2463              if (SvOK(sv_width))
2464                width = SvIV(sv_width);
2465              else if (in_imgs_count)
2466                width = in_imgs[0]->xsize;
2467              else
2468                croak("No output image width supplied");
2469
2470              if (SvOK(sv_height))
2471                height = SvIV(sv_height);
2472              else if (in_imgs_count)
2473                height = in_imgs[0]->ysize;
2474              else
2475                croak("No output image height supplied");
2476
2477              ops = (struct rm_op *)SvPV(sv_ops, ops_len);
2478              if (ops_len % sizeof(struct rm_op))
2479                  croak("Imager: Parameter 3 must be a bitmap of regops\n");
2480              ops_count = ops_len / sizeof(struct rm_op);
2481
2482              n_regs_count = av_len(av_n_regs)+1;
2483              n_regs = mymalloc(n_regs_count * sizeof(double));
2484              for (i = 0; i < n_regs_count; ++i) {
2485                sv1 = *av_fetch(av_n_regs,i,0);
2486                if (SvOK(sv1))
2487                  n_regs[i] = SvNV(sv1);
2488              }
2489              c_regs_count = av_len(av_c_regs)+1;
2490              c_regs = mymalloc(c_regs_count * sizeof(i_color));
2491              /* I don't bother initializing the colou?r registers */
2492
2493              RETVAL=i_transform2(width, height, channels, ops, ops_count, 
2494                                  n_regs, n_regs_count, 
2495                                  c_regs, c_regs_count, in_imgs, in_imgs_count);
2496              if (in_imgs)
2497                  myfree(in_imgs);
2498              myfree(n_regs);
2499              myfree(c_regs);
2500              ST(0) = sv_newmortal();
2501              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2502              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2503
2504
2505 void
2506 i_contrast(im,intensity)
2507     Imager::ImgRaw     im
2508              float     intensity
2509
2510 void
2511 i_hardinvert(im)
2512     Imager::ImgRaw     im
2513
2514 void
2515 i_hardinvertall(im)
2516     Imager::ImgRaw     im
2517
2518 void
2519 i_noise(im,amount,type)
2520     Imager::ImgRaw     im
2521              float     amount
2522      unsigned char     type
2523
2524 void
2525 i_bumpmap(im,bump,channel,light_x,light_y,strength)
2526     Imager::ImgRaw     im
2527     Imager::ImgRaw     bump
2528                int     channel
2529                int     light_x
2530                int     light_y
2531                int     strength
2532
2533
2534 void
2535 i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
2536     Imager::ImgRaw     im
2537     Imager::ImgRaw     bump
2538                int     channel
2539                int     tx
2540                int     ty
2541              float     Lx
2542              float     Ly
2543              float     Lz
2544              float     cd
2545              float     cs
2546              float     n
2547      Imager::Color     Ia
2548      Imager::Color     Il
2549      Imager::Color     Is
2550
2551
2552
2553 void
2554 i_postlevels(im,levels)
2555     Imager::ImgRaw     im
2556              int       levels
2557
2558 void
2559 i_mosaic(im,size)
2560     Imager::ImgRaw     im
2561                int     size
2562
2563 void
2564 i_watermark(im,wmark,tx,ty,pixdiff)
2565     Imager::ImgRaw     im
2566     Imager::ImgRaw     wmark
2567                int     tx
2568                int     ty
2569                int     pixdiff
2570
2571
2572 void
2573 i_autolevels(im,lsat,usat,skew)
2574     Imager::ImgRaw     im
2575              float     lsat
2576              float     usat
2577              float     skew
2578
2579 void
2580 i_radnoise(im,xo,yo,rscale,ascale)
2581     Imager::ImgRaw     im
2582              float     xo
2583              float     yo
2584              float     rscale
2585              float     ascale
2586
2587 void
2588 i_turbnoise(im, xo, yo, scale)
2589     Imager::ImgRaw     im
2590              float     xo
2591              float     yo
2592              float     scale
2593
2594
2595 void
2596 i_gradgen(im, ...)
2597     Imager::ImgRaw     im
2598       PREINIT:
2599         int num;
2600         int *xo;
2601         int *yo;
2602         i_color *ival;
2603         int dmeasure;
2604         int i;
2605         SV *sv;
2606         AV *axx;
2607         AV *ayy;
2608         AV *ac;
2609       CODE:
2610         if (items != 5)
2611             croak("Usage: i_gradgen(im, xo, yo, ival, dmeasure)");
2612         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2613             croak("i_gradgen: Second argument must be an array ref");
2614         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2615             croak("i_gradgen: Third argument must be an array ref");
2616         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2617             croak("i_gradgen: Fourth argument must be an array ref");
2618         axx = (AV *)SvRV(ST(1));
2619         ayy = (AV *)SvRV(ST(2));
2620         ac  = (AV *)SvRV(ST(3));
2621         dmeasure = (int)SvIV(ST(4));
2622         
2623         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2624         num = num <= av_len(ac) ? num : av_len(ac);
2625         num++; 
2626         if (num < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each");
2627         xo = mymalloc( sizeof(int) * num );
2628         yo = mymalloc( sizeof(int) * num );
2629         ival = mymalloc( sizeof(i_color) * num );
2630         for(i = 0; i<num; i++) {
2631           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
2632           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
2633           sv = *av_fetch(ac, i, 0);
2634           if ( !sv_derived_from(sv, "Imager::Color") ) {
2635             free(axx); free(ayy); free(ac);
2636             croak("i_gradgen: Element of fourth argument is not derived from Imager::Color");
2637           }
2638           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
2639         }
2640         i_gradgen(im, num, xo, yo, ival, dmeasure);
2641         myfree(xo);
2642         myfree(yo);
2643         myfree(ival);
2644
2645 Imager::ImgRaw
2646 i_diff_image(im, im2, mindist=0)
2647     Imager::ImgRaw     im
2648     Imager::ImgRaw     im2
2649             double     mindist
2650
2651 undef_int
2652 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2653     Imager::ImgRaw     im
2654             double     xa
2655             double     ya
2656             double     xb
2657             double     yb
2658                int     type
2659                int     repeat
2660                int     combine
2661                int     super_sample
2662             double     ssample_param
2663       PREINIT:
2664         AV *asegs;
2665         int count;
2666         i_fountain_seg *segs;
2667       CODE:
2668         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
2669             croak("i_fountain: argument 11 must be an array ref");
2670         
2671         asegs = (AV *)SvRV(ST(10));
2672         segs = load_fount_segs(aTHX_ asegs, &count);
2673         RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, 
2674                             super_sample, ssample_param, count, segs);
2675         myfree(segs);
2676       OUTPUT:
2677         RETVAL
2678
2679 Imager::FillHandle
2680 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2681             double     xa
2682             double     ya
2683             double     xb
2684             double     yb
2685                int     type
2686                int     repeat
2687                int     combine
2688                int     super_sample
2689             double     ssample_param
2690       PREINIT:
2691         AV *asegs;
2692         int count;
2693         i_fountain_seg *segs;
2694       CODE:
2695         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
2696             croak("i_fountain: argument 11 must be an array ref");
2697         
2698         asegs = (AV *)SvRV(ST(9));
2699         segs = load_fount_segs(aTHX_ asegs, &count);
2700         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
2701                                   super_sample, ssample_param, count, segs);
2702         myfree(segs);        
2703       OUTPUT:
2704         RETVAL
2705
2706 Imager::FillHandle
2707 i_new_fill_opacity(other_fill, alpha_mult)
2708     Imager::FillHandle other_fill
2709     double alpha_mult
2710
2711 void
2712 i_errors()
2713       PREINIT:
2714         i_errmsg *errors;
2715         int i;
2716         AV *av;
2717         SV *sv;
2718       PPCODE:
2719         errors = i_errors();
2720         i = 0;
2721         while (errors[i].msg) {
2722           av = newAV();
2723           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
2724           if (!av_store(av, 0, sv)) {
2725             SvREFCNT_dec(sv);
2726           }
2727           sv = newSViv(errors[i].code);
2728           if (!av_store(av, 1, sv)) {
2729             SvREFCNT_dec(sv);
2730           }
2731           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
2732           ++i;
2733         }
2734
2735 void
2736 i_clear_error()
2737
2738 void
2739 i_push_error(code, msg)
2740         int code
2741         const char *msg
2742
2743 undef_int
2744 i_nearest_color(im, ...)
2745     Imager::ImgRaw     im
2746       PREINIT:
2747         int num;
2748         int *xo;
2749         int *yo;
2750         i_color *ival;
2751         int dmeasure;
2752         int i;
2753         SV *sv;
2754         AV *axx;
2755         AV *ayy;
2756         AV *ac;
2757       CODE:
2758         if (items != 5)
2759             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
2760         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2761             croak("i_nearest_color: Second argument must be an array ref");
2762         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2763             croak("i_nearest_color: Third argument must be an array ref");
2764         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2765             croak("i_nearest_color: Fourth argument must be an array ref");
2766         axx = (AV *)SvRV(ST(1));
2767         ayy = (AV *)SvRV(ST(2));
2768         ac  = (AV *)SvRV(ST(3));
2769         dmeasure = (int)SvIV(ST(4));
2770         
2771         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2772         num = num <= av_len(ac) ? num : av_len(ac);
2773         num++; 
2774         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
2775         xo = mymalloc( sizeof(int) * num );
2776         yo = mymalloc( sizeof(int) * num );
2777         ival = mymalloc( sizeof(i_color) * num );
2778         for(i = 0; i<num; i++) {
2779           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
2780           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
2781           sv = *av_fetch(ac, i, 0);
2782           if ( !sv_derived_from(sv, "Imager::Color") ) {
2783             free(axx); free(ayy); free(ac);
2784             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
2785           }
2786           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
2787         }
2788         RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
2789       OUTPUT:
2790         RETVAL
2791
2792 void
2793 malloc_state()
2794
2795 void
2796 DSO_open(filename)
2797              char*       filename
2798              PREINIT:
2799                void *rc;
2800                char *evstr;
2801              PPCODE:
2802                rc=DSO_open(filename,&evstr);
2803                if (rc!=NULL) {
2804                  if (evstr!=NULL) {
2805                    EXTEND(SP,2); 
2806                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
2807                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
2808                  } else {
2809                    EXTEND(SP,1);
2810                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
2811                  }
2812                }
2813
2814
2815 undef_int
2816 DSO_close(dso_handle)
2817              void*       dso_handle
2818
2819 void
2820 DSO_funclist(dso_handle_v)
2821              void*       dso_handle_v
2822              PREINIT:
2823                int i;
2824                DSO_handle *dso_handle;
2825                func_ptr *functions;
2826              PPCODE:
2827                dso_handle=(DSO_handle*)dso_handle_v;
2828                functions = DSO_funclist(dso_handle);
2829                i=0;
2830                while( functions[i].name != NULL) {
2831                  EXTEND(SP,1);
2832                  PUSHs(sv_2mortal(newSVpv(functions[i].name,0)));
2833                  EXTEND(SP,1);
2834                  PUSHs(sv_2mortal(newSVpv(functions[i++].pcode,0)));
2835                }
2836
2837 void
2838 DSO_call(handle,func_index,hv)
2839                void*  handle
2840                int    func_index
2841              PREINIT:
2842                HV* hv;
2843              PPCODE:
2844                if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
2845                hv=(HV*)SvRV(ST(2));
2846                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
2847                DSO_call( (DSO_handle *)handle,func_index,hv);
2848
2849 SV *
2850 i_get_pixel(im, x, y)
2851         Imager::ImgRaw im
2852         int x
2853         int y;
2854       PREINIT:
2855         i_color *color;
2856       CODE:
2857         color = (i_color *)mymalloc(sizeof(i_color));
2858         if (i_gpix(im, x, y, color) == 0) {
2859           RETVAL = NEWSV(0, 0);
2860           sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
2861         }
2862         else {
2863           myfree(color);
2864           RETVAL = &PL_sv_undef;
2865         }
2866       OUTPUT:
2867         RETVAL
2868         
2869
2870 int
2871 i_ppix(im, x, y, cl)
2872         Imager::ImgRaw im
2873         int x
2874         int y
2875         Imager::Color cl
2876
2877 Imager::ImgRaw
2878 i_img_pal_new(x, y, channels, maxpal)
2879         int     x
2880         int     y
2881         int     channels
2882         int     maxpal
2883
2884 Imager::ImgRaw
2885 i_img_to_pal(src, quant)
2886         Imager::ImgRaw src
2887       PREINIT:
2888         HV *hv;
2889         i_quantize quant;
2890       CODE:
2891         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2892           croak("i_img_to_pal: second argument must be a hash ref");
2893         hv = (HV *)SvRV(ST(1));
2894         memset(&quant, 0, sizeof(quant));
2895         quant.version = 1;
2896         quant.mc_size = 256;
2897         ip_handle_quant_opts(aTHX_ &quant, hv);
2898         RETVAL = i_img_to_pal(src, &quant);
2899         if (RETVAL) {
2900           ip_copy_colors_back(aTHX_ hv, &quant);
2901         }
2902         ip_cleanup_quant_opts(aTHX_ &quant);
2903       OUTPUT:
2904         RETVAL
2905
2906 Imager::ImgRaw
2907 i_img_to_rgb(src)
2908         Imager::ImgRaw src
2909
2910 void
2911 i_gpal(im, l, r, y)
2912         Imager::ImgRaw  im
2913         int     l
2914         int     r
2915         int     y
2916       PREINIT:
2917         i_palidx *work;
2918         int count, i;
2919       PPCODE:
2920         if (l < r) {
2921           work = mymalloc((r-l) * sizeof(i_palidx));
2922           count = i_gpal(im, l, r, y, work);
2923           if (GIMME_V == G_ARRAY) {
2924             EXTEND(SP, count);
2925             for (i = 0; i < count; ++i) {
2926               PUSHs(sv_2mortal(newSViv(work[i])));
2927             }
2928           }
2929           else {
2930             EXTEND(SP, 1);
2931             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
2932           }
2933           myfree(work);
2934         }
2935         else {
2936           if (GIMME_V != G_ARRAY) {
2937             EXTEND(SP, 1);
2938             PUSHs(&PL_sv_undef);
2939           }
2940         }
2941
2942 int
2943 i_ppal(im, l, y, ...)
2944         Imager::ImgRaw  im
2945         int     l
2946         int     y
2947       PREINIT:
2948         i_palidx *work;
2949         int i;
2950       CODE:
2951         if (items > 3) {
2952           work = mymalloc(sizeof(i_palidx) * (items-3));
2953           for (i=0; i < items-3; ++i) {
2954             work[i] = SvIV(ST(i+3));
2955           }
2956           validate_i_ppal(im, work, items - 3);
2957           RETVAL = i_ppal(im, l, l+items-3, y, work);
2958           myfree(work);
2959         }
2960         else {
2961           RETVAL = 0;
2962         }
2963       OUTPUT:
2964         RETVAL
2965
2966 int
2967 i_ppal_p(im, l, y, data)
2968         Imager::ImgRaw  im
2969         int     l
2970         int     y
2971         SV *data
2972       PREINIT:
2973         i_palidx const *work;
2974         STRLEN len;
2975       CODE:
2976         work = (i_palidx const *)SvPV(data, len);
2977         len /= sizeof(i_palidx);
2978         if (len > 0) {
2979           validate_i_ppal(im, work, len);
2980           RETVAL = i_ppal(im, l, l+len, y, work);
2981         }
2982         else {
2983           RETVAL = 0;
2984         }
2985       OUTPUT:
2986         RETVAL
2987
2988 SV *
2989 i_addcolors(im, ...)
2990         Imager::ImgRaw  im
2991       PREINIT:
2992         int index;
2993         i_color *colors;
2994         int i;
2995       CODE:
2996         if (items < 2)
2997           croak("i_addcolors: no colors to add");
2998         colors = mymalloc((items-1) * sizeof(i_color));
2999         for (i=0; i < items-1; ++i) {
3000           if (sv_isobject(ST(i+1)) 
3001               && sv_derived_from(ST(i+1), "Imager::Color")) {
3002             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3003             colors[i] = *INT2PTR(i_color *, tmp);
3004           }
3005           else {
3006             myfree(colors);
3007             croak("i_addcolor: pixels must be Imager::Color objects");
3008           }
3009         }
3010         index = i_addcolors(im, colors, items-1);
3011         myfree(colors);
3012         if (index == 0) {
3013           RETVAL = newSVpv("0 but true", 0);
3014         }
3015         else if (index == -1) {
3016           RETVAL = &PL_sv_undef;
3017         }
3018         else {
3019           RETVAL = newSViv(index);
3020         }
3021       OUTPUT:
3022         RETVAL
3023
3024 undef_int 
3025 i_setcolors(im, index, ...)
3026         Imager::ImgRaw  im
3027         int index
3028       PREINIT:
3029         i_color *colors;
3030         int i;
3031       CODE:
3032         if (items < 3)
3033           croak("i_setcolors: no colors to add");
3034         colors = mymalloc((items-2) * sizeof(i_color));
3035         for (i=0; i < items-2; ++i) {
3036           if (sv_isobject(ST(i+2)) 
3037               && sv_derived_from(ST(i+2), "Imager::Color")) {
3038             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3039             colors[i] = *INT2PTR(i_color *, tmp);
3040           }
3041           else {
3042             myfree(colors);
3043             croak("i_setcolors: pixels must be Imager::Color objects");
3044           }
3045         }
3046         RETVAL = i_setcolors(im, index, colors, items-2);
3047         myfree(colors);
3048       OUTPUT:
3049         RETVAL
3050
3051 void
3052 i_getcolors(im, index, ...)
3053         Imager::ImgRaw im
3054         int index
3055       PREINIT:
3056         i_color *colors;
3057         int count = 1;
3058         int i;
3059       PPCODE:
3060         if (items > 3)
3061           croak("i_getcolors: too many arguments");
3062         if (items == 3)
3063           count = SvIV(ST(2));
3064         if (count < 1)
3065           croak("i_getcolors: count must be positive");
3066         colors = mymalloc(sizeof(i_color) * count);
3067         if (i_getcolors(im, index, colors, count)) {
3068           for (i = 0; i < count; ++i) {
3069             i_color *pv;
3070             SV *sv = sv_newmortal();
3071             pv = mymalloc(sizeof(i_color));
3072             *pv = colors[i];
3073             sv_setref_pv(sv, "Imager::Color", (void *)pv);
3074             PUSHs(sv);
3075           }
3076         }
3077         myfree(colors);
3078
3079
3080 undef_neg_int
3081 i_colorcount(im)
3082         Imager::ImgRaw im
3083
3084 undef_neg_int
3085 i_maxcolors(im)
3086         Imager::ImgRaw im
3087
3088 SV *
3089 i_findcolor(im, color)
3090         Imager::ImgRaw im
3091         Imager::Color color
3092       PREINIT:
3093         i_palidx index;
3094       CODE:
3095         if (i_findcolor(im, color, &index)) {
3096           RETVAL = newSViv(index);
3097         }
3098         else {
3099           RETVAL = &PL_sv_undef;
3100         }
3101       OUTPUT:
3102         RETVAL
3103
3104 int
3105 i_img_bits(im)
3106         Imager::ImgRaw  im
3107
3108 int
3109 i_img_type(im)
3110         Imager::ImgRaw  im
3111
3112 int
3113 i_img_virtual(im)
3114         Imager::ImgRaw  im
3115
3116 void
3117 i_gsamp(im, l, r, y, ...)
3118         Imager::ImgRaw im
3119         int l
3120         int r
3121         int y
3122       PREINIT:
3123         int *chans;
3124         int chan_count;
3125         i_sample_t *data;
3126         int count, i;
3127       PPCODE:
3128         if (items < 5)
3129           croak("No channel numbers supplied to g_samp()");
3130         if (l < r) {
3131           chan_count = items - 4;
3132           chans = mymalloc(sizeof(int) * chan_count);
3133           for (i = 0; i < chan_count; ++i)
3134             chans[i] = SvIV(ST(i+4));
3135           data = mymalloc(sizeof(i_sample_t) * (r-l) * chan_count); /* XXX: memleak? */
3136           count = i_gsamp(im, l, r, y, data, chans, chan_count);
3137           myfree(chans);
3138           if (GIMME_V == G_ARRAY) {
3139             EXTEND(SP, count);
3140             for (i = 0; i < count; ++i)
3141               PUSHs(sv_2mortal(newSViv(data[i])));
3142           }
3143           else {
3144             EXTEND(SP, 1);
3145             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3146           }
3147           myfree(data);
3148         }
3149         else {
3150           if (GIMME_V != G_ARRAY) {
3151             EXTEND(SP, 1);
3152             PUSHs(&PL_sv_undef);
3153           }
3154         }
3155
3156 undef_neg_int
3157 i_gsamp_bits(im, l, r, y, bits, target, offset, ...)
3158         Imager::ImgRaw im
3159         int l
3160         int r
3161         int y
3162         int bits
3163         AV *target
3164         int offset
3165       PREINIT:
3166         int *chans;
3167         int chan_count;
3168         unsigned *data;
3169         int count, i;
3170       CODE:
3171         i_clear_error();
3172         if (items < 8)
3173           croak("No channel numbers supplied to g_samp()");
3174         if (l < r) {
3175           chan_count = items - 7;
3176           chans = mymalloc(sizeof(int) * chan_count);
3177           for (i = 0; i < chan_count; ++i)
3178             chans[i] = SvIV(ST(i+7));
3179           data = mymalloc(sizeof(unsigned) * (r-l) * chan_count);
3180           count = i_gsamp_bits(im, l, r, y, data, chans, chan_count, bits);
3181           myfree(chans);
3182           for (i = 0; i < count; ++i) {
3183             av_store(target, i+offset, newSVuv(data[i]));
3184           }
3185           myfree(data);
3186           RETVAL = count;
3187         }
3188         else {
3189           RETVAL = 0;
3190         }
3191       OUTPUT:
3192         RETVAL
3193
3194 undef_neg_int
3195 i_psamp_bits(im, l, y, bits, channels_sv, data_av, data_offset = 0, pixel_count = -1)
3196         Imager::ImgRaw im
3197         int l
3198         int y
3199         int bits
3200         SV *channels_sv
3201         AV *data_av
3202         int data_offset
3203         int pixel_count
3204       PREINIT:
3205         int chan_count;
3206         int *channels;
3207         int data_count;
3208         int data_used;
3209         unsigned *data;
3210         int i;
3211       CODE:
3212         i_clear_error();
3213         if (SvOK(channels_sv)) {
3214           AV *channels_av;
3215           if (!SvROK(channels_sv) || SvTYPE(SvRV(channels_sv)) != SVt_PVAV) {
3216             croak("channels is not an array ref");
3217           }
3218           channels_av = (AV *)SvRV(channels_sv);
3219           chan_count = av_len(channels_av) + 1;
3220           if (chan_count < 1) {
3221             croak("i_psamp_bits: no channels provided");
3222           }
3223           channels = mymalloc(sizeof(int) * chan_count);
3224           for (i = 0; i < chan_count; ++i)
3225             channels[i] = SvIV(*av_fetch(channels_av, i, 0));
3226         }
3227         else {
3228           chan_count = im->channels;
3229           channels = NULL;
3230         }
3231
3232         data_count = av_len(data_av) + 1;
3233         if (data_offset < 0) {
3234           croak("data_offset must by non-negative");
3235         }
3236         if (data_offset > data_count) {
3237           croak("data_offset greater than number of samples supplied");
3238         }
3239         if (pixel_count == -1 || 
3240             data_offset + pixel_count * chan_count > data_count) {
3241           pixel_count = (data_count - data_offset) / chan_count;
3242         }
3243
3244         data_used = pixel_count * chan_count;
3245         data = mymalloc(sizeof(unsigned) * data_count);
3246         for (i = 0; i < data_used; ++i)
3247           data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0));
3248
3249         RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels, 
3250                               chan_count, bits);
3251
3252         if (data)
3253           myfree(data);
3254         if (channels)
3255           myfree(channels);
3256       OUTPUT:
3257         RETVAL
3258
3259 Imager::ImgRaw
3260 i_img_masked_new(targ, mask, x, y, w, h)
3261         Imager::ImgRaw targ
3262         int x
3263         int y
3264         int w
3265         int h
3266       PREINIT:
3267         i_img *mask;
3268       CODE:
3269         if (SvOK(ST(1))) {
3270           if (!sv_isobject(ST(1)) 
3271               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3272             croak("i_img_masked_new: parameter 2 must undef or an image");
3273           }
3274           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3275         }
3276         else
3277           mask = NULL;
3278         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3279       OUTPUT:
3280         RETVAL
3281
3282 int
3283 i_plin(im, l, y, ...)
3284         Imager::ImgRaw  im
3285         int     l
3286         int     y
3287       PREINIT:
3288         i_color *work;
3289         int i;
3290         STRLEN len;
3291         int count;
3292       CODE:
3293         if (items > 3) {
3294           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3295             /* supplied as a byte string */
3296             work = (i_color *)SvPV(ST(3), len);
3297             count = len / sizeof(i_color);
3298             if (count * sizeof(i_color) != len) {
3299               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3300             }
3301             RETVAL = i_plin(im, l, l+count, y, work);
3302           }
3303           else {
3304             work = mymalloc(sizeof(i_color) * (items-3));
3305             for (i=0; i < items-3; ++i) {
3306               if (sv_isobject(ST(i+3)) 
3307                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3308                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3309                 work[i] = *INT2PTR(i_color *, tmp);
3310               }
3311               else {
3312                 myfree(work);
3313                 croak("i_plin: pixels must be Imager::Color objects");
3314               }
3315             }
3316             RETVAL = i_plin(im, l, l+items-3, y, work);
3317             myfree(work);
3318           }
3319         }
3320         else {
3321           RETVAL = 0;
3322         }
3323       OUTPUT:
3324         RETVAL
3325
3326 int
3327 i_ppixf(im, x, y, cl)
3328         Imager::ImgRaw im
3329         int x
3330         int y
3331         Imager::Color::Float cl
3332
3333 void
3334 i_gsampf(im, l, r, y, ...)
3335         Imager::ImgRaw im
3336         int l
3337         int r
3338         int y
3339       PREINIT:
3340         int *chans;
3341         int chan_count;
3342         i_fsample_t *data;
3343         int count, i;
3344       PPCODE:
3345         if (items < 5)
3346           croak("No channel numbers supplied to g_sampf()");
3347         if (l < r) {
3348           chan_count = items - 4;
3349           chans = mymalloc(sizeof(int) * chan_count);
3350           for (i = 0; i < chan_count; ++i)
3351             chans[i] = SvIV(ST(i+4));
3352           data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count);
3353           count = i_gsampf(im, l, r, y, data, chans, chan_count);
3354           myfree(chans);
3355           if (GIMME_V == G_ARRAY) {
3356             EXTEND(SP, count);
3357             for (i = 0; i < count; ++i)
3358               PUSHs(sv_2mortal(newSVnv(data[i])));
3359           }
3360           else {
3361             EXTEND(SP, 1);
3362             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3363           }
3364           myfree(data);
3365         }
3366         else {
3367           if (GIMME_V != G_ARRAY) {
3368             EXTEND(SP, 1);
3369             PUSHs(&PL_sv_undef);
3370           }
3371         }
3372
3373 int
3374 i_plinf(im, l, y, ...)
3375         Imager::ImgRaw  im
3376         int     l
3377         int     y
3378       PREINIT:
3379         i_fcolor *work;
3380         int i;
3381         STRLEN len;
3382         int count;
3383       CODE:
3384         if (items > 3) {
3385           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3386             /* supplied as a byte string */
3387             work = (i_fcolor *)SvPV(ST(3), len);
3388             count = len / sizeof(i_fcolor);
3389             if (count * sizeof(i_fcolor) != len) {
3390               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3391             }
3392             RETVAL = i_plinf(im, l, l+count, y, work);
3393           }
3394           else {
3395             work = mymalloc(sizeof(i_fcolor) * (items-3));
3396             for (i=0; i < items-3; ++i) {
3397               if (sv_isobject(ST(i+3)) 
3398                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3399                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3400                 work[i] = *INT2PTR(i_fcolor *, tmp);
3401               }
3402               else {
3403                 myfree(work);
3404                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3405               }
3406             }
3407             /**(char *)0 = 1;*/
3408             RETVAL = i_plinf(im, l, l+items-3, y, work);
3409             myfree(work);
3410           }
3411         }
3412         else {
3413           RETVAL = 0;
3414         }
3415       OUTPUT:
3416         RETVAL
3417
3418 SV *
3419 i_gpixf(im, x, y)
3420         Imager::ImgRaw im
3421         int x
3422         int y;
3423       PREINIT:
3424         i_fcolor *color;
3425       CODE:
3426         color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3427         if (i_gpixf(im, x, y, color) == 0) {
3428           RETVAL = NEWSV(0,0);
3429           sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
3430         }
3431         else {
3432           myfree(color);
3433           RETVAL = &PL_sv_undef;
3434         }
3435       OUTPUT:
3436         RETVAL
3437
3438 void
3439 i_glin(im, l, r, y)
3440         Imager::ImgRaw im
3441         int l
3442         int r
3443         int y
3444       PREINIT:
3445         i_color *vals;
3446         int count, i;
3447       PPCODE:
3448         if (l < r) {
3449           vals = mymalloc((r-l) * sizeof(i_color));
3450           memset(vals, 0, (r-l) * sizeof(i_color));
3451           count = i_glin(im, l, r, y, vals);
3452           if (GIMME_V == G_ARRAY) {
3453             EXTEND(SP, count);
3454             for (i = 0; i < count; ++i) {
3455               SV *sv;
3456               i_color *col = mymalloc(sizeof(i_color));
3457               *col = vals[i];
3458               sv = sv_newmortal();
3459               sv_setref_pv(sv, "Imager::Color", (void *)col);
3460               PUSHs(sv);
3461             }
3462           }
3463           else if (count) {
3464             EXTEND(SP, 1);
3465             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3466           }
3467           myfree(vals);
3468         }
3469
3470 void
3471 i_glinf(im, l, r, y)
3472         Imager::ImgRaw im
3473         int l
3474         int r
3475         int y
3476       PREINIT:
3477         i_fcolor *vals;
3478         int count, i;
3479         i_fcolor zero;
3480       PPCODE:
3481         for (i = 0; i < MAXCHANNELS; ++i)
3482           zero.channel[i] = 0;
3483         if (l < r) {
3484           vals = mymalloc((r-l) * sizeof(i_fcolor));
3485           for (i = 0; i < r-l; ++i)
3486             vals[i] = zero;
3487           count = i_glinf(im, l, r, y, vals);
3488           if (GIMME_V == G_ARRAY) {
3489             EXTEND(SP, count);
3490             for (i = 0; i < count; ++i) {
3491               SV *sv;
3492               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3493               *col = vals[i];
3494               sv = sv_newmortal();
3495               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3496               PUSHs(sv);
3497             }
3498           }
3499           else if (count) {
3500             EXTEND(SP, 1);
3501             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3502           }
3503           myfree(vals);
3504         }
3505
3506 Imager::ImgRaw
3507 i_img_16_new(x, y, ch)
3508         int x
3509         int y
3510         int ch
3511
3512 Imager::ImgRaw
3513 i_img_to_rgb16(im)
3514        Imager::ImgRaw im
3515
3516 Imager::ImgRaw
3517 i_img_double_new(x, y, ch)
3518         int x
3519         int y
3520         int ch
3521
3522 undef_int
3523 i_tags_addn(im, name, code, idata)
3524         Imager::ImgRaw im
3525         int     code
3526         int     idata
3527       PREINIT:
3528         char *name;
3529         STRLEN len;
3530       CODE:
3531         if (SvOK(ST(1)))
3532           name = SvPV(ST(1), len);
3533         else
3534           name = NULL;
3535         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3536       OUTPUT:
3537         RETVAL
3538
3539 undef_int
3540 i_tags_add(im, name, code, data, idata)
3541         Imager::ImgRaw  im
3542         int code
3543         int idata
3544       PREINIT:
3545         char *name;
3546         char *data;
3547         STRLEN len;
3548       CODE:
3549         if (SvOK(ST(1)))
3550           name = SvPV(ST(1), len);
3551         else
3552           name = NULL;
3553         if (SvOK(ST(3)))
3554           data = SvPV(ST(3), len);
3555         else {
3556           data = NULL;
3557           len = 0;
3558         }
3559         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3560       OUTPUT:
3561         RETVAL
3562
3563 SV *
3564 i_tags_find(im, name, start)
3565         Imager::ImgRaw  im
3566         char *name
3567         int start
3568       PREINIT:
3569         int entry;
3570       CODE:
3571         if (i_tags_find(&im->tags, name, start, &entry)) {
3572           if (entry == 0)
3573             RETVAL = newSVpv("0 but true", 0);
3574           else
3575             RETVAL = newSViv(entry);
3576         } else {
3577           RETVAL = &PL_sv_undef;
3578         }
3579       OUTPUT:
3580         RETVAL
3581
3582 SV *
3583 i_tags_findn(im, code, start)
3584         Imager::ImgRaw  im
3585         int             code
3586         int             start
3587       PREINIT:
3588         int entry;
3589       CODE:
3590         if (i_tags_findn(&im->tags, code, start, &entry)) {
3591           if (entry == 0)
3592             RETVAL = newSVpv("0 but true", 0);
3593           else
3594             RETVAL = newSViv(entry);
3595         }
3596         else {
3597           RETVAL = &PL_sv_undef;
3598         }
3599       OUTPUT:
3600         RETVAL
3601
3602 int
3603 i_tags_delete(im, entry)
3604         Imager::ImgRaw  im
3605         int             entry
3606       CODE:
3607         RETVAL = i_tags_delete(&im->tags, entry);
3608       OUTPUT:
3609         RETVAL
3610
3611 int
3612 i_tags_delbyname(im, name)
3613         Imager::ImgRaw  im
3614         char *          name
3615       CODE:
3616         RETVAL = i_tags_delbyname(&im->tags, name);
3617       OUTPUT:
3618         RETVAL
3619
3620 int
3621 i_tags_delbycode(im, code)
3622         Imager::ImgRaw  im
3623         int             code
3624       CODE:
3625         RETVAL = i_tags_delbycode(&im->tags, code);
3626       OUTPUT:
3627         RETVAL
3628
3629 void
3630 i_tags_get(im, index)
3631         Imager::ImgRaw  im
3632         int             index
3633       PPCODE:
3634         if (index >= 0 && index < im->tags.count) {
3635           i_img_tag *entry = im->tags.tags + index;
3636           EXTEND(SP, 5);
3637         
3638           if (entry->name) {
3639             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3640           }
3641           else {
3642             PUSHs(sv_2mortal(newSViv(entry->code)));
3643           }
3644           if (entry->data) {
3645             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3646           }
3647           else {
3648             PUSHs(sv_2mortal(newSViv(entry->idata)));
3649           }
3650         }
3651
3652 void
3653 i_tags_get_string(im, what_sv)
3654         Imager::ImgRaw  im
3655         SV *what_sv
3656       PREINIT:
3657         char const *name = NULL;
3658         int code;
3659         char buffer[200];
3660       PPCODE:
3661         if (SvIOK(what_sv)) {
3662           code = SvIV(what_sv);
3663           name = NULL;
3664         }
3665         else {
3666           name = SvPV_nolen(what_sv);
3667           code = 0;
3668         }
3669         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
3670           EXTEND(SP, 1);
3671           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
3672         }
3673
3674 int
3675 i_tags_count(im)
3676         Imager::ImgRaw  im
3677       CODE:
3678         RETVAL = im->tags.count;
3679       OUTPUT:
3680         RETVAL
3681
3682
3683
3684 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
3685
3686 void
3687 IFILL_DESTROY(fill)
3688         Imager::FillHandle fill
3689
3690 int
3691 IFILL_CLONE_SKIP(...)
3692     CODE:
3693         RETVAL = 1;
3694     OUTPUT:
3695         RETVAL
3696
3697 MODULE = Imager         PACKAGE = Imager
3698
3699 Imager::FillHandle
3700 i_new_fill_solid(cl, combine)
3701         Imager::Color cl
3702         int combine
3703
3704 Imager::FillHandle
3705 i_new_fill_solidf(cl, combine)
3706         Imager::Color::Float cl
3707         int combine
3708
3709 Imager::FillHandle
3710 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
3711         Imager::Color fg
3712         Imager::Color bg
3713         int combine
3714         int hatch
3715         int dx
3716         int dy
3717       PREINIT:
3718         unsigned char *cust_hatch;
3719         STRLEN len;
3720       CODE:
3721         if (SvOK(ST(4))) {
3722           cust_hatch = (unsigned char *)SvPV(ST(4), len);
3723         }
3724         else
3725           cust_hatch = NULL;
3726         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
3727       OUTPUT:
3728         RETVAL
3729
3730 Imager::FillHandle
3731 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
3732         Imager::Color::Float fg
3733         Imager::Color::Float bg
3734         int combine
3735         int hatch
3736         int dx
3737         int dy
3738       PREINIT:
3739         unsigned char *cust_hatch;
3740         STRLEN len;
3741       CODE:
3742         if (SvOK(ST(4))) {
3743           cust_hatch = (unsigned char *)SvPV(ST(4), len);
3744         }
3745         else
3746           cust_hatch = NULL;
3747         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
3748       OUTPUT:
3749         RETVAL
3750
3751 Imager::FillHandle
3752 i_new_fill_image(src, matrix, xoff, yoff, combine)
3753         Imager::ImgRaw src
3754         int xoff
3755         int yoff
3756         int combine
3757       PREINIT:
3758         double matrix[9];
3759         double *matrixp;
3760         AV *av;
3761         IV len;
3762         SV *sv1;
3763         int i;
3764       CODE:
3765         if (!SvOK(ST(1))) {
3766           matrixp = NULL;
3767         }
3768         else {
3769           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
3770             croak("i_new_fill_image: parameter must be an arrayref");
3771           av=(AV*)SvRV(ST(1));
3772           len=av_len(av)+1;
3773           if (len > 9)
3774             len = 9;
3775           for (i = 0; i < len; ++i) {
3776             sv1=(*(av_fetch(av,i,0)));
3777             matrix[i] = SvNV(sv1);
3778           }
3779           for (; i < 9; ++i)
3780             matrix[i] = 0;
3781           matrixp = matrix;
3782         }
3783         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
3784       OUTPUT:
3785         RETVAL
3786
3787 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
3788
3789 # this class is only exposed for testing
3790
3791 int
3792 i_int_hlines_testing()
3793
3794 #if i_int_hlines_testing()
3795
3796 Imager::Internal::Hlines
3797 i_int_hlines_new(start_y, count_y, start_x, count_x)
3798         int start_y
3799         int count_y
3800         int start_x
3801         int count_x
3802
3803 Imager::Internal::Hlines
3804 i_int_hlines_new_img(im)
3805         Imager::ImgRaw im
3806
3807 void
3808 i_int_hlines_add(hlines, y, minx, width)
3809         Imager::Internal::Hlines hlines
3810         int y
3811         int minx
3812         int width
3813
3814 void
3815 i_int_hlines_DESTROY(hlines)
3816         Imager::Internal::Hlines hlines
3817
3818 SV *
3819 i_int_hlines_dump(hlines)
3820         Imager::Internal::Hlines hlines
3821
3822 int
3823 i_int_hlines_CLONE_SKIP(cls)
3824         SV *cls
3825
3826 #endif
3827
3828 BOOT:
3829         PERL_SET_GLOBAL_CALLBACKS;
3830         PERL_PL_SET_GLOBAL_CALLBACKS;