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