- start of external Imager API access:
[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         int outsize;
1843         char name[255];
1844       PPCODE:
1845 #ifdef SvUTF8
1846         if (SvUTF8(text_sv))
1847           utf8 = 1;
1848 #endif
1849         text = SvPV(text_sv, work_len);
1850         len = work_len;
1851         while (len) {
1852           unsigned long ch;
1853           if (utf8) {
1854             ch = i_utf8_advance(&text, &len);
1855             if (ch == ~0UL) {
1856               i_push_error(0, "invalid UTF8 character");
1857               break;
1858             }
1859           }
1860           else {
1861             ch = *text++;
1862             --len;
1863           }
1864           EXTEND(SP, 1);
1865           if (outsize = i_t1_glyph_name(handle, ch, name, sizeof(name))) {
1866             PUSHs(sv_2mortal(newSVpv(name, 0)));
1867           }
1868           else {
1869             PUSHs(&PL_sv_undef);
1870           } 
1871         }
1872
1873 #endif 
1874
1875 #ifdef HAVE_LIBTT
1876
1877
1878 Imager::Font::TT
1879 i_tt_new(fontname)
1880               char*     fontname
1881
1882
1883 MODULE = Imager         PACKAGE = Imager::Font::TT      PREFIX=TT_
1884
1885 #define TT_DESTROY(handle) i_tt_destroy(handle)
1886
1887 void
1888 TT_DESTROY(handle)
1889      Imager::Font::TT   handle
1890
1891
1892 MODULE = Imager         PACKAGE = Imager
1893
1894
1895 undef_int
1896 i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1)
1897   Imager::Font::TT     handle
1898     Imager::ImgRaw     im
1899                int     xb
1900                int     yb
1901      Imager::Color     cl
1902              float     points
1903               SV *     str_sv
1904                int     len_ignored
1905                int     smooth
1906                int     utf8
1907                int     align
1908              PREINIT:
1909                char *str;
1910                STRLEN len;
1911              CODE:
1912 #ifdef SvUTF8
1913                if (SvUTF8(str_sv))
1914                  utf8 = 1;
1915 #endif
1916                str = SvPV(str_sv, len);
1917                RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, 
1918                                   len, smooth, utf8, align);
1919              OUTPUT:
1920                RETVAL                
1921
1922
1923 undef_int
1924 i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1)
1925   Imager::Font::TT     handle
1926     Imager::ImgRaw     im
1927                int     xb
1928                int     yb
1929                int     channel
1930              float     points
1931               SV *     str_sv
1932                int     len_ignored
1933                int     smooth
1934                int     utf8
1935                int     align
1936              PREINIT:
1937                char *str;
1938                STRLEN len;
1939              CODE:
1940 #ifdef SvUTF8
1941                if (SvUTF8(str_sv))
1942                  utf8 = 1;
1943 #endif
1944                str = SvPV(str_sv, len);
1945                RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len,
1946                                 smooth, utf8, align);
1947              OUTPUT:
1948                 RETVAL
1949
1950
1951 void
1952 i_tt_bbox(handle,point,str_sv,len_ignored, utf8)
1953   Imager::Font::TT     handle
1954              float     point
1955                SV*    str_sv
1956                int     len_ignored
1957                int     utf8
1958              PREINIT:
1959                int     cords[BOUNDING_BOX_COUNT],rc;
1960                char *  str;
1961                STRLEN len;
1962                int i;
1963              PPCODE:
1964 #ifdef SvUTF8
1965                if (SvUTF8(ST(2)))
1966                  utf8 = 1;
1967 #endif
1968                str = SvPV(str_sv, len);
1969                if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) {
1970                  EXTEND(SP, rc);
1971                  for (i = 0; i < rc; ++i) {
1972                    PUSHs(sv_2mortal(newSViv(cords[i])));
1973                  }
1974                }
1975
1976 void
1977 i_tt_has_chars(handle, text_sv, utf8)
1978         Imager::Font::TT handle
1979         SV  *text_sv
1980         int utf8
1981       PREINIT:
1982         char const *text;
1983         STRLEN len;
1984         char *work;
1985         int count;
1986         int i;
1987       PPCODE:
1988 #ifdef SvUTF8
1989         if (SvUTF8(text_sv))
1990           utf8 = 1;
1991 #endif
1992         text = SvPV(text_sv, len);
1993         work = mymalloc(len);
1994         count = i_tt_has_chars(handle, text, len, utf8, work);
1995         if (GIMME_V == G_ARRAY) {
1996           EXTEND(SP, count);
1997           for (i = 0; i < count; ++i) {
1998             PUSHs(sv_2mortal(newSViv(work[i])));
1999           }
2000         }
2001         else {
2002           EXTEND(SP, 1);
2003           PUSHs(sv_2mortal(newSVpv(work, count)));
2004         }
2005         myfree(work);
2006
2007 void
2008 i_tt_dump_names(handle)
2009         Imager::Font::TT handle
2010
2011 void
2012 i_tt_face_name(handle)
2013         Imager::Font::TT handle
2014       PREINIT:
2015         char name[255];
2016         int len;
2017       PPCODE:
2018         len = i_tt_face_name(handle, name, sizeof(name));
2019         if (len) {
2020           EXTEND(SP, 1);
2021           PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
2022         }
2023
2024 void
2025 i_tt_glyph_name(handle, text_sv, utf8 = 0)
2026         Imager::Font::TT handle
2027         SV *text_sv
2028         int utf8
2029       PREINIT:
2030         char const *text;
2031         STRLEN work_len;
2032         int len;
2033         int outsize;
2034         char name[255];
2035       PPCODE:
2036 #ifdef SvUTF8
2037         if (SvUTF8(text_sv))
2038           utf8 = 1;
2039 #endif
2040         text = SvPV(text_sv, work_len);
2041         len = work_len;
2042         while (len) {
2043           unsigned long ch;
2044           if (utf8) {
2045             ch = i_utf8_advance(&text, &len);
2046             if (ch == ~0UL) {
2047               i_push_error(0, "invalid UTF8 character");
2048               break;
2049             }
2050           }
2051           else {
2052             ch = *text++;
2053             --len;
2054           }
2055           EXTEND(SP, 1);
2056           if (outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) {
2057             PUSHs(sv_2mortal(newSVpv(name, 0)));
2058           }
2059           else {
2060             PUSHs(&PL_sv_undef);
2061           } 
2062         }
2063
2064 #endif 
2065
2066
2067 #ifdef HAVE_LIBJPEG
2068 undef_int
2069 i_writejpeg_wiol(im, ig, qfactor)
2070     Imager::ImgRaw     im
2071         Imager::IO     ig
2072                int     qfactor
2073
2074
2075 void
2076 i_readjpeg_wiol(ig)
2077         Imager::IO     ig
2078              PREINIT:
2079               char*    iptc_itext;
2080                int     tlength;
2081              i_img*    rimg;
2082                 SV*    r;
2083              PPCODE:
2084               iptc_itext = NULL;
2085               rimg = i_readjpeg_wiol(ig,-1,&iptc_itext,&tlength);
2086               if (iptc_itext == NULL) {
2087                     r = sv_newmortal();
2088                     EXTEND(SP,1);
2089                     sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2090                     PUSHs(r);
2091               } else {
2092                     r = sv_newmortal();
2093                     EXTEND(SP,2);
2094                     sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2095                     PUSHs(r);
2096                     PUSHs(sv_2mortal(newSVpv(iptc_itext,tlength)));
2097                     myfree(iptc_itext);
2098               }
2099
2100 int
2101 i_exif_enabled()
2102
2103 #endif
2104
2105
2106 char *
2107 i_test_format_probe(ig, length)
2108         Imager::IO     ig
2109                int     length
2110
2111
2112
2113 #ifdef HAVE_LIBTIFF
2114
2115 Imager::ImgRaw
2116 i_readtiff_wiol(ig, length, page=0)
2117         Imager::IO     ig
2118                int     length
2119                int     page
2120
2121 void
2122 i_readtiff_multi_wiol(ig, length)
2123         Imager::IO     ig
2124                int     length
2125       PREINIT:
2126         i_img **imgs;
2127         int count;
2128         int i;
2129       PPCODE:
2130         imgs = i_readtiff_multi_wiol(ig, length, &count);
2131         if (imgs) {
2132           EXTEND(SP, count);
2133           for (i = 0; i < count; ++i) {
2134             SV *sv = sv_newmortal();
2135             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2136             PUSHs(sv);
2137           }
2138           myfree(imgs);
2139         }
2140
2141
2142 undef_int
2143 i_writetiff_wiol(im, ig)
2144     Imager::ImgRaw     im
2145         Imager::IO     ig
2146
2147 undef_int
2148 i_writetiff_multi_wiol(ig, ...)
2149         Imager::IO     ig
2150       PREINIT:
2151         int i;
2152         int img_count;
2153         i_img **imgs;
2154       CODE:
2155         if (items < 2)
2156           croak("Usage: i_writetiff_multi_wiol(ig, images...)");
2157         img_count = items - 1;
2158         RETVAL = 1;
2159         if (img_count < 1) {
2160           RETVAL = 0;
2161           i_clear_error();
2162           i_push_error(0, "You need to specify images to save");
2163         }
2164         else {
2165           imgs = mymalloc(sizeof(i_img *) * img_count);
2166           for (i = 0; i < img_count; ++i) {
2167             SV *sv = ST(1+i);
2168             imgs[i] = NULL;
2169             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2170               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2171             }
2172             else {
2173               i_clear_error();
2174               i_push_error(0, "Only images can be saved");
2175               myfree(imgs);
2176               RETVAL = 0;
2177               break;
2178             }
2179           }
2180           if (RETVAL) {
2181             RETVAL = i_writetiff_multi_wiol(ig, imgs, img_count);
2182           }
2183           myfree(imgs);
2184         }
2185       OUTPUT:
2186         RETVAL
2187
2188 undef_int
2189 i_writetiff_wiol_faxable(im, ig, fine)
2190     Imager::ImgRaw     im
2191         Imager::IO     ig
2192                int     fine
2193
2194 undef_int
2195 i_writetiff_multi_wiol_faxable(ig, fine, ...)
2196         Imager::IO     ig
2197         int fine
2198       PREINIT:
2199         int i;
2200         int img_count;
2201         i_img **imgs;
2202       CODE:
2203         if (items < 3)
2204           croak("Usage: i_writetiff_multi_wiol_faxable(ig, fine, images...)");
2205         img_count = items - 2;
2206         RETVAL = 1;
2207         if (img_count < 1) {
2208           RETVAL = 0;
2209           i_clear_error();
2210           i_push_error(0, "You need to specify images to save");
2211         }
2212         else {
2213           imgs = mymalloc(sizeof(i_img *) * img_count);
2214           for (i = 0; i < img_count; ++i) {
2215             SV *sv = ST(2+i);
2216             imgs[i] = NULL;
2217             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2218               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2219             }
2220             else {
2221               i_clear_error();
2222               i_push_error(0, "Only images can be saved");
2223               myfree(imgs);
2224               RETVAL = 0;
2225               break;
2226             }
2227           }
2228           if (RETVAL) {
2229             RETVAL = i_writetiff_multi_wiol_faxable(ig, imgs, img_count, fine);
2230           }
2231           myfree(imgs);
2232         }
2233       OUTPUT:
2234         RETVAL
2235
2236
2237 #endif /* HAVE_LIBTIFF */
2238
2239
2240 #ifdef HAVE_LIBPNG
2241
2242 Imager::ImgRaw
2243 i_readpng_wiol(ig, length)
2244         Imager::IO     ig
2245                int     length
2246
2247
2248 undef_int
2249 i_writepng_wiol(im, ig)
2250     Imager::ImgRaw     im
2251         Imager::IO     ig
2252
2253
2254 #endif
2255
2256
2257 #ifdef HAVE_LIBGIF
2258
2259 void
2260 i_giflib_version()
2261         PPCODE:
2262           PUSHs(sv_2mortal(newSVnv(IM_GIFMAJOR+IM_GIFMINOR*0.1)));
2263
2264 undef_int
2265 i_writegif(im,fd,colors,pixdev,fixed)
2266     Imager::ImgRaw     im
2267                int     fd
2268                int     colors
2269                int     pixdev
2270              PREINIT:
2271              int     fixedlen;
2272              Imager__Color  fixed;
2273              Imager__Color  tmp;
2274              AV* av;
2275              SV* sv1;
2276              IV  Itmp;
2277              int i;
2278              CODE:
2279              if (!SvROK(ST(4))) croak("Imager: Parameter 4 must be a reference to an array\n");
2280              if (SvTYPE(SvRV(ST(4))) != SVt_PVAV) croak("Imager: Parameter 4 must be a reference to an array\n");
2281              av=(AV*)SvRV(ST(4));
2282              fixedlen=av_len(av)+1;
2283              fixed=mymalloc( fixedlen*sizeof(i_color) );
2284              for(i=0;i<fixedlen;i++) {
2285                sv1=(*(av_fetch(av,i,0)));
2286                if (sv_derived_from(sv1, "Imager::Color")) {
2287                  Itmp = SvIV((SV*)SvRV(sv1));
2288                  tmp = INT2PTR(i_color*, Itmp);
2289                } else croak("Imager: one of the elements of array ref is not of Imager::Color type\n");
2290                fixed[i]=*tmp;
2291              }
2292              RETVAL=i_writegif(im,fd,colors,pixdev,fixedlen,fixed);
2293              myfree(fixed);
2294              ST(0) = sv_newmortal();
2295              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2296              else sv_setiv(ST(0), (IV)RETVAL);
2297
2298
2299
2300
2301 undef_int
2302 i_writegifmc(im,fd,colors)
2303     Imager::ImgRaw    im
2304                int     fd
2305                int     colors
2306
2307
2308 undef_int
2309 i_writegif_gen(fd, ...)
2310                int     fd
2311       PROTOTYPE: $$@
2312       PREINIT:
2313         i_quantize quant;
2314         i_img **imgs = NULL;
2315         int img_count;
2316         int i;
2317         HV *hv;
2318       CODE:
2319         if (items < 3)
2320             croak("Usage: i_writegif_gen(fd,hashref, images...)");
2321         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2322             croak("i_writegif_gen: Second argument must be a hash ref");
2323         hv = (HV *)SvRV(ST(1));
2324         memset(&quant, 0, sizeof(quant));
2325         quant.mc_size = 256;
2326         handle_quant_opts(&quant, hv);
2327         img_count = items - 2;
2328         RETVAL = 1;
2329         if (img_count < 1) {
2330           RETVAL = 0;
2331           i_clear_error();
2332           i_push_error(0, "You need to specify images to save");
2333         }
2334         else {
2335           imgs = mymalloc(sizeof(i_img *) * img_count);
2336           for (i = 0; i < img_count; ++i) {
2337             SV *sv = ST(2+i);
2338             imgs[i] = NULL;
2339             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2340               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2341             }
2342             else {
2343               i_clear_error();
2344               i_push_error(0, "Only images can be saved");
2345               RETVAL = 0;
2346               break;
2347             }
2348           }
2349           if (RETVAL) {
2350             RETVAL = i_writegif_gen(&quant, fd, imgs, img_count);
2351           }
2352           myfree(imgs);
2353           if (RETVAL) {
2354             copy_colors_back(hv, &quant);
2355           }
2356         }
2357         ST(0) = sv_newmortal();
2358         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2359         else sv_setiv(ST(0), (IV)RETVAL);
2360         cleanup_quant_opts(&quant);
2361
2362
2363 undef_int
2364 i_writegif_callback(cb, maxbuffer,...)
2365         int maxbuffer;
2366       PREINIT:
2367         i_quantize quant;
2368         i_img **imgs = NULL;
2369         int img_count;
2370         int i;
2371         HV *hv;
2372         i_writer_data wd;
2373       CODE:
2374         if (items < 4)
2375             croak("Usage: i_writegif_callback(\\&callback,maxbuffer,hashref, images...)");
2376         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2377             croak("i_writegif_callback: Second argument must be a hash ref");
2378         hv = (HV *)SvRV(ST(2));
2379         memset(&quant, 0, sizeof(quant));
2380         quant.mc_size = 256;
2381         handle_quant_opts(&quant, hv);
2382         img_count = items - 3;
2383         RETVAL = 1;
2384         if (img_count < 1) {
2385           RETVAL = 0;
2386         }
2387         else {
2388           imgs = mymalloc(sizeof(i_img *) * img_count);
2389           for (i = 0; i < img_count; ++i) {
2390             SV *sv = ST(3+i);
2391             imgs[i] = NULL;
2392             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2393               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2394             }
2395             else {
2396               RETVAL = 0;
2397               break;
2398             }
2399           }
2400           if (RETVAL) {
2401             wd.sv = ST(0);
2402             RETVAL = i_writegif_callback(&quant, write_callback, (char *)&wd, maxbuffer, imgs, img_count);
2403           }
2404           myfree(imgs);
2405           if (RETVAL) {
2406             copy_colors_back(hv, &quant);
2407           }
2408         }
2409         ST(0) = sv_newmortal();
2410         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2411         else sv_setiv(ST(0), (IV)RETVAL);
2412         cleanup_quant_opts(&quant);
2413
2414 undef_int
2415 i_writegif_wiol(ig, opts,...)
2416         Imager::IO ig
2417       PREINIT:
2418         i_quantize quant;
2419         i_img **imgs = NULL;
2420         int img_count;
2421         int i;
2422         HV *hv;
2423       CODE:
2424         if (items < 3)
2425             croak("Usage: i_writegif_wiol(IO,hashref, images...)");
2426         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2427             croak("i_writegif_callback: Second argument must be a hash ref");
2428         hv = (HV *)SvRV(ST(1));
2429         memset(&quant, 0, sizeof(quant));
2430         quant.mc_size = 256;
2431         handle_quant_opts(&quant, hv);
2432         img_count = items - 2;
2433         RETVAL = 1;
2434         if (img_count < 1) {
2435           RETVAL = 0;
2436         }
2437         else {
2438           imgs = mymalloc(sizeof(i_img *) * img_count);
2439           for (i = 0; i < img_count; ++i) {
2440             SV *sv = ST(2+i);
2441             imgs[i] = NULL;
2442             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2443               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2444             }
2445             else {
2446               RETVAL = 0;
2447               break;
2448             }
2449           }
2450           if (RETVAL) {
2451             RETVAL = i_writegif_wiol(ig, &quant, imgs, img_count);
2452           }
2453           myfree(imgs);
2454           if (RETVAL) {
2455             copy_colors_back(hv, &quant);
2456           }
2457         }
2458         ST(0) = sv_newmortal();
2459         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2460         else sv_setiv(ST(0), (IV)RETVAL);
2461         cleanup_quant_opts(&quant);
2462
2463 void
2464 i_readgif(fd)
2465                int     fd
2466               PREINIT:
2467                 int*    colour_table;
2468                 int     colours, q, w;
2469               i_img*    rimg;
2470                  SV*    temp[3];
2471                  AV*    ct; 
2472                  SV*    r;
2473                PPCODE:
2474                colour_table = NULL;
2475                colours = 0;
2476
2477         if(GIMME_V == G_ARRAY) {
2478             rimg = i_readgif(fd,&colour_table,&colours);
2479         } else {
2480             /* don't waste time with colours if they aren't wanted */
2481             rimg = i_readgif(fd,NULL,NULL);
2482         }
2483         
2484         if (colour_table == NULL) {
2485             EXTEND(SP,1);
2486             r=sv_newmortal();
2487             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2488             PUSHs(r);
2489         } else {
2490             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2491             /* I don't know if I have the reference counts right or not :( */
2492             /* Neither do I :-) */
2493             /* No Idea here either */
2494
2495             ct=newAV();
2496             av_extend(ct, colours);
2497             for(q=0; q<colours; q++) {
2498                 for(w=0; w<3; w++)
2499                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2500                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2501             }
2502             myfree(colour_table);
2503
2504             EXTEND(SP,2);
2505             r = sv_newmortal();
2506             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2507             PUSHs(r);
2508             PUSHs(newRV_noinc((SV*)ct));
2509         }
2510
2511 void
2512 i_readgif_wiol(ig)
2513      Imager::IO         ig
2514               PREINIT:
2515                 int*    colour_table;
2516                 int     colours, q, w;
2517               i_img*    rimg;
2518                  SV*    temp[3];
2519                  AV*    ct; 
2520                  SV*    r;
2521                PPCODE:
2522                colour_table = NULL;
2523                colours = 0;
2524
2525         if(GIMME_V == G_ARRAY) {
2526             rimg = i_readgif_wiol(ig,&colour_table,&colours);
2527         } else {
2528             /* don't waste time with colours if they aren't wanted */
2529             rimg = i_readgif_wiol(ig,NULL,NULL);
2530         }
2531         
2532         if (colour_table == NULL) {
2533             EXTEND(SP,1);
2534             r=sv_newmortal();
2535             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2536             PUSHs(r);
2537         } else {
2538             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2539             /* I don't know if I have the reference counts right or not :( */
2540             /* Neither do I :-) */
2541             /* No Idea here either */
2542
2543             ct=newAV();
2544             av_extend(ct, colours);
2545             for(q=0; q<colours; q++) {
2546                 for(w=0; w<3; w++)
2547                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2548                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2549             }
2550             myfree(colour_table);
2551
2552             EXTEND(SP,2);
2553             r = sv_newmortal();
2554             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2555             PUSHs(r);
2556             PUSHs(newRV_noinc((SV*)ct));
2557         }
2558
2559 Imager::ImgRaw
2560 i_readgif_single_wiol(ig, page=0)
2561         Imager::IO      ig
2562         int             page
2563
2564 void
2565 i_readgif_scalar(...)
2566           PROTOTYPE: $
2567             PREINIT:
2568                char*    data;
2569              STRLEN     length;
2570                 int*    colour_table;
2571                 int     colours, q, w;
2572               i_img*    rimg;
2573                  SV*    temp[3];
2574                  AV*    ct; 
2575                  SV*    r;
2576                PPCODE:
2577         data = (char *)SvPV(ST(0), length);
2578         colour_table=NULL;
2579         colours=0;
2580
2581         if(GIMME_V == G_ARRAY) {  
2582             rimg=i_readgif_scalar(data,length,&colour_table,&colours);
2583         } else {
2584             /* don't waste time with colours if they aren't wanted */
2585             rimg=i_readgif_scalar(data,length,NULL,NULL);
2586         }
2587
2588         if (colour_table == NULL) {
2589             EXTEND(SP,1);
2590             r=sv_newmortal();
2591             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2592             PUSHs(r);
2593         } else {
2594             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2595             /* I don't know if I have the reference counts right or not :( */
2596             /* Neither do I :-) */
2597             ct=newAV();
2598             av_extend(ct, colours);
2599             for(q=0; q<colours; q++) {
2600                 for(w=0; w<3; w++)
2601                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2602                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2603             }
2604             myfree(colour_table);
2605             
2606             EXTEND(SP,2);
2607             r=sv_newmortal();
2608             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2609             PUSHs(r);
2610             PUSHs(newRV_noinc((SV*)ct));
2611         }
2612
2613 void
2614 i_readgif_callback(...)
2615           PROTOTYPE: &
2616             PREINIT:
2617                 int*    colour_table;
2618                 int     colours, q, w;
2619               i_img*    rimg;
2620                  SV*    temp[3];
2621                  AV*    ct; 
2622                  SV*    r;
2623        i_reader_data    rd;
2624                PPCODE:
2625         rd.sv = ST(0);
2626         colour_table=NULL;
2627         colours=0;
2628
2629         if(GIMME_V == G_ARRAY) {  
2630             rimg=i_readgif_callback(read_callback, (char *)&rd,&colour_table,&colours);
2631         } else {
2632             /* don't waste time with colours if they aren't wanted */
2633             rimg=i_readgif_callback(read_callback, (char *)&rd,NULL,NULL);
2634         }
2635
2636         if (colour_table == NULL) {
2637             EXTEND(SP,1);
2638             r=sv_newmortal();
2639             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2640             PUSHs(r);
2641         } else {
2642             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2643             /* I don't know if I have the reference counts right or not :( */
2644             /* Neither do I :-) */
2645             /* Neither do I - maybe I'll move this somewhere */
2646             ct=newAV();
2647             av_extend(ct, colours);
2648             for(q=0; q<colours; q++) {
2649                 for(w=0; w<3; w++)
2650                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2651                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2652             }
2653             myfree(colour_table);
2654             
2655             EXTEND(SP,2);
2656             r=sv_newmortal();
2657             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2658             PUSHs(r);
2659             PUSHs(newRV_noinc((SV*)ct));
2660         }
2661
2662 void
2663 i_readgif_multi(fd)
2664         int     fd
2665       PREINIT:
2666         i_img **imgs;
2667         int count;
2668         int i;
2669       PPCODE:
2670         imgs = i_readgif_multi(fd, &count);
2671         if (imgs) {
2672           EXTEND(SP, count);
2673           for (i = 0; i < count; ++i) {
2674             SV *sv = sv_newmortal();
2675             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2676             PUSHs(sv);
2677           }
2678           myfree(imgs);
2679         }
2680
2681 void
2682 i_readgif_multi_scalar(data)
2683       PREINIT:
2684         i_img **imgs;
2685         int count;
2686         char *data;
2687         STRLEN length;
2688         int i;
2689       PPCODE:
2690         data = (char *)SvPV(ST(0), length);
2691         imgs = i_readgif_multi_scalar(data, length, &count);
2692         if (imgs) {
2693           EXTEND(SP, count);
2694           for (i = 0; i < count; ++i) {
2695             SV *sv = sv_newmortal();
2696             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2697             PUSHs(sv);
2698           }
2699           myfree(imgs);
2700         }
2701
2702 void
2703 i_readgif_multi_callback(cb)
2704       PREINIT:
2705         i_reader_data rd;
2706         i_img **imgs;
2707         int count;
2708         int i;
2709       PPCODE:
2710         rd.sv = ST(0);
2711         imgs = i_readgif_multi_callback(read_callback, (char *)&rd, &count);
2712         if (imgs) {
2713           EXTEND(SP, count);
2714           for (i = 0; i < count; ++i) {
2715             SV *sv = sv_newmortal();
2716             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2717             PUSHs(sv);
2718           }
2719           myfree(imgs);
2720         }
2721
2722 void
2723 i_readgif_multi_wiol(ig)
2724         Imager::IO ig
2725       PREINIT:
2726         i_img **imgs;
2727         int count;
2728         int i;
2729       PPCODE:
2730         imgs = i_readgif_multi_wiol(ig, &count);
2731         if (imgs) {
2732           EXTEND(SP, count);
2733           for (i = 0; i < count; ++i) {
2734             SV *sv = sv_newmortal();
2735             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2736             PUSHs(sv);
2737           }
2738           myfree(imgs);
2739         }
2740
2741
2742 #endif
2743
2744
2745
2746 Imager::ImgRaw
2747 i_readpnm_wiol(ig, length)
2748         Imager::IO     ig
2749                int     length
2750
2751
2752 undef_int
2753 i_writeppm_wiol(im, ig)
2754     Imager::ImgRaw     im
2755         Imager::IO     ig
2756
2757
2758 Imager::ImgRaw
2759 i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
2760         Imager::IO     ig
2761                int     x
2762                int     y
2763                int     datachannels
2764                int     storechannels
2765                int     intrl
2766
2767 undef_int
2768 i_writeraw_wiol(im,ig)
2769     Imager::ImgRaw     im
2770         Imager::IO     ig
2771
2772 undef_int
2773 i_writebmp_wiol(im,ig)
2774     Imager::ImgRaw     im
2775         Imager::IO     ig
2776
2777 Imager::ImgRaw
2778 i_readbmp_wiol(ig)
2779         Imager::IO     ig
2780
2781
2782 undef_int
2783 i_writetga_wiol(im,ig, wierdpack, compress, idstring)
2784     Imager::ImgRaw     im
2785         Imager::IO     ig
2786                int     wierdpack
2787                int     compress
2788               char*    idstring
2789             PREINIT:
2790                 int idlen;
2791                CODE:
2792                 idlen  = SvCUR(ST(4));
2793                 RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
2794                 OUTPUT:
2795                 RETVAL
2796
2797
2798 Imager::ImgRaw
2799 i_readtga_wiol(ig, length)
2800         Imager::IO     ig
2801                int     length
2802
2803
2804 undef_int
2805 i_writergb_wiol(im,ig, wierdpack, compress, idstring)
2806     Imager::ImgRaw     im
2807         Imager::IO     ig
2808                int     wierdpack
2809                int     compress
2810               char*    idstring
2811             PREINIT:
2812                 int idlen;
2813                CODE:
2814                 idlen  = SvCUR(ST(4));
2815                 RETVAL = i_writergb_wiol(im, ig, wierdpack, compress, idstring, idlen);
2816                 OUTPUT:
2817                 RETVAL
2818
2819
2820 Imager::ImgRaw
2821 i_readrgb_wiol(ig, length)
2822         Imager::IO     ig
2823                int     length
2824
2825
2826
2827 Imager::ImgRaw
2828 i_scaleaxis(im,Value,Axis)
2829     Imager::ImgRaw     im
2830              float     Value
2831                int     Axis
2832
2833 Imager::ImgRaw
2834 i_scale_nn(im,scx,scy)
2835     Imager::ImgRaw     im
2836              float     scx
2837              float     scy
2838
2839 Imager::ImgRaw
2840 i_haar(im)
2841     Imager::ImgRaw     im
2842
2843 int
2844 i_count_colors(im,maxc)
2845     Imager::ImgRaw     im
2846                int     maxc
2847
2848
2849 Imager::ImgRaw
2850 i_transform(im,opx,opy,parm)
2851     Imager::ImgRaw     im
2852              PREINIT:
2853              double* parm;
2854              int*    opx;
2855              int*    opy;
2856              int     opxl;
2857              int     opyl;
2858              int     parmlen;
2859              AV* av;
2860              SV* sv1;
2861              int i;
2862              CODE:
2863              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
2864              if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n");
2865              if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n");
2866              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
2867              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n");
2868              if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n");
2869              av=(AV*)SvRV(ST(1));
2870              opxl=av_len(av)+1;
2871              opx=mymalloc( opxl*sizeof(int) );
2872              for(i=0;i<opxl;i++) {
2873                sv1=(*(av_fetch(av,i,0)));
2874                opx[i]=(int)SvIV(sv1);
2875              }
2876              av=(AV*)SvRV(ST(2));
2877              opyl=av_len(av)+1;
2878              opy=mymalloc( opyl*sizeof(int) );
2879              for(i=0;i<opyl;i++) {
2880                sv1=(*(av_fetch(av,i,0)));
2881                opy[i]=(int)SvIV(sv1);
2882              }
2883              av=(AV*)SvRV(ST(3));
2884              parmlen=av_len(av)+1;
2885              parm=mymalloc( parmlen*sizeof(double) );
2886              for(i=0;i<parmlen;i++) { /* FIXME: Bug? */
2887                sv1=(*(av_fetch(av,i,0)));
2888                parm[i]=(double)SvNV(sv1);
2889              }
2890              RETVAL=i_transform(im,opx,opxl,opy,opyl,parm,parmlen);
2891              myfree(parm);
2892              myfree(opy);
2893              myfree(opx);
2894              ST(0) = sv_newmortal();
2895              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2896              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2897
2898 Imager::ImgRaw
2899 i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
2900         SV *sv_width
2901         SV *sv_height
2902         SV *sv_ops
2903         AV *av_n_regs
2904         AV *av_c_regs
2905         AV *av_in_imgs
2906         int channels
2907              PREINIT:
2908              int width;
2909              int height;
2910              struct rm_op *ops;
2911              STRLEN ops_len;
2912              int ops_count;
2913              double *n_regs;
2914              int n_regs_count;
2915              i_color *c_regs;
2916              int c_regs_count;
2917              int in_imgs_count;
2918              i_img **in_imgs;
2919              SV *sv1;
2920              IV tmp;
2921              int i;
2922              CODE:
2923
2924              in_imgs_count = av_len(av_in_imgs)+1;
2925              for (i = 0; i < in_imgs_count; ++i) {
2926                sv1 = *av_fetch(av_in_imgs, i, 0);
2927                if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2928                  croak("sv_in_img must contain only images");
2929                }
2930              }
2931              if (in_imgs_count > 0) {
2932                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2933                for (i = 0; i < in_imgs_count; ++i) {              
2934                  sv1 = *av_fetch(av_in_imgs,i,0);
2935                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2936                    croak("Parameter 5 must contain only images");
2937                  }
2938                  tmp = SvIV((SV*)SvRV(sv1));
2939                  in_imgs[i] = INT2PTR(i_img*, tmp);
2940                }
2941              }
2942              else {
2943                /* no input images */
2944                in_imgs = NULL;
2945              }
2946              /* default the output size from the first input if possible */
2947              if (SvOK(sv_width))
2948                width = SvIV(sv_width);
2949              else if (in_imgs_count)
2950                width = in_imgs[0]->xsize;
2951              else
2952                croak("No output image width supplied");
2953
2954              if (SvOK(sv_height))
2955                height = SvIV(sv_height);
2956              else if (in_imgs_count)
2957                height = in_imgs[0]->ysize;
2958              else
2959                croak("No output image height supplied");
2960
2961              ops = (struct rm_op *)SvPV(sv_ops, ops_len);
2962              if (ops_len % sizeof(struct rm_op))
2963                  croak("Imager: Parameter 3 must be a bitmap of regops\n");
2964              ops_count = ops_len / sizeof(struct rm_op);
2965
2966              n_regs_count = av_len(av_n_regs)+1;
2967              n_regs = mymalloc(n_regs_count * sizeof(double));
2968              for (i = 0; i < n_regs_count; ++i) {
2969                sv1 = *av_fetch(av_n_regs,i,0);
2970                if (SvOK(sv1))
2971                  n_regs[i] = SvNV(sv1);
2972              }
2973              c_regs_count = av_len(av_c_regs)+1;
2974              c_regs = mymalloc(c_regs_count * sizeof(i_color));
2975              /* I don't bother initializing the colou?r registers */
2976
2977              RETVAL=i_transform2(width, height, channels, ops, ops_count, 
2978                                  n_regs, n_regs_count, 
2979                                  c_regs, c_regs_count, in_imgs, in_imgs_count);
2980              if (in_imgs)
2981                  myfree(in_imgs);
2982              myfree(n_regs);
2983              myfree(c_regs);
2984              ST(0) = sv_newmortal();
2985              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2986              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2987
2988
2989 void
2990 i_contrast(im,intensity)
2991     Imager::ImgRaw     im
2992              float     intensity
2993
2994 void
2995 i_hardinvert(im)
2996     Imager::ImgRaw     im
2997
2998 void
2999 i_noise(im,amount,type)
3000     Imager::ImgRaw     im
3001              float     amount
3002      unsigned char     type
3003
3004 void
3005 i_bumpmap(im,bump,channel,light_x,light_y,strength)
3006     Imager::ImgRaw     im
3007     Imager::ImgRaw     bump
3008                int     channel
3009                int     light_x
3010                int     light_y
3011                int     strength
3012
3013
3014 void
3015 i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
3016     Imager::ImgRaw     im
3017     Imager::ImgRaw     bump
3018                int     channel
3019                int     tx
3020                int     ty
3021              float     Lx
3022              float     Ly
3023              float     Lz
3024              float     cd
3025              float     cs
3026              float     n
3027      Imager::Color     Ia
3028      Imager::Color     Il
3029      Imager::Color     Is
3030
3031
3032
3033 void
3034 i_postlevels(im,levels)
3035     Imager::ImgRaw     im
3036              int       levels
3037
3038 void
3039 i_mosaic(im,size)
3040     Imager::ImgRaw     im
3041                int     size
3042
3043 void
3044 i_watermark(im,wmark,tx,ty,pixdiff)
3045     Imager::ImgRaw     im
3046     Imager::ImgRaw     wmark
3047                int     tx
3048                int     ty
3049                int     pixdiff
3050
3051
3052 void
3053 i_autolevels(im,lsat,usat,skew)
3054     Imager::ImgRaw     im
3055              float     lsat
3056              float     usat
3057              float     skew
3058
3059 void
3060 i_radnoise(im,xo,yo,rscale,ascale)
3061     Imager::ImgRaw     im
3062              float     xo
3063              float     yo
3064              float     rscale
3065              float     ascale
3066
3067 void
3068 i_turbnoise(im, xo, yo, scale)
3069     Imager::ImgRaw     im
3070              float     xo
3071              float     yo
3072              float     scale
3073
3074
3075 void
3076 i_gradgen(im, ...)
3077     Imager::ImgRaw     im
3078       PREINIT:
3079         int num;
3080         int *xo;
3081         int *yo;
3082         i_color *ival;
3083         int dmeasure;
3084         int i;
3085         SV *sv;
3086         AV *axx;
3087         AV *ayy;
3088         AV *ac;
3089       CODE:
3090         if (items != 5)
3091             croak("Usage: i_gradgen(im, xo, yo, ival, dmeasure)");
3092         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3093             croak("i_gradgen: Second argument must be an array ref");
3094         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
3095             croak("i_gradgen: Third argument must be an array ref");
3096         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
3097             croak("i_gradgen: Fourth argument must be an array ref");
3098         axx = (AV *)SvRV(ST(1));
3099         ayy = (AV *)SvRV(ST(2));
3100         ac  = (AV *)SvRV(ST(3));
3101         dmeasure = (int)SvIV(ST(4));
3102         
3103         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
3104         num = num <= av_len(ac) ? num : av_len(ac);
3105         num++; 
3106         if (num < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each");
3107         xo = mymalloc( sizeof(int) * num );
3108         yo = mymalloc( sizeof(int) * num );
3109         ival = mymalloc( sizeof(i_color) * num );
3110         for(i = 0; i<num; i++) {
3111           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
3112           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
3113           sv = *av_fetch(ac, i, 0);
3114           if ( !sv_derived_from(sv, "Imager::Color") ) {
3115             free(axx); free(ayy); free(ac);
3116             croak("i_gradgen: Element of fourth argument is not derived from Imager::Color");
3117           }
3118           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
3119         }
3120         i_gradgen(im, num, xo, yo, ival, dmeasure);
3121         myfree(xo);
3122         myfree(yo);
3123         myfree(ival);
3124
3125 Imager::ImgRaw
3126 i_diff_image(im, im2, mindist=0)
3127     Imager::ImgRaw     im
3128     Imager::ImgRaw     im2
3129                int     mindist
3130
3131 void
3132 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
3133     Imager::ImgRaw     im
3134             double     xa
3135             double     ya
3136             double     xb
3137             double     yb
3138                int     type
3139                int     repeat
3140                int     combine
3141                int     super_sample
3142             double     ssample_param
3143       PREINIT:
3144         AV *asegs;
3145         int count;
3146         i_fountain_seg *segs;
3147       CODE:
3148         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
3149             croak("i_fountain: argument 11 must be an array ref");
3150         
3151         asegs = (AV *)SvRV(ST(10));
3152         segs = load_fount_segs(asegs, &count);
3153         i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, 
3154                    ssample_param, count, segs);
3155         myfree(segs);
3156
3157 Imager::FillHandle
3158 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
3159             double     xa
3160             double     ya
3161             double     xb
3162             double     yb
3163                int     type
3164                int     repeat
3165                int     combine
3166                int     super_sample
3167             double     ssample_param
3168       PREINIT:
3169         AV *asegs;
3170         int count;
3171         i_fountain_seg *segs;
3172       CODE:
3173         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
3174             croak("i_fountain: argument 11 must be an array ref");
3175         
3176         asegs = (AV *)SvRV(ST(9));
3177         segs = load_fount_segs(asegs, &count);
3178         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
3179                                   super_sample, ssample_param, count, segs);
3180         myfree(segs);        
3181       OUTPUT:
3182         RETVAL
3183
3184 void
3185 i_errors()
3186       PREINIT:
3187         i_errmsg *errors;
3188         int i;
3189         AV *av;
3190         SV *sv;
3191       PPCODE:
3192         errors = i_errors();
3193         i = 0;
3194         while (errors[i].msg) {
3195           av = newAV();
3196           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
3197           if (!av_store(av, 0, sv)) {
3198             SvREFCNT_dec(sv);
3199           }
3200           sv = newSViv(errors[i].code);
3201           if (!av_store(av, 1, sv)) {
3202             SvREFCNT_dec(sv);
3203           }
3204           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
3205           ++i;
3206         }
3207
3208 void
3209 i_nearest_color(im, ...)
3210     Imager::ImgRaw     im
3211       PREINIT:
3212         int num;
3213         int *xo;
3214         int *yo;
3215         i_color *ival;
3216         int dmeasure;
3217         int i;
3218         SV *sv;
3219         AV *axx;
3220         AV *ayy;
3221         AV *ac;
3222       CODE:
3223         if (items != 5)
3224             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
3225         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3226             croak("i_nearest_color: Second argument must be an array ref");
3227         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
3228             croak("i_nearest_color: Third argument must be an array ref");
3229         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
3230             croak("i_nearest_color: Fourth argument must be an array ref");
3231         axx = (AV *)SvRV(ST(1));
3232         ayy = (AV *)SvRV(ST(2));
3233         ac  = (AV *)SvRV(ST(3));
3234         dmeasure = (int)SvIV(ST(4));
3235         
3236         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
3237         num = num <= av_len(ac) ? num : av_len(ac);
3238         num++; 
3239         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
3240         xo = mymalloc( sizeof(int) * num );
3241         yo = mymalloc( sizeof(int) * num );
3242         ival = mymalloc( sizeof(i_color) * num );
3243         for(i = 0; i<num; i++) {
3244           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
3245           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
3246           sv = *av_fetch(ac, i, 0);
3247           if ( !sv_derived_from(sv, "Imager::Color") ) {
3248             free(axx); free(ayy); free(ac);
3249             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
3250           }
3251           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
3252         }
3253         i_nearest_color(im, num, xo, yo, ival, dmeasure);
3254
3255
3256
3257
3258 void
3259 malloc_state()
3260
3261 void
3262 hashinfo(hv)
3263              PREINIT:
3264                HV* hv;
3265                int stuff;
3266              PPCODE:
3267                if (!SvROK(ST(0))) croak("Imager: Parameter 0 must be a reference to a hash\n");        
3268                hv=(HV*)SvRV(ST(0));
3269                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 0 must be a reference to a hash\n");
3270                if (getint(hv,"stuff",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
3271                if (getint(hv,"stuff2",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
3272                
3273 void
3274 DSO_open(filename)
3275              char*       filename
3276              PREINIT:
3277                void *rc;
3278                char *evstr;
3279              PPCODE:
3280                rc=DSO_open(filename,&evstr);
3281                if (rc!=NULL) {
3282                  if (evstr!=NULL) {
3283                    EXTEND(SP,2); 
3284                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3285                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
3286                  } else {
3287                    EXTEND(SP,1);
3288                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3289                  }
3290                }
3291
3292
3293 undef_int
3294 DSO_close(dso_handle)
3295              void*       dso_handle
3296
3297 void
3298 DSO_funclist(dso_handle_v)
3299              void*       dso_handle_v
3300              PREINIT:
3301                int i;
3302                DSO_handle *dso_handle;
3303              PPCODE:
3304                dso_handle=(DSO_handle*)dso_handle_v;
3305                i=0;
3306                while( dso_handle->function_list[i].name != NULL) {
3307                  EXTEND(SP,1);
3308                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i].name,0)));
3309                  EXTEND(SP,1);
3310                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i++].pcode,0)));
3311                }
3312
3313
3314 void
3315 DSO_call(handle,func_index,hv)
3316                void*  handle
3317                int    func_index
3318              PREINIT:
3319                HV* hv;
3320              PPCODE:
3321                if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
3322                hv=(HV*)SvRV(ST(2));
3323                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
3324                DSO_call( (DSO_handle *)handle,func_index,hv);
3325
3326
3327
3328 SV *
3329 i_get_pixel(im, x, y)
3330         Imager::ImgRaw im
3331         int x
3332         int y;
3333       PREINIT:
3334         i_color *color;
3335       CODE:
3336         color = (i_color *)mymalloc(sizeof(i_color));
3337         if (i_gpix(im, x, y, color) == 0) {
3338           RETVAL = NEWSV(0, 0);
3339           sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
3340         }
3341         else {
3342           myfree(color);
3343           RETVAL = &PL_sv_undef;
3344         }
3345       OUTPUT:
3346         RETVAL
3347         
3348
3349 int
3350 i_ppix(im, x, y, cl)
3351         Imager::ImgRaw im
3352         int x
3353         int y
3354         Imager::Color cl
3355
3356 Imager::ImgRaw
3357 i_img_pal_new(x, y, channels, maxpal)
3358         int     x
3359         int     y
3360         int     channels
3361         int     maxpal
3362
3363 Imager::ImgRaw
3364 i_img_to_pal(src, quant)
3365         Imager::ImgRaw src
3366       PREINIT:
3367         HV *hv;
3368         i_quantize quant;
3369       CODE:
3370         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3371           croak("i_img_to_pal: second argument must be a hash ref");
3372         hv = (HV *)SvRV(ST(1));
3373         memset(&quant, 0, sizeof(quant));
3374         quant.mc_size = 256;
3375         handle_quant_opts(&quant, hv);
3376         RETVAL = i_img_to_pal(src, &quant);
3377         if (RETVAL) {
3378           copy_colors_back(hv, &quant);
3379         }
3380         cleanup_quant_opts(&quant);
3381       OUTPUT:
3382         RETVAL
3383
3384 Imager::ImgRaw
3385 i_img_to_rgb(src)
3386         Imager::ImgRaw src
3387
3388 void
3389 i_gpal(im, l, r, y)
3390         Imager::ImgRaw  im
3391         int     l
3392         int     r
3393         int     y
3394       PREINIT:
3395         i_palidx *work;
3396         int count, i;
3397       PPCODE:
3398         if (l < r) {
3399           work = mymalloc((r-l) * sizeof(i_palidx));
3400           count = i_gpal(im, l, r, y, work);
3401           if (GIMME_V == G_ARRAY) {
3402             EXTEND(SP, count);
3403             for (i = 0; i < count; ++i) {
3404               PUSHs(sv_2mortal(newSViv(work[i])));
3405             }
3406           }
3407           else {
3408             EXTEND(SP, 1);
3409             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3410           }
3411           myfree(work);
3412         }
3413         else {
3414           if (GIMME_V != G_ARRAY) {
3415             EXTEND(SP, 1);
3416             PUSHs(&PL_sv_undef);
3417           }
3418         }
3419
3420 int
3421 i_ppal(im, l, y, ...)
3422         Imager::ImgRaw  im
3423         int     l
3424         int     y
3425       PREINIT:
3426         i_palidx *work;
3427         int i;
3428       CODE:
3429         if (items > 3) {
3430           work = mymalloc(sizeof(i_palidx) * (items-3));
3431           for (i=0; i < items-3; ++i) {
3432             work[i] = SvIV(ST(i+3));
3433           }
3434           RETVAL = i_ppal(im, l, l+items-3, y, work);
3435           myfree(work);
3436         }
3437         else {
3438           RETVAL = 0;
3439         }
3440       OUTPUT:
3441         RETVAL
3442
3443 SV *
3444 i_addcolors(im, ...)
3445         Imager::ImgRaw  im
3446       PREINIT:
3447         int index;
3448         i_color *colors;
3449         int i;
3450       CODE:
3451         if (items < 2)
3452           croak("i_addcolors: no colors to add");
3453         colors = mymalloc((items-1) * sizeof(i_color));
3454         for (i=0; i < items-1; ++i) {
3455           if (sv_isobject(ST(i+1)) 
3456               && sv_derived_from(ST(i+1), "Imager::Color")) {
3457             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3458             colors[i] = *INT2PTR(i_color *, tmp);
3459           }
3460           else {
3461             myfree(colors);
3462             croak("i_addcolor: pixels must be Imager::Color objects");
3463           }
3464         }
3465         index = i_addcolors(im, colors, items-1);
3466         myfree(colors);
3467         if (index == 0) {
3468           RETVAL = newSVpv("0 but true", 0);
3469         }
3470         else if (index == -1) {
3471           RETVAL = &PL_sv_undef;
3472         }
3473         else {
3474           RETVAL = newSViv(index);
3475         }
3476       OUTPUT:
3477         RETVAL
3478
3479 undef_int 
3480 i_setcolors(im, index, ...)
3481         Imager::ImgRaw  im
3482         int index
3483       PREINIT:
3484         i_color *colors;
3485         int i;
3486       CODE:
3487         if (items < 3)
3488           croak("i_setcolors: no colors to add");
3489         colors = mymalloc((items-2) * sizeof(i_color));
3490         for (i=0; i < items-2; ++i) {
3491           if (sv_isobject(ST(i+2)) 
3492               && sv_derived_from(ST(i+2), "Imager::Color")) {
3493             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3494             colors[i] = *INT2PTR(i_color *, tmp);
3495           }
3496           else {
3497             myfree(colors);
3498             croak("i_setcolors: pixels must be Imager::Color objects");
3499           }
3500         }
3501         RETVAL = i_setcolors(im, index, colors, items-2);
3502         myfree(colors);
3503       OUTPUT:
3504         RETVAL
3505
3506 void
3507 i_getcolors(im, index, ...)
3508         Imager::ImgRaw im
3509         int index
3510       PREINIT:
3511         i_color *colors;
3512         int count = 1;
3513         int i;
3514       PPCODE:
3515         if (items > 3)
3516           croak("i_getcolors: too many arguments");
3517         if (items == 3)
3518           count = SvIV(ST(2));
3519         if (count < 1)
3520           croak("i_getcolors: count must be positive");
3521         colors = mymalloc(sizeof(i_color) * count);
3522         if (i_getcolors(im, index, colors, count)) {
3523           for (i = 0; i < count; ++i) {
3524             i_color *pv;
3525             SV *sv = sv_newmortal();
3526             pv = mymalloc(sizeof(i_color));
3527             *pv = colors[i];
3528             sv_setref_pv(sv, "Imager::Color", (void *)pv);
3529             PUSHs(sv);
3530           }
3531         }
3532         myfree(colors);
3533
3534
3535 undef_neg_int
3536 i_colorcount(im)
3537         Imager::ImgRaw im
3538
3539 undef_neg_int
3540 i_maxcolors(im)
3541         Imager::ImgRaw im
3542
3543 SV *
3544 i_findcolor(im, color)
3545         Imager::ImgRaw im
3546         Imager::Color color
3547       PREINIT:
3548         i_palidx index;
3549       CODE:
3550         if (i_findcolor(im, color, &index)) {
3551           RETVAL = newSViv(index);
3552         }
3553         else {
3554           RETVAL = &PL_sv_undef;
3555         }
3556       OUTPUT:
3557         RETVAL
3558
3559 int
3560 i_img_bits(im)
3561         Imager::ImgRaw  im
3562
3563 int
3564 i_img_type(im)
3565         Imager::ImgRaw  im
3566
3567 int
3568 i_img_virtual(im)
3569         Imager::ImgRaw  im
3570
3571 void
3572 i_gsamp(im, l, r, y, ...)
3573         Imager::ImgRaw im
3574         int l
3575         int r
3576         int y
3577       PREINIT:
3578         int *chans;
3579         int chan_count;
3580         i_sample_t *data;
3581         int count, i;
3582       PPCODE:
3583         if (items < 5)
3584           croak("No channel numbers supplied to g_samp()");
3585         if (l < r) {
3586           chan_count = items - 4;
3587           chans = mymalloc(sizeof(int) * chan_count);
3588           for (i = 0; i < chan_count; ++i)
3589             chans[i] = SvIV(ST(i+4));
3590           data = mymalloc(sizeof(i_sample_t) * (r-l) * chan_count); /* XXX: memleak? */
3591           count = i_gsamp(im, l, r, y, data, chans, chan_count);
3592           myfree(chans);
3593           if (GIMME_V == G_ARRAY) {
3594             EXTEND(SP, count);
3595             for (i = 0; i < count; ++i)
3596               PUSHs(sv_2mortal(newSViv(data[i])));
3597           }
3598           else {
3599             EXTEND(SP, 1);
3600             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3601           }
3602           myfree(data);
3603         }
3604         else {
3605           if (GIMME_V != G_ARRAY) {
3606             EXTEND(SP, 1);
3607             PUSHs(&PL_sv_undef);
3608           }
3609         }
3610
3611
3612 Imager::ImgRaw
3613 i_img_masked_new(targ, mask, x, y, w, h)
3614         Imager::ImgRaw targ
3615         int x
3616         int y
3617         int w
3618         int h
3619       PREINIT:
3620         i_img *mask;
3621       CODE:
3622         if (SvOK(ST(1))) {
3623           if (!sv_isobject(ST(1)) 
3624               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3625             croak("i_img_masked_new: parameter 2 must undef or an image");
3626           }
3627           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3628         }
3629         else
3630           mask = NULL;
3631         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3632       OUTPUT:
3633         RETVAL
3634
3635 int
3636 i_plin(im, l, y, ...)
3637         Imager::ImgRaw  im
3638         int     l
3639         int     y
3640       PREINIT:
3641         i_color *work;
3642         int i;
3643         STRLEN len;
3644         int count;
3645       CODE:
3646         if (items > 3) {
3647           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3648             /* supplied as a byte string */
3649             work = (i_color *)SvPV(ST(3), len);
3650             count = len / sizeof(i_color);
3651             if (count * sizeof(i_color) != len) {
3652               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3653             }
3654             RETVAL = i_plin(im, l, l+count, y, work);
3655           }
3656           else {
3657             work = mymalloc(sizeof(i_color) * (items-3));
3658             for (i=0; i < items-3; ++i) {
3659               if (sv_isobject(ST(i+3)) 
3660                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3661                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3662                 work[i] = *INT2PTR(i_color *, tmp);
3663               }
3664               else {
3665                 myfree(work);
3666                 croak("i_plin: pixels must be Imager::Color objects");
3667               }
3668             }
3669             RETVAL = i_plin(im, l, l+items-3, y, work);
3670             myfree(work);
3671           }
3672         }
3673         else {
3674           RETVAL = 0;
3675         }
3676       OUTPUT:
3677         RETVAL
3678
3679 int
3680 i_ppixf(im, x, y, cl)
3681         Imager::ImgRaw im
3682         int x
3683         int y
3684         Imager::Color::Float cl
3685
3686 void
3687 i_gsampf(im, l, r, y, ...)
3688         Imager::ImgRaw im
3689         int l
3690         int r
3691         int y
3692       PREINIT:
3693         int *chans;
3694         int chan_count;
3695         i_fsample_t *data;
3696         int count, i;
3697       PPCODE:
3698         if (items < 5)
3699           croak("No channel numbers supplied to g_sampf()");
3700         if (l < r) {
3701           chan_count = items - 4;
3702           chans = mymalloc(sizeof(int) * chan_count);
3703           for (i = 0; i < chan_count; ++i)
3704             chans[i] = SvIV(ST(i+4));
3705           data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count);
3706           count = i_gsampf(im, l, r, y, data, chans, chan_count);
3707           if (GIMME_V == G_ARRAY) {
3708             EXTEND(SP, count);
3709             for (i = 0; i < count; ++i)
3710               PUSHs(sv_2mortal(newSVnv(data[i])));
3711           }
3712           else {
3713             EXTEND(SP, 1);
3714             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3715           }
3716         }
3717         else {
3718           if (GIMME_V != G_ARRAY) {
3719             EXTEND(SP, 1);
3720             PUSHs(&PL_sv_undef);
3721           }
3722         }
3723
3724 int
3725 i_plinf(im, l, y, ...)
3726         Imager::ImgRaw  im
3727         int     l
3728         int     y
3729       PREINIT:
3730         i_fcolor *work;
3731         int i;
3732         STRLEN len;
3733         int count;
3734       CODE:
3735         if (items > 3) {
3736           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3737             /* supplied as a byte string */
3738             work = (i_fcolor *)SvPV(ST(3), len);
3739             count = len / sizeof(i_fcolor);
3740             if (count * sizeof(i_fcolor) != len) {
3741               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3742             }
3743             RETVAL = i_plinf(im, l, l+count, y, work);
3744           }
3745           else {
3746             work = mymalloc(sizeof(i_fcolor) * (items-3));
3747             for (i=0; i < items-3; ++i) {
3748               if (sv_isobject(ST(i+3)) 
3749                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3750                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3751                 work[i] = *INT2PTR(i_fcolor *, tmp);
3752               }
3753               else {
3754                 myfree(work);
3755                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3756               }
3757             }
3758             /**(char *)0 = 1;*/
3759             RETVAL = i_plinf(im, l, l+items-3, y, work);
3760             myfree(work);
3761           }
3762         }
3763         else {
3764           RETVAL = 0;
3765         }
3766       OUTPUT:
3767         RETVAL
3768
3769 SV *
3770 i_gpixf(im, x, y)
3771         Imager::ImgRaw im
3772         int x
3773         int y;
3774       PREINIT:
3775         i_fcolor *color;
3776       CODE:
3777         color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3778         if (i_gpixf(im, x, y, color) == 0) {
3779           RETVAL = NEWSV(0,0);
3780           sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
3781         }
3782         else {
3783           myfree(color);
3784           RETVAL = &PL_sv_undef;
3785         }
3786       OUTPUT:
3787         RETVAL
3788
3789 void
3790 i_glin(im, l, r, y)
3791         Imager::ImgRaw im
3792         int l
3793         int r
3794         int y
3795       PREINIT:
3796         i_color *vals;
3797         int count, i;
3798       PPCODE:
3799         if (l < r) {
3800           vals = mymalloc((r-l) * sizeof(i_color));
3801           count = i_glin(im, l, r, y, vals);
3802           if (GIMME_V == G_ARRAY) {
3803             EXTEND(SP, count);
3804             for (i = 0; i < count; ++i) {
3805               SV *sv;
3806               i_color *col = mymalloc(sizeof(i_color));
3807               *col = vals[i];
3808               sv = sv_newmortal();
3809               sv_setref_pv(sv, "Imager::Color", (void *)col);
3810               PUSHs(sv);
3811             }
3812           }
3813           else if (count) {
3814             EXTEND(SP, 1);
3815             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3816           }
3817           myfree(vals);
3818         }
3819
3820 void
3821 i_glinf(im, l, r, y)
3822         Imager::ImgRaw im
3823         int l
3824         int r
3825         int y
3826       PREINIT:
3827         i_fcolor *vals;
3828         int count, i;
3829       PPCODE:
3830         if (l < r) {
3831           vals = mymalloc((r-l) * sizeof(i_fcolor));
3832           count = i_glinf(im, l, r, y, vals);
3833           if (GIMME_V == G_ARRAY) {
3834             EXTEND(SP, count);
3835             for (i = 0; i < count; ++i) {
3836               SV *sv;
3837               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3838               *col = vals[i];
3839               sv = sv_newmortal();
3840               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3841               PUSHs(sv);
3842             }
3843           }
3844           else if (count) {
3845             EXTEND(SP, 1);
3846             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3847           }
3848           myfree(vals);
3849         }
3850
3851 Imager::ImgRaw
3852 i_img_16_new(x, y, ch)
3853         int x
3854         int y
3855         int ch
3856
3857 Imager::ImgRaw
3858 i_img_double_new(x, y, ch)
3859         int x
3860         int y
3861         int ch
3862
3863 undef_int
3864 i_tags_addn(im, name, code, idata)
3865         Imager::ImgRaw im
3866         int     code
3867         int     idata
3868       PREINIT:
3869         char *name;
3870         STRLEN len;
3871       CODE:
3872         if (SvOK(ST(1)))
3873           name = SvPV(ST(1), len);
3874         else
3875           name = NULL;
3876         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3877       OUTPUT:
3878         RETVAL
3879
3880 undef_int
3881 i_tags_add(im, name, code, data, idata)
3882         Imager::ImgRaw  im
3883         int code
3884         int idata
3885       PREINIT:
3886         char *name;
3887         char *data;
3888         STRLEN len;
3889       CODE:
3890         if (SvOK(ST(1)))
3891           name = SvPV(ST(1), len);
3892         else
3893           name = NULL;
3894         if (SvOK(ST(3)))
3895           data = SvPV(ST(3), len);
3896         else {
3897           data = NULL;
3898           len = 0;
3899         }
3900         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3901       OUTPUT:
3902         RETVAL
3903
3904 SV *
3905 i_tags_find(im, name, start)
3906         Imager::ImgRaw  im
3907         char *name
3908         int start
3909       PREINIT:
3910         int entry;
3911       CODE:
3912         if (i_tags_find(&im->tags, name, start, &entry)) {
3913           if (entry == 0)
3914             RETVAL = newSVpv("0 but true", 0);
3915           else
3916             RETVAL = newSViv(entry);
3917         } else {
3918           RETVAL = &PL_sv_undef;
3919         }
3920       OUTPUT:
3921         RETVAL
3922
3923 SV *
3924 i_tags_findn(im, code, start)
3925         Imager::ImgRaw  im
3926         int             code
3927         int             start
3928       PREINIT:
3929         int entry;
3930       CODE:
3931         if (i_tags_findn(&im->tags, code, start, &entry)) {
3932           if (entry == 0)
3933             RETVAL = newSVpv("0 but true", 0);
3934           else
3935             RETVAL = newSViv(entry);
3936         }
3937         else {
3938           RETVAL = &PL_sv_undef;
3939         }
3940       OUTPUT:
3941         RETVAL
3942
3943 int
3944 i_tags_delete(im, entry)
3945         Imager::ImgRaw  im
3946         int             entry
3947       CODE:
3948         RETVAL = i_tags_delete(&im->tags, entry);
3949       OUTPUT:
3950         RETVAL
3951
3952 int
3953 i_tags_delbyname(im, name)
3954         Imager::ImgRaw  im
3955         char *          name
3956       CODE:
3957         RETVAL = i_tags_delbyname(&im->tags, name);
3958       OUTPUT:
3959         RETVAL
3960
3961 int
3962 i_tags_delbycode(im, code)
3963         Imager::ImgRaw  im
3964         int             code
3965       CODE:
3966         RETVAL = i_tags_delbycode(&im->tags, code);
3967       OUTPUT:
3968         RETVAL
3969
3970 void
3971 i_tags_get(im, index)
3972         Imager::ImgRaw  im
3973         int             index
3974       PPCODE:
3975         if (index >= 0 && index < im->tags.count) {
3976           i_img_tag *entry = im->tags.tags + index;
3977           EXTEND(SP, 5);
3978         
3979           if (entry->name) {
3980             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3981           }
3982           else {
3983             PUSHs(sv_2mortal(newSViv(entry->code)));
3984           }
3985           if (entry->data) {
3986             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3987           }
3988           else {
3989             PUSHs(sv_2mortal(newSViv(entry->idata)));
3990           }
3991         }
3992
3993 void
3994 i_tags_get_string(im, what_sv)
3995         Imager::ImgRaw  im
3996         SV *what_sv
3997       PREINIT:
3998         char const *name = NULL;
3999         int code;
4000         char buffer[200];
4001       PPCODE:
4002         if (SvIOK(what_sv)) {
4003           code = SvIV(what_sv);
4004           name = NULL;
4005         }
4006         else {
4007           name = SvPV_nolen(what_sv);
4008           code = 0;
4009         }
4010         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
4011           EXTEND(SP, 1);
4012           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
4013         }
4014
4015 int
4016 i_tags_count(im)
4017         Imager::ImgRaw  im
4018       CODE:
4019         RETVAL = im->tags.count;
4020       OUTPUT:
4021         RETVAL
4022
4023 #ifdef HAVE_WIN32
4024
4025 void
4026 i_wf_bbox(face, size, text)
4027         char *face
4028         int size
4029         char *text
4030       PREINIT:
4031         int cords[BOUNDING_BOX_COUNT];
4032         int rc, i;
4033       PPCODE:
4034         if (rc = i_wf_bbox(face, size, text, strlen(text), cords)) {
4035           EXTEND(SP, rc);  
4036           for (i = 0; i < rc; ++i) 
4037             PUSHs(sv_2mortal(newSViv(cords[i])));
4038         }
4039
4040 undef_int
4041 i_wf_text(face, im, tx, ty, cl, size, text, align, aa)
4042         char *face
4043         Imager::ImgRaw im
4044         int tx
4045         int ty
4046         Imager::Color cl
4047         int size
4048         char *text
4049         int align
4050         int aa
4051       CODE:
4052         RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text), 
4053                            align, aa);
4054       OUTPUT:
4055         RETVAL
4056
4057 undef_int
4058 i_wf_cp(face, im, tx, ty, channel, size, text, align, aa)
4059         char *face
4060         Imager::ImgRaw im
4061         int tx
4062         int ty
4063         int channel
4064         int size
4065         char *text
4066         int align
4067         int aa
4068       CODE:
4069         RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text), 
4070                          align, aa);
4071       OUTPUT:
4072         RETVAL
4073
4074 undef_int
4075 i_wf_addfont(font)
4076         char *font
4077
4078 #endif
4079
4080 #ifdef HAVE_FT2
4081
4082 MODULE = Imager         PACKAGE = Imager::Font::FT2     PREFIX=FT2_
4083
4084 #define FT2_DESTROY(font) i_ft2_destroy(font)
4085
4086 void
4087 FT2_DESTROY(font)
4088         Imager::Font::FT2 font
4089
4090 MODULE = Imager         PACKAGE = Imager::Font::FreeType2 
4091
4092 Imager::Font::FT2
4093 i_ft2_new(name, index)
4094         char *name
4095         int index
4096
4097 undef_int
4098 i_ft2_setdpi(font, xdpi, ydpi)
4099         Imager::Font::FT2 font
4100         int xdpi
4101         int ydpi
4102
4103 void
4104 i_ft2_getdpi(font)
4105         Imager::Font::FT2 font
4106       PREINIT:
4107         int xdpi, ydpi;
4108       CODE:
4109         if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
4110           EXTEND(SP, 2);
4111           PUSHs(sv_2mortal(newSViv(xdpi)));
4112           PUSHs(sv_2mortal(newSViv(ydpi)));
4113         }
4114
4115 undef_int
4116 i_ft2_sethinting(font, hinting)
4117         Imager::Font::FT2 font
4118         int hinting
4119
4120 undef_int
4121 i_ft2_settransform(font, matrix)
4122         Imager::Font::FT2 font
4123       PREINIT:
4124         double matrix[6];
4125         int len;
4126         AV *av;
4127         SV *sv1;
4128         int i;
4129       CODE:
4130         if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4131           croak("i_ft2_settransform: parameter 2 must be an array ref\n");
4132         av=(AV*)SvRV(ST(1));
4133         len=av_len(av)+1;
4134         if (len > 6)
4135           len = 6;
4136         for (i = 0; i < len; ++i) {
4137           sv1=(*(av_fetch(av,i,0)));
4138           matrix[i] = SvNV(sv1);
4139         }
4140         for (; i < 6; ++i)
4141           matrix[i] = 0;
4142         RETVAL = i_ft2_settransform(font, matrix);
4143       OUTPUT:
4144         RETVAL
4145
4146 void
4147 i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
4148         Imager::Font::FT2 font
4149         double cheight
4150         double cwidth
4151         SV *text_sv
4152         int utf8
4153       PREINIT:
4154         int bbox[BOUNDING_BOX_COUNT];
4155         int i;
4156         char *text;
4157         STRLEN text_len;
4158         int rc;
4159       PPCODE:
4160         text = SvPV(text_sv, text_len);
4161 #ifdef SvUTF8
4162         if (SvUTF8(text_sv))
4163           utf8 = 1;
4164 #endif
4165         rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8);
4166         if (rc) {
4167           EXTEND(SP, rc);
4168           for (i = 0; i < rc; ++i)
4169             PUSHs(sv_2mortal(newSViv(bbox[i])));
4170         }
4171
4172 void
4173 i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
4174         Imager::Font::FT2 font
4175         double cheight
4176         double cwidth
4177         char *text
4178         int vlayout
4179         int utf8
4180       PREINIT:
4181         int bbox[8];
4182         int i;
4183       PPCODE:
4184 #ifdef SvUTF8
4185         if (SvUTF8(ST(3)))
4186           utf8 = 1;
4187 #endif
4188         if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
4189                          utf8, bbox)) {
4190           EXTEND(SP, 8);
4191           for (i = 0; i < 8; ++i)
4192             PUSHs(sv_2mortal(newSViv(bbox[i])));
4193         }
4194
4195 undef_int
4196 i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
4197         Imager::Font::FT2 font
4198         Imager::ImgRaw im
4199         int tx
4200         int ty
4201         Imager::Color cl
4202         double cheight
4203         double cwidth
4204         int align
4205         int aa
4206         int vlayout
4207         int utf8
4208       PREINIT:
4209         char *text;
4210         STRLEN len;
4211       CODE:
4212 #ifdef SvUTF8
4213         if (SvUTF8(ST(7))) {
4214           utf8 = 1;
4215         }
4216 #endif
4217         text = SvPV(ST(7), len);
4218         RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
4219                             len, align, aa, vlayout, utf8);
4220       OUTPUT:
4221         RETVAL
4222
4223 undef_int
4224 i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8)
4225         Imager::Font::FT2 font
4226         Imager::ImgRaw im
4227         int tx
4228         int ty
4229         int channel
4230         double cheight
4231         double cwidth
4232         char *text
4233         int align
4234         int aa
4235         int vlayout
4236         int utf8
4237       CODE:
4238 #ifdef SvUTF8
4239         if (SvUTF8(ST(7)))
4240           utf8 = 1;
4241 #endif
4242         RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
4243                           strlen(text), align, aa, vlayout, 1);
4244       OUTPUT:
4245         RETVAL
4246
4247 void
4248 ft2_transform_box(font, x0, x1, x2, x3)
4249         Imager::Font::FT2 font
4250         int x0
4251         int x1
4252         int x2
4253         int x3
4254       PREINIT:
4255         int box[4];
4256       PPCODE:
4257         box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
4258         ft2_transform_box(font, box);
4259           EXTEND(SP, 4);
4260           PUSHs(sv_2mortal(newSViv(box[0])));
4261           PUSHs(sv_2mortal(newSViv(box[1])));
4262           PUSHs(sv_2mortal(newSViv(box[2])));
4263           PUSHs(sv_2mortal(newSViv(box[3])));
4264
4265 void
4266 i_ft2_has_chars(handle, text_sv, utf8)
4267         Imager::Font::FT2 handle
4268         SV  *text_sv
4269         int utf8
4270       PREINIT:
4271         char *text;
4272         STRLEN len;
4273         char *work;
4274         int count;
4275         int i;
4276       PPCODE:
4277 #ifdef SvUTF8
4278         if (SvUTF8(text_sv))
4279           utf8 = 1;
4280 #endif
4281         text = SvPV(text_sv, len);
4282         work = mymalloc(len);
4283         count = i_ft2_has_chars(handle, text, len, utf8, work);
4284         if (GIMME_V == G_ARRAY) {
4285           EXTEND(SP, count);
4286           for (i = 0; i < count; ++i) {
4287             PUSHs(sv_2mortal(newSViv(work[i])));
4288           }
4289         }
4290         else {
4291           EXTEND(SP, 1);
4292           PUSHs(sv_2mortal(newSVpv(work, count)));
4293         }
4294         myfree(work);
4295
4296 void
4297 i_ft2_face_name(handle)
4298         Imager::Font::FT2 handle
4299       PREINIT:
4300         char name[255];
4301         int len;
4302       PPCODE:
4303         len = i_ft2_face_name(handle, name, sizeof(name));
4304         if (len) {
4305           EXTEND(SP, 1);
4306           PUSHs(sv_2mortal(newSVpv(name, 0)));
4307         }
4308
4309 undef_int
4310 i_ft2_can_face_name()
4311
4312 void
4313 i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
4314         Imager::Font::FT2 handle
4315         SV *text_sv
4316         int utf8
4317         int reliable_only
4318       PREINIT:
4319         char const *text;
4320         STRLEN work_len;
4321         int len;
4322         int outsize;
4323         char name[255];
4324       PPCODE:
4325 #ifdef SvUTF8
4326         if (SvUTF8(text_sv))
4327           utf8 = 1;
4328 #endif
4329         text = SvPV(text_sv, work_len);
4330         len = work_len;
4331         while (len) {
4332           unsigned long ch;
4333           if (utf8) {
4334             ch = i_utf8_advance(&text, &len);
4335             if (ch == ~0UL) {
4336               i_push_error(0, "invalid UTF8 character");
4337               break;
4338             }
4339           }
4340           else {
4341             ch = *text++;
4342             --len;
4343           }
4344           EXTEND(SP, 1);
4345           if (outsize = i_ft2_glyph_name(handle, ch, name, sizeof(name), 
4346                                          reliable_only)) {
4347             PUSHs(sv_2mortal(newSVpv(name, 0)));
4348           }
4349           else {
4350             PUSHs(&PL_sv_undef);
4351           } 
4352         }
4353
4354 int
4355 i_ft2_can_do_glyph_names()
4356
4357 int
4358 i_ft2_face_has_glyph_names(handle)
4359         Imager::Font::FT2 handle
4360
4361 int
4362 i_ft2_is_multiple_master(handle)
4363         Imager::Font::FT2 handle
4364
4365 void
4366 i_ft2_get_multiple_masters(handle)
4367         Imager::Font::FT2 handle
4368       PREINIT:
4369         i_font_mm mm;
4370         int i;
4371       PPCODE:
4372         if (i_ft2_get_multiple_masters(handle, &mm)) {
4373           EXTEND(SP, 2+mm.num_axis);
4374           PUSHs(sv_2mortal(newSViv(mm.num_axis)));
4375           PUSHs(sv_2mortal(newSViv(mm.num_designs)));
4376           for (i = 0; i < mm.num_axis; ++i) {
4377             AV *av = newAV();
4378             SV *sv;
4379             av_extend(av, 3);
4380             sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name));
4381             SvREFCNT_inc(sv);
4382             av_store(av, 0, sv);
4383             sv = newSViv(mm.axis[i].minimum);
4384             SvREFCNT_inc(sv);
4385             av_store(av, 1, sv);
4386             sv = newSViv(mm.axis[i].maximum);
4387             SvREFCNT_inc(sv);
4388             av_store(av, 2, sv);
4389             PUSHs(newRV_noinc((SV *)av));
4390           }
4391         }
4392
4393 undef_int
4394 i_ft2_set_mm_coords(handle, ...)
4395         Imager::Font::FT2 handle
4396       PROTOTYPE: DISABLE
4397       PREINIT:
4398         long *coords;
4399         int ix_coords, i;
4400       CODE:
4401         /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so
4402            transfer the array manually */
4403         ix_coords = items-1;
4404         coords = mymalloc(sizeof(long) * ix_coords);
4405         for (i = 0; i < ix_coords; ++i) {
4406           coords[i] = (long)SvIV(ST(1+i));
4407         }
4408         RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords);
4409         myfree(coords);
4410       OUTPUT:
4411         RETVAL
4412
4413 #endif
4414
4415 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
4416
4417 void
4418 IFILL_DESTROY(fill)
4419         Imager::FillHandle fill
4420
4421 MODULE = Imager         PACKAGE = Imager
4422
4423 Imager::FillHandle
4424 i_new_fill_solid(cl, combine)
4425         Imager::Color cl
4426         int combine
4427
4428 Imager::FillHandle
4429 i_new_fill_solidf(cl, combine)
4430         Imager::Color::Float cl
4431         int combine
4432
4433 Imager::FillHandle
4434 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
4435         Imager::Color fg
4436         Imager::Color bg
4437         int combine
4438         int hatch
4439         int dx
4440         int dy
4441       PREINIT:
4442         unsigned char *cust_hatch;
4443         STRLEN len;
4444       CODE:
4445         if (SvOK(ST(4))) {
4446           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4447         }
4448         else
4449           cust_hatch = NULL;
4450         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
4451       OUTPUT:
4452         RETVAL
4453
4454 Imager::FillHandle
4455 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
4456         Imager::Color::Float fg
4457         Imager::Color::Float bg
4458         int combine
4459         int hatch
4460         int dx
4461         int dy
4462       PREINIT:
4463         unsigned char *cust_hatch;
4464         STRLEN len;
4465       CODE:
4466         if (SvOK(ST(4))) {
4467           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4468         }
4469         else
4470           cust_hatch = NULL;
4471         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
4472       OUTPUT:
4473         RETVAL
4474
4475 Imager::FillHandle
4476 i_new_fill_image(src, matrix, xoff, yoff, combine)
4477         Imager::ImgRaw src
4478         int xoff
4479         int yoff
4480         int combine
4481       PREINIT:
4482         double matrix[9];
4483         double *matrixp;
4484         AV *av;
4485         IV len;
4486         SV *sv1;
4487         int i;
4488       CODE:
4489         if (!SvOK(ST(1))) {
4490           matrixp = NULL;
4491         }
4492         else {
4493           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4494             croak("i_new_fill_image: parameter must be an arrayref");
4495           av=(AV*)SvRV(ST(1));
4496           len=av_len(av)+1;
4497           if (len > 9)
4498             len = 9;
4499           for (i = 0; i < len; ++i) {
4500             sv1=(*(av_fetch(av,i,0)));
4501             matrix[i] = SvNV(sv1);
4502           }
4503           for (; i < 9; ++i)
4504             matrix[i] = 0;
4505           matrixp = matrix;
4506         }
4507         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4508       OUTPUT:
4509         RETVAL
4510
4511 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
4512
4513 # this class is only exposed for testing
4514
4515 int
4516 i_int_hlines_testing()
4517
4518 #if i_int_hlines_testing()
4519
4520 Imager::Internal::Hlines
4521 i_int_hlines_new(start_y, count_y, start_x, count_x)
4522         int start_y
4523         int count_y
4524         int start_x
4525         int count_x
4526
4527 Imager::Internal::Hlines
4528 i_int_hlines_new_img(im)
4529         Imager::ImgRaw im
4530
4531 void
4532 i_int_hlines_add(hlines, y, minx, width)
4533         Imager::Internal::Hlines hlines
4534         int y
4535         int minx
4536         int width
4537
4538 void
4539 i_int_hlines_DESTROY(hlines)
4540         Imager::Internal::Hlines hlines
4541
4542 SV *
4543 i_int_hlines_dump(hlines)
4544         Imager::Internal::Hlines hlines
4545
4546 #endif
4547
4548 BOOT:
4549         PERL_SET_GLOBAL_CALLBACKS;