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