]> git.imager.perl.org - imager.git/blob - Imager.xs
6c9dafe6352d3e27e45874361ccc60042e3bcc9b
[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 hashinfo(hv)
3260              PREINIT:
3261                HV* hv;
3262                int stuff;
3263              PPCODE:
3264                if (!SvROK(ST(0))) croak("Imager: Parameter 0 must be a reference to a hash\n");        
3265                hv=(HV*)SvRV(ST(0));
3266                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 0 must be a reference to a hash\n");
3267                if (getint(hv,"stuff",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
3268                if (getint(hv,"stuff2",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
3269                
3270 void
3271 DSO_open(filename)
3272              char*       filename
3273              PREINIT:
3274                void *rc;
3275                char *evstr;
3276              PPCODE:
3277                rc=DSO_open(filename,&evstr);
3278                if (rc!=NULL) {
3279                  if (evstr!=NULL) {
3280                    EXTEND(SP,2); 
3281                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3282                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
3283                  } else {
3284                    EXTEND(SP,1);
3285                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3286                  }
3287                }
3288
3289
3290 undef_int
3291 DSO_close(dso_handle)
3292              void*       dso_handle
3293
3294 void
3295 DSO_funclist(dso_handle_v)
3296              void*       dso_handle_v
3297              PREINIT:
3298                int i;
3299                DSO_handle *dso_handle;
3300              PPCODE:
3301                dso_handle=(DSO_handle*)dso_handle_v;
3302                i=0;
3303                while( dso_handle->function_list[i].name != NULL) {
3304                  EXTEND(SP,1);
3305                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i].name,0)));
3306                  EXTEND(SP,1);
3307                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i++].pcode,0)));
3308                }
3309
3310
3311 void
3312 DSO_call(handle,func_index,hv)
3313                void*  handle
3314                int    func_index
3315              PREINIT:
3316                HV* hv;
3317              PPCODE:
3318                if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
3319                hv=(HV*)SvRV(ST(2));
3320                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
3321                DSO_call( (DSO_handle *)handle,func_index,hv);
3322
3323
3324
3325 SV *
3326 i_get_pixel(im, x, y)
3327         Imager::ImgRaw im
3328         int x
3329         int y;
3330       PREINIT:
3331         i_color *color;
3332       CODE:
3333         color = (i_color *)mymalloc(sizeof(i_color));
3334         if (i_gpix(im, x, y, color) == 0) {
3335           RETVAL = NEWSV(0, 0);
3336           sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
3337         }
3338         else {
3339           myfree(color);
3340           RETVAL = &PL_sv_undef;
3341         }
3342       OUTPUT:
3343         RETVAL
3344         
3345
3346 int
3347 i_ppix(im, x, y, cl)
3348         Imager::ImgRaw im
3349         int x
3350         int y
3351         Imager::Color cl
3352
3353 Imager::ImgRaw
3354 i_img_pal_new(x, y, channels, maxpal)
3355         int     x
3356         int     y
3357         int     channels
3358         int     maxpal
3359
3360 Imager::ImgRaw
3361 i_img_to_pal(src, quant)
3362         Imager::ImgRaw src
3363       PREINIT:
3364         HV *hv;
3365         i_quantize quant;
3366       CODE:
3367         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3368           croak("i_img_to_pal: second argument must be a hash ref");
3369         hv = (HV *)SvRV(ST(1));
3370         memset(&quant, 0, sizeof(quant));
3371         quant.mc_size = 256;
3372         handle_quant_opts(&quant, hv);
3373         RETVAL = i_img_to_pal(src, &quant);
3374         if (RETVAL) {
3375           copy_colors_back(hv, &quant);
3376         }
3377         cleanup_quant_opts(&quant);
3378       OUTPUT:
3379         RETVAL
3380
3381 Imager::ImgRaw
3382 i_img_to_rgb(src)
3383         Imager::ImgRaw src
3384
3385 void
3386 i_gpal(im, l, r, y)
3387         Imager::ImgRaw  im
3388         int     l
3389         int     r
3390         int     y
3391       PREINIT:
3392         i_palidx *work;
3393         int count, i;
3394       PPCODE:
3395         if (l < r) {
3396           work = mymalloc((r-l) * sizeof(i_palidx));
3397           count = i_gpal(im, l, r, y, work);
3398           if (GIMME_V == G_ARRAY) {
3399             EXTEND(SP, count);
3400             for (i = 0; i < count; ++i) {
3401               PUSHs(sv_2mortal(newSViv(work[i])));
3402             }
3403           }
3404           else {
3405             EXTEND(SP, 1);
3406             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3407           }
3408           myfree(work);
3409         }
3410         else {
3411           if (GIMME_V != G_ARRAY) {
3412             EXTEND(SP, 1);
3413             PUSHs(&PL_sv_undef);
3414           }
3415         }
3416
3417 int
3418 i_ppal(im, l, y, ...)
3419         Imager::ImgRaw  im
3420         int     l
3421         int     y
3422       PREINIT:
3423         i_palidx *work;
3424         int i;
3425       CODE:
3426         if (items > 3) {
3427           work = mymalloc(sizeof(i_palidx) * (items-3));
3428           for (i=0; i < items-3; ++i) {
3429             work[i] = SvIV(ST(i+3));
3430           }
3431           RETVAL = i_ppal(im, l, l+items-3, y, work);
3432           myfree(work);
3433         }
3434         else {
3435           RETVAL = 0;
3436         }
3437       OUTPUT:
3438         RETVAL
3439
3440 SV *
3441 i_addcolors(im, ...)
3442         Imager::ImgRaw  im
3443       PREINIT:
3444         int index;
3445         i_color *colors;
3446         int i;
3447       CODE:
3448         if (items < 2)
3449           croak("i_addcolors: no colors to add");
3450         colors = mymalloc((items-1) * sizeof(i_color));
3451         for (i=0; i < items-1; ++i) {
3452           if (sv_isobject(ST(i+1)) 
3453               && sv_derived_from(ST(i+1), "Imager::Color")) {
3454             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3455             colors[i] = *INT2PTR(i_color *, tmp);
3456           }
3457           else {
3458             myfree(colors);
3459             croak("i_addcolor: pixels must be Imager::Color objects");
3460           }
3461         }
3462         index = i_addcolors(im, colors, items-1);
3463         myfree(colors);
3464         if (index == 0) {
3465           RETVAL = newSVpv("0 but true", 0);
3466         }
3467         else if (index == -1) {
3468           RETVAL = &PL_sv_undef;
3469         }
3470         else {
3471           RETVAL = newSViv(index);
3472         }
3473       OUTPUT:
3474         RETVAL
3475
3476 undef_int 
3477 i_setcolors(im, index, ...)
3478         Imager::ImgRaw  im
3479         int index
3480       PREINIT:
3481         i_color *colors;
3482         int i;
3483       CODE:
3484         if (items < 3)
3485           croak("i_setcolors: no colors to add");
3486         colors = mymalloc((items-2) * sizeof(i_color));
3487         for (i=0; i < items-2; ++i) {
3488           if (sv_isobject(ST(i+2)) 
3489               && sv_derived_from(ST(i+2), "Imager::Color")) {
3490             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3491             colors[i] = *INT2PTR(i_color *, tmp);
3492           }
3493           else {
3494             myfree(colors);
3495             croak("i_setcolors: pixels must be Imager::Color objects");
3496           }
3497         }
3498         RETVAL = i_setcolors(im, index, colors, items-2);
3499         myfree(colors);
3500       OUTPUT:
3501         RETVAL
3502
3503 void
3504 i_getcolors(im, index, ...)
3505         Imager::ImgRaw im
3506         int index
3507       PREINIT:
3508         i_color *colors;
3509         int count = 1;
3510         int i;
3511       PPCODE:
3512         if (items > 3)
3513           croak("i_getcolors: too many arguments");
3514         if (items == 3)
3515           count = SvIV(ST(2));
3516         if (count < 1)
3517           croak("i_getcolors: count must be positive");
3518         colors = mymalloc(sizeof(i_color) * count);
3519         if (i_getcolors(im, index, colors, count)) {
3520           for (i = 0; i < count; ++i) {
3521             i_color *pv;
3522             SV *sv = sv_newmortal();
3523             pv = mymalloc(sizeof(i_color));
3524             *pv = colors[i];
3525             sv_setref_pv(sv, "Imager::Color", (void *)pv);
3526             PUSHs(sv);
3527           }
3528         }
3529         myfree(colors);
3530
3531
3532 undef_neg_int
3533 i_colorcount(im)
3534         Imager::ImgRaw im
3535
3536 undef_neg_int
3537 i_maxcolors(im)
3538         Imager::ImgRaw im
3539
3540 SV *
3541 i_findcolor(im, color)
3542         Imager::ImgRaw im
3543         Imager::Color color
3544       PREINIT:
3545         i_palidx index;
3546       CODE:
3547         if (i_findcolor(im, color, &index)) {
3548           RETVAL = newSViv(index);
3549         }
3550         else {
3551           RETVAL = &PL_sv_undef;
3552         }
3553       OUTPUT:
3554         RETVAL
3555
3556 int
3557 i_img_bits(im)
3558         Imager::ImgRaw  im
3559
3560 int
3561 i_img_type(im)
3562         Imager::ImgRaw  im
3563
3564 int
3565 i_img_virtual(im)
3566         Imager::ImgRaw  im
3567
3568 void
3569 i_gsamp(im, l, r, y, ...)
3570         Imager::ImgRaw im
3571         int l
3572         int r
3573         int y
3574       PREINIT:
3575         int *chans;
3576         int chan_count;
3577         i_sample_t *data;
3578         int count, i;
3579       PPCODE:
3580         if (items < 5)
3581           croak("No channel numbers supplied to g_samp()");
3582         if (l < r) {
3583           chan_count = items - 4;
3584           chans = mymalloc(sizeof(int) * chan_count);
3585           for (i = 0; i < chan_count; ++i)
3586             chans[i] = SvIV(ST(i+4));
3587           data = mymalloc(sizeof(i_sample_t) * (r-l) * chan_count); /* XXX: memleak? */
3588           count = i_gsamp(im, l, r, y, data, chans, chan_count);
3589           myfree(chans);
3590           if (GIMME_V == G_ARRAY) {
3591             EXTEND(SP, count);
3592             for (i = 0; i < count; ++i)
3593               PUSHs(sv_2mortal(newSViv(data[i])));
3594           }
3595           else {
3596             EXTEND(SP, 1);
3597             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3598           }
3599           myfree(data);
3600         }
3601         else {
3602           if (GIMME_V != G_ARRAY) {
3603             EXTEND(SP, 1);
3604             PUSHs(&PL_sv_undef);
3605           }
3606         }
3607
3608
3609 Imager::ImgRaw
3610 i_img_masked_new(targ, mask, x, y, w, h)
3611         Imager::ImgRaw targ
3612         int x
3613         int y
3614         int w
3615         int h
3616       PREINIT:
3617         i_img *mask;
3618       CODE:
3619         if (SvOK(ST(1))) {
3620           if (!sv_isobject(ST(1)) 
3621               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3622             croak("i_img_masked_new: parameter 2 must undef or an image");
3623           }
3624           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3625         }
3626         else
3627           mask = NULL;
3628         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3629       OUTPUT:
3630         RETVAL
3631
3632 int
3633 i_plin(im, l, y, ...)
3634         Imager::ImgRaw  im
3635         int     l
3636         int     y
3637       PREINIT:
3638         i_color *work;
3639         int i;
3640         STRLEN len;
3641         int count;
3642       CODE:
3643         if (items > 3) {
3644           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3645             /* supplied as a byte string */
3646             work = (i_color *)SvPV(ST(3), len);
3647             count = len / sizeof(i_color);
3648             if (count * sizeof(i_color) != len) {
3649               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3650             }
3651             RETVAL = i_plin(im, l, l+count, y, work);
3652           }
3653           else {
3654             work = mymalloc(sizeof(i_color) * (items-3));
3655             for (i=0; i < items-3; ++i) {
3656               if (sv_isobject(ST(i+3)) 
3657                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3658                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3659                 work[i] = *INT2PTR(i_color *, tmp);
3660               }
3661               else {
3662                 myfree(work);
3663                 croak("i_plin: pixels must be Imager::Color objects");
3664               }
3665             }
3666             RETVAL = i_plin(im, l, l+items-3, y, work);
3667             myfree(work);
3668           }
3669         }
3670         else {
3671           RETVAL = 0;
3672         }
3673       OUTPUT:
3674         RETVAL
3675
3676 int
3677 i_ppixf(im, x, y, cl)
3678         Imager::ImgRaw im
3679         int x
3680         int y
3681         Imager::Color::Float cl
3682
3683 void
3684 i_gsampf(im, l, r, y, ...)
3685         Imager::ImgRaw im
3686         int l
3687         int r
3688         int y
3689       PREINIT:
3690         int *chans;
3691         int chan_count;
3692         i_fsample_t *data;
3693         int count, i;
3694       PPCODE:
3695         if (items < 5)
3696           croak("No channel numbers supplied to g_sampf()");
3697         if (l < r) {
3698           chan_count = items - 4;
3699           chans = mymalloc(sizeof(int) * chan_count);
3700           for (i = 0; i < chan_count; ++i)
3701             chans[i] = SvIV(ST(i+4));
3702           data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count);
3703           count = i_gsampf(im, l, r, y, data, chans, chan_count);
3704           if (GIMME_V == G_ARRAY) {
3705             EXTEND(SP, count);
3706             for (i = 0; i < count; ++i)
3707               PUSHs(sv_2mortal(newSVnv(data[i])));
3708           }
3709           else {
3710             EXTEND(SP, 1);
3711             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3712           }
3713         }
3714         else {
3715           if (GIMME_V != G_ARRAY) {
3716             EXTEND(SP, 1);
3717             PUSHs(&PL_sv_undef);
3718           }
3719         }
3720
3721 int
3722 i_plinf(im, l, y, ...)
3723         Imager::ImgRaw  im
3724         int     l
3725         int     y
3726       PREINIT:
3727         i_fcolor *work;
3728         int i;
3729         STRLEN len;
3730         int count;
3731       CODE:
3732         if (items > 3) {
3733           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3734             /* supplied as a byte string */
3735             work = (i_fcolor *)SvPV(ST(3), len);
3736             count = len / sizeof(i_fcolor);
3737             if (count * sizeof(i_fcolor) != len) {
3738               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3739             }
3740             RETVAL = i_plinf(im, l, l+count, y, work);
3741           }
3742           else {
3743             work = mymalloc(sizeof(i_fcolor) * (items-3));
3744             for (i=0; i < items-3; ++i) {
3745               if (sv_isobject(ST(i+3)) 
3746                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3747                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3748                 work[i] = *INT2PTR(i_fcolor *, tmp);
3749               }
3750               else {
3751                 myfree(work);
3752                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3753               }
3754             }
3755             /**(char *)0 = 1;*/
3756             RETVAL = i_plinf(im, l, l+items-3, y, work);
3757             myfree(work);
3758           }
3759         }
3760         else {
3761           RETVAL = 0;
3762         }
3763       OUTPUT:
3764         RETVAL
3765
3766 SV *
3767 i_gpixf(im, x, y)
3768         Imager::ImgRaw im
3769         int x
3770         int y;
3771       PREINIT:
3772         i_fcolor *color;
3773       CODE:
3774         color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3775         if (i_gpixf(im, x, y, color) == 0) {
3776           RETVAL = NEWSV(0,0);
3777           sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
3778         }
3779         else {
3780           myfree(color);
3781           RETVAL = &PL_sv_undef;
3782         }
3783       OUTPUT:
3784         RETVAL
3785
3786 void
3787 i_glin(im, l, r, y)
3788         Imager::ImgRaw im
3789         int l
3790         int r
3791         int y
3792       PREINIT:
3793         i_color *vals;
3794         int count, i;
3795       PPCODE:
3796         if (l < r) {
3797           vals = mymalloc((r-l) * sizeof(i_color));
3798           count = i_glin(im, l, r, y, vals);
3799           if (GIMME_V == G_ARRAY) {
3800             EXTEND(SP, count);
3801             for (i = 0; i < count; ++i) {
3802               SV *sv;
3803               i_color *col = mymalloc(sizeof(i_color));
3804               *col = vals[i];
3805               sv = sv_newmortal();
3806               sv_setref_pv(sv, "Imager::Color", (void *)col);
3807               PUSHs(sv);
3808             }
3809           }
3810           else if (count) {
3811             EXTEND(SP, 1);
3812             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3813           }
3814           myfree(vals);
3815         }
3816
3817 void
3818 i_glinf(im, l, r, y)
3819         Imager::ImgRaw im
3820         int l
3821         int r
3822         int y
3823       PREINIT:
3824         i_fcolor *vals;
3825         int count, i;
3826       PPCODE:
3827         if (l < r) {
3828           vals = mymalloc((r-l) * sizeof(i_fcolor));
3829           count = i_glinf(im, l, r, y, vals);
3830           if (GIMME_V == G_ARRAY) {
3831             EXTEND(SP, count);
3832             for (i = 0; i < count; ++i) {
3833               SV *sv;
3834               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3835               *col = vals[i];
3836               sv = sv_newmortal();
3837               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3838               PUSHs(sv);
3839             }
3840           }
3841           else if (count) {
3842             EXTEND(SP, 1);
3843             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3844           }
3845           myfree(vals);
3846         }
3847
3848 Imager::ImgRaw
3849 i_img_16_new(x, y, ch)
3850         int x
3851         int y
3852         int ch
3853
3854 Imager::ImgRaw
3855 i_img_double_new(x, y, ch)
3856         int x
3857         int y
3858         int ch
3859
3860 undef_int
3861 i_tags_addn(im, name, code, idata)
3862         Imager::ImgRaw im
3863         int     code
3864         int     idata
3865       PREINIT:
3866         char *name;
3867         STRLEN len;
3868       CODE:
3869         if (SvOK(ST(1)))
3870           name = SvPV(ST(1), len);
3871         else
3872           name = NULL;
3873         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3874       OUTPUT:
3875         RETVAL
3876
3877 undef_int
3878 i_tags_add(im, name, code, data, idata)
3879         Imager::ImgRaw  im
3880         int code
3881         int idata
3882       PREINIT:
3883         char *name;
3884         char *data;
3885         STRLEN len;
3886       CODE:
3887         if (SvOK(ST(1)))
3888           name = SvPV(ST(1), len);
3889         else
3890           name = NULL;
3891         if (SvOK(ST(3)))
3892           data = SvPV(ST(3), len);
3893         else {
3894           data = NULL;
3895           len = 0;
3896         }
3897         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3898       OUTPUT:
3899         RETVAL
3900
3901 SV *
3902 i_tags_find(im, name, start)
3903         Imager::ImgRaw  im
3904         char *name
3905         int start
3906       PREINIT:
3907         int entry;
3908       CODE:
3909         if (i_tags_find(&im->tags, name, start, &entry)) {
3910           if (entry == 0)
3911             RETVAL = newSVpv("0 but true", 0);
3912           else
3913             RETVAL = newSViv(entry);
3914         } else {
3915           RETVAL = &PL_sv_undef;
3916         }
3917       OUTPUT:
3918         RETVAL
3919
3920 SV *
3921 i_tags_findn(im, code, start)
3922         Imager::ImgRaw  im
3923         int             code
3924         int             start
3925       PREINIT:
3926         int entry;
3927       CODE:
3928         if (i_tags_findn(&im->tags, code, start, &entry)) {
3929           if (entry == 0)
3930             RETVAL = newSVpv("0 but true", 0);
3931           else
3932             RETVAL = newSViv(entry);
3933         }
3934         else {
3935           RETVAL = &PL_sv_undef;
3936         }
3937       OUTPUT:
3938         RETVAL
3939
3940 int
3941 i_tags_delete(im, entry)
3942         Imager::ImgRaw  im
3943         int             entry
3944       CODE:
3945         RETVAL = i_tags_delete(&im->tags, entry);
3946       OUTPUT:
3947         RETVAL
3948
3949 int
3950 i_tags_delbyname(im, name)
3951         Imager::ImgRaw  im
3952         char *          name
3953       CODE:
3954         RETVAL = i_tags_delbyname(&im->tags, name);
3955       OUTPUT:
3956         RETVAL
3957
3958 int
3959 i_tags_delbycode(im, code)
3960         Imager::ImgRaw  im
3961         int             code
3962       CODE:
3963         RETVAL = i_tags_delbycode(&im->tags, code);
3964       OUTPUT:
3965         RETVAL
3966
3967 void
3968 i_tags_get(im, index)
3969         Imager::ImgRaw  im
3970         int             index
3971       PPCODE:
3972         if (index >= 0 && index < im->tags.count) {
3973           i_img_tag *entry = im->tags.tags + index;
3974           EXTEND(SP, 5);
3975         
3976           if (entry->name) {
3977             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3978           }
3979           else {
3980             PUSHs(sv_2mortal(newSViv(entry->code)));
3981           }
3982           if (entry->data) {
3983             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3984           }
3985           else {
3986             PUSHs(sv_2mortal(newSViv(entry->idata)));
3987           }
3988         }
3989
3990 void
3991 i_tags_get_string(im, what_sv)
3992         Imager::ImgRaw  im
3993         SV *what_sv
3994       PREINIT:
3995         char const *name = NULL;
3996         int code;
3997         char buffer[200];
3998       PPCODE:
3999         if (SvIOK(what_sv)) {
4000           code = SvIV(what_sv);
4001           name = NULL;
4002         }
4003         else {
4004           name = SvPV_nolen(what_sv);
4005           code = 0;
4006         }
4007         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
4008           EXTEND(SP, 1);
4009           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
4010         }
4011
4012 int
4013 i_tags_count(im)
4014         Imager::ImgRaw  im
4015       CODE:
4016         RETVAL = im->tags.count;
4017       OUTPUT:
4018         RETVAL
4019
4020 #ifdef HAVE_WIN32
4021
4022 void
4023 i_wf_bbox(face, size, text)
4024         char *face
4025         int size
4026         char *text
4027       PREINIT:
4028         int cords[BOUNDING_BOX_COUNT];
4029         int rc, i;
4030       PPCODE:
4031         if (rc = i_wf_bbox(face, size, text, strlen(text), cords)) {
4032           EXTEND(SP, rc);  
4033           for (i = 0; i < rc; ++i) 
4034             PUSHs(sv_2mortal(newSViv(cords[i])));
4035         }
4036
4037 undef_int
4038 i_wf_text(face, im, tx, ty, cl, size, text, align, aa)
4039         char *face
4040         Imager::ImgRaw im
4041         int tx
4042         int ty
4043         Imager::Color cl
4044         int size
4045         char *text
4046         int align
4047         int aa
4048       CODE:
4049         RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text), 
4050                            align, aa);
4051       OUTPUT:
4052         RETVAL
4053
4054 undef_int
4055 i_wf_cp(face, im, tx, ty, channel, size, text, align, aa)
4056         char *face
4057         Imager::ImgRaw im
4058         int tx
4059         int ty
4060         int channel
4061         int size
4062         char *text
4063         int align
4064         int aa
4065       CODE:
4066         RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text), 
4067                          align, aa);
4068       OUTPUT:
4069         RETVAL
4070
4071 undef_int
4072 i_wf_addfont(font)
4073         char *font
4074
4075 #endif
4076
4077 #ifdef HAVE_FT2
4078
4079 MODULE = Imager         PACKAGE = Imager::Font::FT2     PREFIX=FT2_
4080
4081 #define FT2_DESTROY(font) i_ft2_destroy(font)
4082
4083 void
4084 FT2_DESTROY(font)
4085         Imager::Font::FT2 font
4086
4087 MODULE = Imager         PACKAGE = Imager::Font::FreeType2 
4088
4089 Imager::Font::FT2
4090 i_ft2_new(name, index)
4091         char *name
4092         int index
4093
4094 undef_int
4095 i_ft2_setdpi(font, xdpi, ydpi)
4096         Imager::Font::FT2 font
4097         int xdpi
4098         int ydpi
4099
4100 void
4101 i_ft2_getdpi(font)
4102         Imager::Font::FT2 font
4103       PREINIT:
4104         int xdpi, ydpi;
4105       CODE:
4106         if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
4107           EXTEND(SP, 2);
4108           PUSHs(sv_2mortal(newSViv(xdpi)));
4109           PUSHs(sv_2mortal(newSViv(ydpi)));
4110         }
4111
4112 undef_int
4113 i_ft2_sethinting(font, hinting)
4114         Imager::Font::FT2 font
4115         int hinting
4116
4117 undef_int
4118 i_ft2_settransform(font, matrix)
4119         Imager::Font::FT2 font
4120       PREINIT:
4121         double matrix[6];
4122         int len;
4123         AV *av;
4124         SV *sv1;
4125         int i;
4126       CODE:
4127         if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4128           croak("i_ft2_settransform: parameter 2 must be an array ref\n");
4129         av=(AV*)SvRV(ST(1));
4130         len=av_len(av)+1;
4131         if (len > 6)
4132           len = 6;
4133         for (i = 0; i < len; ++i) {
4134           sv1=(*(av_fetch(av,i,0)));
4135           matrix[i] = SvNV(sv1);
4136         }
4137         for (; i < 6; ++i)
4138           matrix[i] = 0;
4139         RETVAL = i_ft2_settransform(font, matrix);
4140       OUTPUT:
4141         RETVAL
4142
4143 void
4144 i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
4145         Imager::Font::FT2 font
4146         double cheight
4147         double cwidth
4148         SV *text_sv
4149         int utf8
4150       PREINIT:
4151         int bbox[BOUNDING_BOX_COUNT];
4152         int i;
4153         char *text;
4154         STRLEN text_len;
4155         int rc;
4156       PPCODE:
4157         text = SvPV(text_sv, text_len);
4158 #ifdef SvUTF8
4159         if (SvUTF8(text_sv))
4160           utf8 = 1;
4161 #endif
4162         rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8);
4163         if (rc) {
4164           EXTEND(SP, rc);
4165           for (i = 0; i < rc; ++i)
4166             PUSHs(sv_2mortal(newSViv(bbox[i])));
4167         }
4168
4169 void
4170 i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
4171         Imager::Font::FT2 font
4172         double cheight
4173         double cwidth
4174         char *text
4175         int vlayout
4176         int utf8
4177       PREINIT:
4178         int bbox[8];
4179         int i;
4180       PPCODE:
4181 #ifdef SvUTF8
4182         if (SvUTF8(ST(3)))
4183           utf8 = 1;
4184 #endif
4185         if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
4186                          utf8, bbox)) {
4187           EXTEND(SP, 8);
4188           for (i = 0; i < 8; ++i)
4189             PUSHs(sv_2mortal(newSViv(bbox[i])));
4190         }
4191
4192 undef_int
4193 i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
4194         Imager::Font::FT2 font
4195         Imager::ImgRaw im
4196         int tx
4197         int ty
4198         Imager::Color cl
4199         double cheight
4200         double cwidth
4201         int align
4202         int aa
4203         int vlayout
4204         int utf8
4205       PREINIT:
4206         char *text;
4207         STRLEN len;
4208       CODE:
4209 #ifdef SvUTF8
4210         if (SvUTF8(ST(7))) {
4211           utf8 = 1;
4212         }
4213 #endif
4214         text = SvPV(ST(7), len);
4215         RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
4216                             len, align, aa, vlayout, utf8);
4217       OUTPUT:
4218         RETVAL
4219
4220 undef_int
4221 i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8)
4222         Imager::Font::FT2 font
4223         Imager::ImgRaw im
4224         int tx
4225         int ty
4226         int channel
4227         double cheight
4228         double cwidth
4229         char *text
4230         int align
4231         int aa
4232         int vlayout
4233         int utf8
4234       CODE:
4235 #ifdef SvUTF8
4236         if (SvUTF8(ST(7)))
4237           utf8 = 1;
4238 #endif
4239         RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
4240                           strlen(text), align, aa, vlayout, 1);
4241       OUTPUT:
4242         RETVAL
4243
4244 void
4245 ft2_transform_box(font, x0, x1, x2, x3)
4246         Imager::Font::FT2 font
4247         int x0
4248         int x1
4249         int x2
4250         int x3
4251       PREINIT:
4252         int box[4];
4253       PPCODE:
4254         box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
4255         ft2_transform_box(font, box);
4256           EXTEND(SP, 4);
4257           PUSHs(sv_2mortal(newSViv(box[0])));
4258           PUSHs(sv_2mortal(newSViv(box[1])));
4259           PUSHs(sv_2mortal(newSViv(box[2])));
4260           PUSHs(sv_2mortal(newSViv(box[3])));
4261
4262 void
4263 i_ft2_has_chars(handle, text_sv, utf8)
4264         Imager::Font::FT2 handle
4265         SV  *text_sv
4266         int utf8
4267       PREINIT:
4268         char *text;
4269         STRLEN len;
4270         char *work;
4271         int count;
4272         int i;
4273       PPCODE:
4274 #ifdef SvUTF8
4275         if (SvUTF8(text_sv))
4276           utf8 = 1;
4277 #endif
4278         text = SvPV(text_sv, len);
4279         work = mymalloc(len);
4280         count = i_ft2_has_chars(handle, text, len, utf8, work);
4281         if (GIMME_V == G_ARRAY) {
4282           EXTEND(SP, count);
4283           for (i = 0; i < count; ++i) {
4284             PUSHs(sv_2mortal(newSViv(work[i])));
4285           }
4286         }
4287         else {
4288           EXTEND(SP, 1);
4289           PUSHs(sv_2mortal(newSVpv(work, count)));
4290         }
4291         myfree(work);
4292
4293 void
4294 i_ft2_face_name(handle)
4295         Imager::Font::FT2 handle
4296       PREINIT:
4297         char name[255];
4298         int len;
4299       PPCODE:
4300         len = i_ft2_face_name(handle, name, sizeof(name));
4301         if (len) {
4302           EXTEND(SP, 1);
4303           PUSHs(sv_2mortal(newSVpv(name, 0)));
4304         }
4305
4306 undef_int
4307 i_ft2_can_face_name()
4308
4309 void
4310 i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
4311         Imager::Font::FT2 handle
4312         SV *text_sv
4313         int utf8
4314         int reliable_only
4315       PREINIT:
4316         char const *text;
4317         STRLEN work_len;
4318         int len;
4319         char name[255];
4320       PPCODE:
4321 #ifdef SvUTF8
4322         if (SvUTF8(text_sv))
4323           utf8 = 1;
4324 #endif
4325         text = SvPV(text_sv, work_len);
4326         len = work_len;
4327         while (len) {
4328           unsigned long ch;
4329           if (utf8) {
4330             ch = i_utf8_advance(&text, &len);
4331             if (ch == ~0UL) {
4332               i_push_error(0, "invalid UTF8 character");
4333               break;
4334             }
4335           }
4336           else {
4337             ch = *text++;
4338             --len;
4339           }
4340           EXTEND(SP, 1);
4341           if (i_ft2_glyph_name(handle, ch, name, sizeof(name), 
4342                                          reliable_only)) {
4343             PUSHs(sv_2mortal(newSVpv(name, 0)));
4344           }
4345           else {
4346             PUSHs(&PL_sv_undef);
4347           } 
4348         }
4349
4350 int
4351 i_ft2_can_do_glyph_names()
4352
4353 int
4354 i_ft2_face_has_glyph_names(handle)
4355         Imager::Font::FT2 handle
4356
4357 int
4358 i_ft2_is_multiple_master(handle)
4359         Imager::Font::FT2 handle
4360
4361 void
4362 i_ft2_get_multiple_masters(handle)
4363         Imager::Font::FT2 handle
4364       PREINIT:
4365         i_font_mm mm;
4366         int i;
4367       PPCODE:
4368         if (i_ft2_get_multiple_masters(handle, &mm)) {
4369           EXTEND(SP, 2+mm.num_axis);
4370           PUSHs(sv_2mortal(newSViv(mm.num_axis)));
4371           PUSHs(sv_2mortal(newSViv(mm.num_designs)));
4372           for (i = 0; i < mm.num_axis; ++i) {
4373             AV *av = newAV();
4374             SV *sv;
4375             av_extend(av, 3);
4376             sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name));
4377             SvREFCNT_inc(sv);
4378             av_store(av, 0, sv);
4379             sv = newSViv(mm.axis[i].minimum);
4380             SvREFCNT_inc(sv);
4381             av_store(av, 1, sv);
4382             sv = newSViv(mm.axis[i].maximum);
4383             SvREFCNT_inc(sv);
4384             av_store(av, 2, sv);
4385             PUSHs(newRV_noinc((SV *)av));
4386           }
4387         }
4388
4389 undef_int
4390 i_ft2_set_mm_coords(handle, ...)
4391         Imager::Font::FT2 handle
4392       PROTOTYPE: DISABLE
4393       PREINIT:
4394         long *coords;
4395         int ix_coords, i;
4396       CODE:
4397         /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so
4398            transfer the array manually */
4399         ix_coords = items-1;
4400         coords = mymalloc(sizeof(long) * ix_coords);
4401         for (i = 0; i < ix_coords; ++i) {
4402           coords[i] = (long)SvIV(ST(1+i));
4403         }
4404         RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords);
4405         myfree(coords);
4406       OUTPUT:
4407         RETVAL
4408
4409 #endif
4410
4411 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
4412
4413 void
4414 IFILL_DESTROY(fill)
4415         Imager::FillHandle fill
4416
4417 MODULE = Imager         PACKAGE = Imager
4418
4419 Imager::FillHandle
4420 i_new_fill_solid(cl, combine)
4421         Imager::Color cl
4422         int combine
4423
4424 Imager::FillHandle
4425 i_new_fill_solidf(cl, combine)
4426         Imager::Color::Float cl
4427         int combine
4428
4429 Imager::FillHandle
4430 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
4431         Imager::Color fg
4432         Imager::Color bg
4433         int combine
4434         int hatch
4435         int dx
4436         int dy
4437       PREINIT:
4438         unsigned char *cust_hatch;
4439         STRLEN len;
4440       CODE:
4441         if (SvOK(ST(4))) {
4442           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4443         }
4444         else
4445           cust_hatch = NULL;
4446         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
4447       OUTPUT:
4448         RETVAL
4449
4450 Imager::FillHandle
4451 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
4452         Imager::Color::Float fg
4453         Imager::Color::Float bg
4454         int combine
4455         int hatch
4456         int dx
4457         int dy
4458       PREINIT:
4459         unsigned char *cust_hatch;
4460         STRLEN len;
4461       CODE:
4462         if (SvOK(ST(4))) {
4463           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4464         }
4465         else
4466           cust_hatch = NULL;
4467         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
4468       OUTPUT:
4469         RETVAL
4470
4471 Imager::FillHandle
4472 i_new_fill_image(src, matrix, xoff, yoff, combine)
4473         Imager::ImgRaw src
4474         int xoff
4475         int yoff
4476         int combine
4477       PREINIT:
4478         double matrix[9];
4479         double *matrixp;
4480         AV *av;
4481         IV len;
4482         SV *sv1;
4483         int i;
4484       CODE:
4485         if (!SvOK(ST(1))) {
4486           matrixp = NULL;
4487         }
4488         else {
4489           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4490             croak("i_new_fill_image: parameter must be an arrayref");
4491           av=(AV*)SvRV(ST(1));
4492           len=av_len(av)+1;
4493           if (len > 9)
4494             len = 9;
4495           for (i = 0; i < len; ++i) {
4496             sv1=(*(av_fetch(av,i,0)));
4497             matrix[i] = SvNV(sv1);
4498           }
4499           for (; i < 9; ++i)
4500             matrix[i] = 0;
4501           matrixp = matrix;
4502         }
4503         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4504       OUTPUT:
4505         RETVAL
4506
4507 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
4508
4509 # this class is only exposed for testing
4510
4511 int
4512 i_int_hlines_testing()
4513
4514 #if i_int_hlines_testing()
4515
4516 Imager::Internal::Hlines
4517 i_int_hlines_new(start_y, count_y, start_x, count_x)
4518         int start_y
4519         int count_y
4520         int start_x
4521         int count_x
4522
4523 Imager::Internal::Hlines
4524 i_int_hlines_new_img(im)
4525         Imager::ImgRaw im
4526
4527 void
4528 i_int_hlines_add(hlines, y, minx, width)
4529         Imager::Internal::Hlines hlines
4530         int y
4531         int minx
4532         int width
4533
4534 void
4535 i_int_hlines_DESTROY(hlines)
4536         Imager::Internal::Hlines hlines
4537
4538 SV *
4539 i_int_hlines_dump(hlines)
4540         Imager::Internal::Hlines hlines
4541
4542 #endif
4543
4544 BOOT:
4545         PERL_SET_GLOBAL_CALLBACKS;