io_glue_destroy() now uses an extra callback to handle type specific
[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 i_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 /* trying to use more C style names, map them here */
883 #define io_glue_DESTROY(ig) io_glue_destroy(ig)
884
885 MODULE = Imager         PACKAGE = Imager::Color PREFIX = ICL_
886
887 Imager::Color
888 ICL_new_internal(r,g,b,a)
889                unsigned char     r
890                unsigned char     g
891                unsigned char     b
892                unsigned char     a
893
894 void
895 ICL_DESTROY(cl)
896                Imager::Color    cl
897
898
899 void
900 ICL_set_internal(cl,r,g,b,a)
901                Imager::Color    cl
902                unsigned char     r
903                unsigned char     g
904                unsigned char     b
905                unsigned char     a
906            PPCODE:
907                ICL_set_internal(cl, r, g, b, a);
908                EXTEND(SP, 1);
909                PUSHs(ST(0));
910
911 void
912 ICL_info(cl)
913                Imager::Color    cl
914
915
916 void
917 ICL_rgba(cl)
918               Imager::Color     cl
919             PPCODE:
920                 EXTEND(SP, 4);
921                 PUSHs(sv_2mortal(newSVnv(cl->rgba.r)));
922                 PUSHs(sv_2mortal(newSVnv(cl->rgba.g)));
923                 PUSHs(sv_2mortal(newSVnv(cl->rgba.b)));
924                 PUSHs(sv_2mortal(newSVnv(cl->rgba.a)));
925
926 Imager::Color
927 i_hsv_to_rgb(c)
928         Imager::Color c
929       CODE:
930         RETVAL = mymalloc(sizeof(i_color));
931         *RETVAL = *c;
932         i_hsv_to_rgb(RETVAL);
933       OUTPUT:
934         RETVAL
935         
936 Imager::Color
937 i_rgb_to_hsv(c)
938         Imager::Color c
939       CODE:
940         RETVAL = mymalloc(sizeof(i_color));
941         *RETVAL = *c;
942         i_rgb_to_hsv(RETVAL);
943       OUTPUT:
944         RETVAL
945         
946
947
948 MODULE = Imager        PACKAGE = Imager::Color::Float  PREFIX=ICLF_
949
950 Imager::Color::Float
951 ICLF_new_internal(r, g, b, a)
952         double r
953         double g
954         double b
955         double a
956
957 void
958 ICLF_DESTROY(cl)
959         Imager::Color::Float    cl
960
961 void
962 ICLF_rgba(cl)
963         Imager::Color::Float    cl
964       PREINIT:
965         int ch;
966       PPCODE:
967         EXTEND(SP, MAXCHANNELS);
968         for (ch = 0; ch < MAXCHANNELS; ++ch) {
969         /* printf("%d: %g\n", ch, cl->channel[ch]); */
970           PUSHs(sv_2mortal(newSVnv(cl->channel[ch])));
971         }
972
973 void
974 ICLF_set_internal(cl,r,g,b,a)
975         Imager::Color::Float    cl
976         double     r
977         double     g
978         double     b
979         double     a
980       PPCODE:
981         cl->rgba.r = r;
982         cl->rgba.g = g;
983         cl->rgba.b = b;
984         cl->rgba.a = a;                
985         EXTEND(SP, 1);
986         PUSHs(ST(0));
987
988 Imager::Color::Float
989 i_hsv_to_rgb(c)
990         Imager::Color::Float c
991       CODE:
992         RETVAL = mymalloc(sizeof(i_fcolor));
993         *RETVAL = *c;
994         i_hsv_to_rgbf(RETVAL);
995       OUTPUT:
996         RETVAL
997         
998 Imager::Color::Float
999 i_rgb_to_hsv(c)
1000         Imager::Color::Float c
1001       CODE:
1002         RETVAL = mymalloc(sizeof(i_fcolor));
1003         *RETVAL = *c;
1004         i_rgb_to_hsvf(RETVAL);
1005       OUTPUT:
1006         RETVAL
1007
1008 MODULE = Imager         PACKAGE = Imager::ImgRaw        PREFIX = IIM_
1009
1010 Imager::ImgRaw
1011 IIM_new(x,y,ch)
1012                int     x
1013                int     y
1014                int     ch
1015
1016 void
1017 IIM_DESTROY(im)
1018                Imager::ImgRaw    im
1019
1020
1021
1022 MODULE = Imager         PACKAGE = Imager
1023
1024 PROTOTYPES: ENABLE
1025
1026
1027 Imager::IO
1028 io_new_fd(fd)
1029                          int     fd
1030
1031 Imager::IO
1032 io_new_bufchain()
1033
1034
1035 Imager::IO
1036 io_new_buffer(data)
1037           char   *data
1038         PREINIT:
1039           size_t length;
1040         CODE:
1041           SvPV(ST(0), length);
1042           SvREFCNT_inc(ST(0));
1043           RETVAL = io_new_buffer(data, length, my_SvREFCNT_dec, ST(0));
1044         OUTPUT:
1045           RETVAL
1046
1047 Imager::IO
1048 io_new_cb(writecb, readcb, seekcb, closecb, maxwrite = CBDATA_BUFSIZE)
1049         SV *writecb;
1050         SV *readcb;
1051         SV *seekcb;
1052         SV *closecb;
1053         int maxwrite;
1054       PREINIT:
1055         struct cbdata *cbd;
1056       CODE:
1057         cbd = mymalloc(sizeof(struct cbdata));
1058         SvREFCNT_inc(writecb);
1059         cbd->writecb = writecb;
1060         SvREFCNT_inc(readcb);
1061         cbd->readcb = readcb;
1062         SvREFCNT_inc(seekcb);
1063         cbd->seekcb = seekcb;
1064         SvREFCNT_inc(closecb);
1065         cbd->closecb = closecb;
1066         cbd->reading = cbd->writing = cbd->where = cbd->used = 0;
1067         if (maxwrite > CBDATA_BUFSIZE)
1068           maxwrite = CBDATA_BUFSIZE;
1069         cbd->maxlength = maxwrite;
1070         RETVAL = io_new_cb(cbd, io_reader, io_writer, io_seeker, io_closer, 
1071                            io_destroyer);
1072       OUTPUT:
1073         RETVAL
1074
1075 void
1076 io_slurp(ig)
1077         Imager::IO     ig
1078              PREINIT:
1079               unsigned char*    data;
1080               size_t    tlength;
1081              PPCODE:
1082               data    = NULL;
1083               tlength = io_slurp(ig, &data);
1084               EXTEND(SP,1);
1085               PUSHs(sv_2mortal(newSVpv((char *)data,tlength)));
1086               myfree(data);
1087
1088
1089 undef_int
1090 i_set_image_file_limits(width, height, bytes)
1091         int width
1092         int height
1093         int bytes
1094
1095 void
1096 i_get_image_file_limits()
1097       PREINIT:
1098         int width, height, bytes;
1099       PPCODE:
1100         if (i_get_image_file_limits(&width, &height, &bytes)) {
1101           EXTEND(SP, 3);
1102           PUSHs(sv_2mortal(newSViv(width)));
1103           PUSHs(sv_2mortal(newSViv(height)));
1104           PUSHs(sv_2mortal(newSViv(bytes)));
1105         }
1106
1107 MODULE = Imager         PACKAGE = Imager::IO    PREFIX = io_glue_
1108
1109 void
1110 io_glue_DESTROY(ig)
1111         Imager::IO     ig
1112
1113
1114 MODULE = Imager         PACKAGE = Imager
1115
1116 PROTOTYPES: ENABLE
1117
1118
1119
1120 void
1121 i_list_formats()
1122              PREINIT:
1123               char*    item;
1124                int     i;
1125              PPCODE:
1126                i=0;
1127                while( (item=i_format_list[i++]) != NULL ) {
1128                       EXTEND(SP, 1);
1129                       PUSHs(sv_2mortal(newSVpv(item,0)));
1130                }
1131
1132 undef_int
1133 i_has_format(frmt)
1134               char*    frmt
1135
1136 Imager::ImgRaw
1137 i_img_new()
1138
1139 Imager::ImgRaw
1140 i_img_empty(im,x,y)
1141     Imager::ImgRaw     im
1142                int     x
1143                int     y
1144
1145 Imager::ImgRaw
1146 i_img_empty_ch(im,x,y,ch)
1147     Imager::ImgRaw     im
1148                int     x
1149                int     y
1150                int     ch
1151
1152 Imager::ImgRaw
1153 i_sametype(im, x, y)
1154     Imager::ImgRaw im
1155                int x
1156                int y
1157
1158 Imager::ImgRaw
1159 i_sametype_chans(im, x, y, channels)
1160     Imager::ImgRaw im
1161                int x
1162                int y
1163                int channels
1164
1165 void
1166 i_init_log(name,level)
1167               char*    name
1168                int     level
1169
1170 void
1171 i_log_entry(string,level)
1172               char*    string
1173                int     level
1174
1175
1176 void
1177 i_img_exorcise(im)
1178     Imager::ImgRaw     im
1179
1180 void
1181 i_img_destroy(im)
1182     Imager::ImgRaw     im
1183
1184 void
1185 i_img_info(im)
1186     Imager::ImgRaw     im
1187              PREINIT:
1188                int     info[4];
1189              PPCODE:
1190                i_img_info(im,info);
1191                EXTEND(SP, 4);
1192                PUSHs(sv_2mortal(newSViv(info[0])));
1193                PUSHs(sv_2mortal(newSViv(info[1])));
1194                PUSHs(sv_2mortal(newSViv(info[2])));
1195                PUSHs(sv_2mortal(newSViv(info[3])));
1196
1197
1198
1199
1200 void
1201 i_img_setmask(im,ch_mask)
1202     Imager::ImgRaw     im
1203                int     ch_mask
1204
1205 int
1206 i_img_getmask(im)
1207     Imager::ImgRaw     im
1208
1209 int
1210 i_img_getchannels(im)
1211     Imager::ImgRaw     im
1212
1213 void
1214 i_img_getdata(im)
1215     Imager::ImgRaw     im
1216              PPCODE:
1217                EXTEND(SP, 1);
1218                PUSHs(im->idata ? 
1219                      sv_2mortal(newSVpv((char *)im->idata, im->bytes)) 
1220                      : &PL_sv_undef);
1221
1222
1223 void
1224 i_line(im,x1,y1,x2,y2,val,endp)
1225     Imager::ImgRaw     im
1226                int     x1
1227                int     y1
1228                int     x2
1229                int     y2
1230      Imager::Color     val
1231                int     endp
1232
1233 void
1234 i_line_aa(im,x1,y1,x2,y2,val,endp)
1235     Imager::ImgRaw     im
1236                int     x1
1237                int     y1
1238                int     x2
1239                int     y2
1240      Imager::Color     val
1241                int     endp
1242
1243 void
1244 i_box(im,x1,y1,x2,y2,val)
1245     Imager::ImgRaw     im
1246                int     x1
1247                int     y1
1248                int     x2
1249                int     y2
1250      Imager::Color     val
1251
1252 void
1253 i_box_filled(im,x1,y1,x2,y2,val)
1254     Imager::ImgRaw     im
1255                int     x1
1256                int     y1
1257                int     x2
1258                int     y2
1259            Imager::Color    val
1260
1261 void
1262 i_box_cfill(im,x1,y1,x2,y2,fill)
1263     Imager::ImgRaw     im
1264                int     x1
1265                int     y1
1266                int     x2
1267                int     y2
1268            Imager::FillHandle    fill
1269
1270 void
1271 i_arc(im,x,y,rad,d1,d2,val)
1272     Imager::ImgRaw     im
1273                int     x
1274                int     y
1275              float     rad
1276              float     d1
1277              float     d2
1278            Imager::Color    val
1279
1280 void
1281 i_arc_aa(im,x,y,rad,d1,d2,val)
1282     Imager::ImgRaw     im
1283             double     x
1284             double     y
1285             double     rad
1286             double     d1
1287             double     d2
1288            Imager::Color    val
1289
1290 void
1291 i_arc_cfill(im,x,y,rad,d1,d2,fill)
1292     Imager::ImgRaw     im
1293                int     x
1294                int     y
1295              float     rad
1296              float     d1
1297              float     d2
1298            Imager::FillHandle    fill
1299
1300 void
1301 i_arc_aa_cfill(im,x,y,rad,d1,d2,fill)
1302     Imager::ImgRaw     im
1303             double     x
1304             double     y
1305             double     rad
1306             double     d1
1307             double     d2
1308            Imager::FillHandle   fill
1309
1310
1311 void
1312 i_circle_aa(im,x,y,rad,val)
1313     Imager::ImgRaw     im
1314              float     x
1315              float     y
1316              float     rad
1317            Imager::Color    val
1318
1319
1320
1321 void
1322 i_bezier_multi(im,xc,yc,val)
1323     Imager::ImgRaw     im
1324              Imager::Color  val
1325              PREINIT:
1326              double   *x,*y;
1327              int       len;
1328              AV       *av1;
1329              AV       *av2;
1330              SV       *sv1;
1331              SV       *sv2;
1332              int i;
1333              PPCODE:
1334              ICL_info(val);
1335              if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
1336              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
1337              if (!SvROK(ST(2))) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
1338              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
1339              av1=(AV*)SvRV(ST(1));
1340              av2=(AV*)SvRV(ST(2));
1341              if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
1342              len=av_len(av1)+1;
1343              x=mymalloc( len*sizeof(double) );
1344              y=mymalloc( len*sizeof(double) );
1345              for(i=0;i<len;i++) {
1346                sv1=(*(av_fetch(av1,i,0)));
1347                sv2=(*(av_fetch(av2,i,0)));
1348                x[i]=(double)SvNV(sv1);
1349                y[i]=(double)SvNV(sv2);
1350              }
1351              i_bezier_multi(im,len,x,y,val);
1352              myfree(x);
1353              myfree(y);
1354
1355
1356 void
1357 i_poly_aa(im,xc,yc,val)
1358     Imager::ImgRaw     im
1359              Imager::Color  val
1360              PREINIT:
1361              double   *x,*y;
1362              int       len;
1363              AV       *av1;
1364              AV       *av2;
1365              SV       *sv1;
1366              SV       *sv2;
1367              int i;
1368              PPCODE:
1369              ICL_info(val);
1370              if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1371              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1372              if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1373              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
1374              av1=(AV*)SvRV(ST(1));
1375              av2=(AV*)SvRV(ST(2));
1376              if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_poly_aa must be equal length\n");
1377              len=av_len(av1)+1;
1378              x=mymalloc( len*sizeof(double) );
1379              y=mymalloc( len*sizeof(double) );
1380              for(i=0;i<len;i++) {
1381                sv1=(*(av_fetch(av1,i,0)));
1382                sv2=(*(av_fetch(av2,i,0)));
1383                x[i]=(double)SvNV(sv1);
1384                y[i]=(double)SvNV(sv2);
1385              }
1386              i_poly_aa(im,len,x,y,val);
1387              myfree(x);
1388              myfree(y);
1389
1390 void
1391 i_poly_aa_cfill(im,xc,yc,fill)
1392     Imager::ImgRaw     im
1393      Imager::FillHandle     fill
1394              PREINIT:
1395              double   *x,*y;
1396              int       len;
1397              AV       *av1;
1398              AV       *av2;
1399              SV       *sv1;
1400              SV       *sv2;
1401              int i;
1402              PPCODE:
1403              if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1404              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1405              if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1406              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
1407              av1=(AV*)SvRV(ST(1));
1408              av2=(AV*)SvRV(ST(2));
1409              if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n");
1410              len=av_len(av1)+1;
1411              x=mymalloc( len*sizeof(double) );
1412              y=mymalloc( len*sizeof(double) );
1413              for(i=0;i<len;i++) {
1414                sv1=(*(av_fetch(av1,i,0)));
1415                sv2=(*(av_fetch(av2,i,0)));
1416                x[i]=(double)SvNV(sv1);
1417                y[i]=(double)SvNV(sv2);
1418              }
1419              i_poly_aa_cfill(im,len,x,y,fill);
1420              myfree(x);
1421              myfree(y);
1422
1423
1424
1425 undef_int
1426 i_flood_fill(im,seedx,seedy,dcol)
1427     Imager::ImgRaw     im
1428                int     seedx
1429                int     seedy
1430      Imager::Color     dcol
1431
1432 undef_int
1433 i_flood_cfill(im,seedx,seedy,fill)
1434     Imager::ImgRaw     im
1435                int     seedx
1436                int     seedy
1437      Imager::FillHandle     fill
1438
1439
1440 void
1441 i_copyto(im,src,x1,y1,x2,y2,tx,ty)
1442     Imager::ImgRaw     im
1443     Imager::ImgRaw     src
1444                int     x1
1445                int     y1
1446                int     x2
1447                int     y2
1448                int     tx
1449                int     ty
1450
1451
1452 void
1453 i_copyto_trans(im,src,x1,y1,x2,y2,tx,ty,trans)
1454     Imager::ImgRaw     im
1455     Imager::ImgRaw     src
1456                int     x1
1457                int     y1
1458                int     x2
1459                int     y2
1460                int     tx
1461                int     ty
1462      Imager::Color     trans
1463
1464 Imager::ImgRaw
1465 i_copy(src)
1466     Imager::ImgRaw     src
1467
1468
1469 undef_int
1470 i_rubthru(im,src,tx,ty,src_minx,src_miny,src_maxx,src_maxy)
1471     Imager::ImgRaw     im
1472     Imager::ImgRaw     src
1473                int     tx
1474                int     ty
1475                int     src_minx
1476                int     src_miny
1477                int     src_maxx
1478                int     src_maxy
1479
1480
1481 undef_int
1482 i_flipxy(im, direction)
1483     Imager::ImgRaw     im
1484                int     direction
1485
1486 Imager::ImgRaw
1487 i_rotate90(im, degrees)
1488     Imager::ImgRaw      im
1489                int      degrees
1490
1491 Imager::ImgRaw
1492 i_rotate_exact(im, amount, ...)
1493     Imager::ImgRaw      im
1494             double      amount
1495       PREINIT:
1496         i_color *backp = NULL;
1497         i_fcolor *fbackp = NULL;
1498         int i;
1499         SV * sv1;
1500       CODE:
1501         /* extract the bg colors if any */
1502         /* yes, this is kind of strange */
1503         for (i = 2; i < items; ++i) {
1504           sv1 = ST(i);
1505           if (sv_derived_from(sv1, "Imager::Color")) {
1506             IV tmp = SvIV((SV*)SvRV(sv1));
1507             backp = INT2PTR(i_color *, tmp);
1508           }
1509           else if (sv_derived_from(sv1, "Imager::Color::Float")) {
1510             IV tmp = SvIV((SV*)SvRV(sv1));
1511             fbackp = INT2PTR(i_fcolor *, tmp);
1512           }
1513         }
1514         RETVAL = i_rotate_exact_bg(im, amount, backp, fbackp);
1515       OUTPUT:
1516         RETVAL
1517
1518 Imager::ImgRaw
1519 i_matrix_transform(im, xsize, ysize, matrix, ...)
1520     Imager::ImgRaw      im
1521                int      xsize
1522                int      ysize
1523       PREINIT:
1524         double matrix[9];
1525         AV *av;
1526         IV len;
1527         SV *sv1;
1528         int i;
1529         i_color *backp = NULL;
1530         i_fcolor *fbackp = NULL;
1531       CODE:
1532         if (!SvROK(ST(3)) || SvTYPE(SvRV(ST(3))) != SVt_PVAV)
1533           croak("i_matrix_transform: parameter 4 must be an array ref\n");
1534         av=(AV*)SvRV(ST(3));
1535         len=av_len(av)+1;
1536         if (len > 9)
1537           len = 9;
1538         for (i = 0; i < len; ++i) {
1539           sv1=(*(av_fetch(av,i,0)));
1540           matrix[i] = SvNV(sv1);
1541         }
1542         for (; i < 9; ++i)
1543           matrix[i] = 0;
1544         /* extract the bg colors if any */
1545         /* yes, this is kind of strange */
1546         for (i = 4; i < items; ++i) {
1547           sv1 = ST(i);
1548           if (sv_derived_from(sv1, "Imager::Color")) {
1549             IV tmp = SvIV((SV*)SvRV(sv1));
1550             backp = INT2PTR(i_color *, tmp);
1551           }
1552           else if (sv_derived_from(sv1, "Imager::Color::Float")) {
1553             IV tmp = SvIV((SV*)SvRV(sv1));
1554             fbackp = INT2PTR(i_fcolor *, tmp);
1555           }
1556         }
1557         RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp);
1558       OUTPUT:
1559         RETVAL
1560
1561 void
1562 i_gaussian(im,stdev)
1563     Imager::ImgRaw     im
1564              float     stdev
1565
1566 void
1567 i_unsharp_mask(im,stdev,scale)
1568     Imager::ImgRaw     im
1569              float     stdev
1570              double    scale
1571
1572 void
1573 i_conv(im,pcoef)
1574     Imager::ImgRaw     im
1575              PREINIT:
1576              float*    coeff;
1577              int     len;
1578              AV* av;
1579              SV* sv1;
1580              int i;
1581              PPCODE:
1582              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
1583              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
1584              av=(AV*)SvRV(ST(1));
1585              len=av_len(av)+1;
1586              coeff=mymalloc( len*sizeof(float) );
1587              for(i=0;i<len;i++) {
1588                sv1=(*(av_fetch(av,i,0)));
1589                coeff[i]=(float)SvNV(sv1);
1590              }
1591              i_conv(im,coeff,len);
1592              myfree(coeff);
1593
1594 undef_int
1595 i_convert(im, src, coeff)
1596     Imager::ImgRaw     im
1597     Imager::ImgRaw     src
1598         PREINIT:
1599           float *coeff;
1600           int outchan;
1601           int inchan;
1602           AV *avmain;
1603           SV **temp;
1604           AV *avsub;
1605           int len;
1606           int i, j;
1607         CODE:
1608           if (!SvROK(ST(2)) || SvTYPE(SvRV(ST(2))) != SVt_PVAV)
1609             croak("i_convert: parameter 3 must be an arrayref\n");
1610           avmain = (AV*)SvRV(ST(2));
1611           outchan = av_len(avmain)+1;
1612           /* find the biggest */
1613           inchan = 0;
1614           for (j=0; j < outchan; ++j) {
1615             temp = av_fetch(avmain, j, 0);
1616             if (temp && SvROK(*temp) && SvTYPE(SvRV(*temp)) == SVt_PVAV) {
1617               avsub = (AV*)SvRV(*temp);
1618               len = av_len(avsub)+1;
1619               if (len > inchan)
1620                 inchan = len;
1621             }
1622           }
1623           coeff = mymalloc(sizeof(float) * outchan * inchan);
1624           for (j = 0; j < outchan; ++j) {
1625             avsub = (AV*)SvRV(*av_fetch(avmain, j, 0));
1626             len = av_len(avsub)+1;
1627             for (i = 0; i < len; ++i) {
1628               temp = av_fetch(avsub, i, 0);
1629               if (temp)
1630                 coeff[i+j*inchan] = SvNV(*temp);
1631               else
1632                 coeff[i+j*inchan] = 0;
1633             }
1634             while (i < inchan)
1635               coeff[i++ + j*inchan] = 0;
1636           }
1637           RETVAL = i_convert(im, src, coeff, outchan, inchan);
1638           myfree(coeff);
1639         OUTPUT:
1640           RETVAL
1641
1642
1643 void
1644 i_map(im, pmaps)
1645     Imager::ImgRaw     im
1646         PREINIT:
1647           unsigned int mask = 0;
1648           AV *avmain;
1649           AV *avsub;
1650           SV **temp;
1651           int len;
1652           int i, j;
1653           unsigned char (*maps)[256];
1654         CODE:
1655           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
1656             croak("i_map: parameter 2 must be an arrayref\n");
1657           avmain = (AV*)SvRV(ST(1));
1658           len = av_len(avmain)+1;
1659           if (im->channels < len) len = im->channels;
1660
1661           maps = mymalloc( len * sizeof(unsigned char [256]) );
1662
1663           for (j=0; j<len ; j++) {
1664             temp = av_fetch(avmain, j, 0);
1665             if (temp && SvROK(*temp) && (SvTYPE(SvRV(*temp)) == SVt_PVAV) ) {
1666               avsub = (AV*)SvRV(*temp);
1667               if(av_len(avsub) != 255) continue;
1668               mask |= 1<<j;
1669               for (i=0; i<256 ; i++) {
1670                 int val;
1671                 temp = av_fetch(avsub, i, 0);
1672                 val = temp ? SvIV(*temp) : 0;
1673                 if (val<0) val = 0;
1674                 if (val>255) val = 255;
1675                 maps[j][i] = val;
1676               }
1677             }
1678           }
1679           i_map(im, maps, mask);
1680           myfree(maps);
1681
1682
1683
1684 float
1685 i_img_diff(im1,im2)
1686     Imager::ImgRaw     im1
1687     Imager::ImgRaw     im2
1688
1689
1690
1691 undef_int         
1692 i_init_fonts(t1log=0)
1693     int t1log
1694
1695 #ifdef HAVE_LIBT1
1696
1697 void
1698 i_t1_set_aa(st)
1699                int     st
1700
1701 int
1702 i_t1_new(pfb,afm)
1703               char*    pfb
1704               char*    afm
1705
1706 int
1707 i_t1_destroy(font_id)
1708                int     font_id
1709
1710
1711 undef_int
1712 i_t1_cp(im,xb,yb,channel,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
1713     Imager::ImgRaw     im
1714                int     xb
1715                int     yb
1716                int     channel
1717                int     fontnum
1718              float     points
1719                 SV*    str_sv
1720                int     align
1721                int     utf8
1722               char*    flags
1723              PREINIT:
1724                char *str;
1725                STRLEN len;
1726              CODE:
1727 #ifdef SvUTF8
1728                if (SvUTF8(str_sv))
1729                  utf8 = 1;
1730 #endif
1731                str = SvPV(str_sv, len);
1732                RETVAL = i_t1_cp(im, xb,yb,channel,fontnum,points,str,len,align,
1733                                   utf8,flags);
1734            OUTPUT:
1735              RETVAL
1736
1737
1738 void
1739 i_t1_bbox(fontnum,point,str_sv,len_ignored,utf8=0,flags="")
1740                int     fontnum
1741              float     point
1742                 SV*    str_sv
1743                int     utf8
1744               char*    flags
1745              PREINIT:
1746                char *str;
1747                STRLEN len;
1748                int     cords[BOUNDING_BOX_COUNT];
1749                int i;
1750                int rc;
1751              PPCODE:
1752 #ifdef SvUTF8
1753                if (SvUTF8(str_sv))
1754                  utf8 = 1;
1755 #endif
1756                str = SvPV(str_sv, len);
1757                rc = i_t1_bbox(fontnum,point,str,len,cords,utf8,flags);
1758                if (rc > 0) {
1759                  EXTEND(SP, rc);
1760                  for (i = 0; i < rc; ++i)
1761                    PUSHs(sv_2mortal(newSViv(cords[i])));
1762                }
1763
1764
1765
1766 undef_int
1767 i_t1_text(im,xb,yb,cl,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
1768     Imager::ImgRaw     im
1769                int     xb
1770                int     yb
1771      Imager::Color    cl
1772                int     fontnum
1773              float     points
1774                 SV*    str_sv
1775                int     align
1776                int     utf8
1777               char*    flags
1778              PREINIT:
1779                char *str;
1780                STRLEN len;
1781              CODE:
1782 #ifdef SvUTF8
1783                if (SvUTF8(str_sv))
1784                  utf8 = 1;
1785 #endif
1786                str = SvPV(str_sv, len);
1787                RETVAL = i_t1_text(im, xb,yb,cl,fontnum,points,str,len,align,
1788                                   utf8,flags);
1789            OUTPUT:
1790              RETVAL
1791
1792 void
1793 i_t1_has_chars(handle, text_sv, utf8 = 0)
1794         int handle
1795         SV  *text_sv
1796         int utf8
1797       PREINIT:
1798         char const *text;
1799         STRLEN len;
1800         char *work;
1801         int count;
1802         int i;
1803       PPCODE:
1804 #ifdef SvUTF8
1805         if (SvUTF8(text_sv))
1806           utf8 = 1;
1807 #endif
1808         text = SvPV(text_sv, len);
1809         work = mymalloc(len);
1810         count = i_t1_has_chars(handle, text, len, utf8, work);
1811         if (GIMME_V == G_ARRAY) {
1812           EXTEND(SP, count);
1813           for (i = 0; i < count; ++i) {
1814             PUSHs(sv_2mortal(newSViv(work[i])));
1815           }
1816         }
1817         else {
1818           EXTEND(SP, 1);
1819           PUSHs(sv_2mortal(newSVpv(work, count)));
1820         }
1821         myfree(work);
1822
1823 void
1824 i_t1_face_name(handle)
1825         int handle
1826       PREINIT:
1827         char name[255];
1828         int len;
1829       PPCODE:
1830         len = i_t1_face_name(handle, name, sizeof(name));
1831         if (len) {
1832           EXTEND(SP, 1);
1833           PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
1834         }
1835
1836 void
1837 i_t1_glyph_name(handle, text_sv, utf8 = 0)
1838         int handle
1839         SV *text_sv
1840         int utf8
1841       PREINIT:
1842         char const *text;
1843         STRLEN work_len;
1844         int len;
1845         char name[255];
1846       PPCODE:
1847 #ifdef SvUTF8
1848         if (SvUTF8(text_sv))
1849           utf8 = 1;
1850 #endif
1851         text = SvPV(text_sv, work_len);
1852         len = work_len;
1853         while (len) {
1854           unsigned long ch;
1855           if (utf8) {
1856             ch = i_utf8_advance(&text, &len);
1857             if (ch == ~0UL) {
1858               i_push_error(0, "invalid UTF8 character");
1859               break;
1860             }
1861           }
1862           else {
1863             ch = *text++;
1864             --len;
1865           }
1866           EXTEND(SP, 1);
1867           if (i_t1_glyph_name(handle, ch, name, sizeof(name))) {
1868             PUSHs(sv_2mortal(newSVpv(name, 0)));
1869           }
1870           else {
1871             PUSHs(&PL_sv_undef);
1872           } 
1873         }
1874
1875 #endif 
1876
1877 #ifdef HAVE_LIBTT
1878
1879
1880 Imager::Font::TT
1881 i_tt_new(fontname)
1882               char*     fontname
1883
1884
1885 MODULE = Imager         PACKAGE = Imager::Font::TT      PREFIX=TT_
1886
1887 #define TT_DESTROY(handle) i_tt_destroy(handle)
1888
1889 void
1890 TT_DESTROY(handle)
1891      Imager::Font::TT   handle
1892
1893
1894 MODULE = Imager         PACKAGE = Imager
1895
1896
1897 undef_int
1898 i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1)
1899   Imager::Font::TT     handle
1900     Imager::ImgRaw     im
1901                int     xb
1902                int     yb
1903      Imager::Color     cl
1904              float     points
1905               SV *     str_sv
1906                int     smooth
1907                int     utf8
1908                int     align
1909              PREINIT:
1910                char *str;
1911                STRLEN len;
1912              CODE:
1913 #ifdef SvUTF8
1914                if (SvUTF8(str_sv))
1915                  utf8 = 1;
1916 #endif
1917                str = SvPV(str_sv, len);
1918                RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, 
1919                                   len, smooth, utf8, align);
1920              OUTPUT:
1921                RETVAL                
1922
1923
1924 undef_int
1925 i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1)
1926   Imager::Font::TT     handle
1927     Imager::ImgRaw     im
1928                int     xb
1929                int     yb
1930                int     channel
1931              float     points
1932               SV *     str_sv
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     utf8
1957              PREINIT:
1958                int     cords[BOUNDING_BOX_COUNT],rc;
1959                char *  str;
1960                STRLEN len;
1961                int i;
1962              PPCODE:
1963 #ifdef SvUTF8
1964                if (SvUTF8(ST(2)))
1965                  utf8 = 1;
1966 #endif
1967                str = SvPV(str_sv, len);
1968                if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) {
1969                  EXTEND(SP, rc);
1970                  for (i = 0; i < rc; ++i) {
1971                    PUSHs(sv_2mortal(newSViv(cords[i])));
1972                  }
1973                }
1974
1975 void
1976 i_tt_has_chars(handle, text_sv, utf8)
1977         Imager::Font::TT handle
1978         SV  *text_sv
1979         int utf8
1980       PREINIT:
1981         char const *text;
1982         STRLEN len;
1983         char *work;
1984         int count;
1985         int i;
1986       PPCODE:
1987 #ifdef SvUTF8
1988         if (SvUTF8(text_sv))
1989           utf8 = 1;
1990 #endif
1991         text = SvPV(text_sv, len);
1992         work = mymalloc(len);
1993         count = i_tt_has_chars(handle, text, len, utf8, work);
1994         if (GIMME_V == G_ARRAY) {
1995           EXTEND(SP, count);
1996           for (i = 0; i < count; ++i) {
1997             PUSHs(sv_2mortal(newSViv(work[i])));
1998           }
1999         }
2000         else {
2001           EXTEND(SP, 1);
2002           PUSHs(sv_2mortal(newSVpv(work, count)));
2003         }
2004         myfree(work);
2005
2006 void
2007 i_tt_dump_names(handle)
2008         Imager::Font::TT handle
2009
2010 void
2011 i_tt_face_name(handle)
2012         Imager::Font::TT handle
2013       PREINIT:
2014         char name[255];
2015         int len;
2016       PPCODE:
2017         len = i_tt_face_name(handle, name, sizeof(name));
2018         if (len) {
2019           EXTEND(SP, 1);
2020           PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
2021         }
2022
2023 void
2024 i_tt_glyph_name(handle, text_sv, utf8 = 0)
2025         Imager::Font::TT handle
2026         SV *text_sv
2027         int utf8
2028       PREINIT:
2029         char const *text;
2030         STRLEN work_len;
2031         int len;
2032         int outsize;
2033         char name[255];
2034       PPCODE:
2035 #ifdef SvUTF8
2036         if (SvUTF8(text_sv))
2037           utf8 = 1;
2038 #endif
2039         text = SvPV(text_sv, work_len);
2040         len = work_len;
2041         while (len) {
2042           unsigned long ch;
2043           if (utf8) {
2044             ch = i_utf8_advance(&text, &len);
2045             if (ch == ~0UL) {
2046               i_push_error(0, "invalid UTF8 character");
2047               break;
2048             }
2049           }
2050           else {
2051             ch = *text++;
2052             --len;
2053           }
2054           EXTEND(SP, 1);
2055           if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
2056             PUSHs(sv_2mortal(newSVpv(name, 0)));
2057           }
2058           else {
2059             PUSHs(&PL_sv_undef);
2060           } 
2061         }
2062
2063 #endif 
2064
2065
2066 #ifdef HAVE_LIBJPEG
2067 undef_int
2068 i_writejpeg_wiol(im, ig, qfactor)
2069     Imager::ImgRaw     im
2070         Imager::IO     ig
2071                int     qfactor
2072
2073
2074 void
2075 i_readjpeg_wiol(ig)
2076         Imager::IO     ig
2077              PREINIT:
2078               char*    iptc_itext;
2079                int     tlength;
2080              i_img*    rimg;
2081                 SV*    r;
2082              PPCODE:
2083               iptc_itext = NULL;
2084               rimg = i_readjpeg_wiol(ig,-1,&iptc_itext,&tlength);
2085               if (iptc_itext == NULL) {
2086                     r = sv_newmortal();
2087                     EXTEND(SP,1);
2088                     sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2089                     PUSHs(r);
2090               } else {
2091                     r = sv_newmortal();
2092                     EXTEND(SP,2);
2093                     sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2094                     PUSHs(r);
2095                     PUSHs(sv_2mortal(newSVpv(iptc_itext,tlength)));
2096                     myfree(iptc_itext);
2097               }
2098
2099 int
2100 i_exif_enabled()
2101
2102 #endif
2103
2104
2105 char *
2106 i_test_format_probe(ig, length)
2107         Imager::IO     ig
2108                int     length
2109
2110
2111
2112 #ifdef HAVE_LIBTIFF
2113
2114 Imager::ImgRaw
2115 i_readtiff_wiol(ig, length, page=0)
2116         Imager::IO     ig
2117                int     length
2118                int     page
2119
2120 void
2121 i_readtiff_multi_wiol(ig, length)
2122         Imager::IO     ig
2123                int     length
2124       PREINIT:
2125         i_img **imgs;
2126         int count;
2127         int i;
2128       PPCODE:
2129         imgs = i_readtiff_multi_wiol(ig, length, &count);
2130         if (imgs) {
2131           EXTEND(SP, count);
2132           for (i = 0; i < count; ++i) {
2133             SV *sv = sv_newmortal();
2134             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2135             PUSHs(sv);
2136           }
2137           myfree(imgs);
2138         }
2139
2140
2141 undef_int
2142 i_writetiff_wiol(im, ig)
2143     Imager::ImgRaw     im
2144         Imager::IO     ig
2145
2146 undef_int
2147 i_writetiff_multi_wiol(ig, ...)
2148         Imager::IO     ig
2149       PREINIT:
2150         int i;
2151         int img_count;
2152         i_img **imgs;
2153       CODE:
2154         if (items < 2)
2155           croak("Usage: i_writetiff_multi_wiol(ig, images...)");
2156         img_count = items - 1;
2157         RETVAL = 1;
2158         if (img_count < 1) {
2159           RETVAL = 0;
2160           i_clear_error();
2161           i_push_error(0, "You need to specify images to save");
2162         }
2163         else {
2164           imgs = mymalloc(sizeof(i_img *) * img_count);
2165           for (i = 0; i < img_count; ++i) {
2166             SV *sv = ST(1+i);
2167             imgs[i] = NULL;
2168             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2169               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2170             }
2171             else {
2172               i_clear_error();
2173               i_push_error(0, "Only images can be saved");
2174               myfree(imgs);
2175               RETVAL = 0;
2176               break;
2177             }
2178           }
2179           if (RETVAL) {
2180             RETVAL = i_writetiff_multi_wiol(ig, imgs, img_count);
2181           }
2182           myfree(imgs);
2183         }
2184       OUTPUT:
2185         RETVAL
2186
2187 undef_int
2188 i_writetiff_wiol_faxable(im, ig, fine)
2189     Imager::ImgRaw     im
2190         Imager::IO     ig
2191                int     fine
2192
2193 undef_int
2194 i_writetiff_multi_wiol_faxable(ig, fine, ...)
2195         Imager::IO     ig
2196         int fine
2197       PREINIT:
2198         int i;
2199         int img_count;
2200         i_img **imgs;
2201       CODE:
2202         if (items < 3)
2203           croak("Usage: i_writetiff_multi_wiol_faxable(ig, fine, images...)");
2204         img_count = items - 2;
2205         RETVAL = 1;
2206         if (img_count < 1) {
2207           RETVAL = 0;
2208           i_clear_error();
2209           i_push_error(0, "You need to specify images to save");
2210         }
2211         else {
2212           imgs = mymalloc(sizeof(i_img *) * img_count);
2213           for (i = 0; i < img_count; ++i) {
2214             SV *sv = ST(2+i);
2215             imgs[i] = NULL;
2216             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2217               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2218             }
2219             else {
2220               i_clear_error();
2221               i_push_error(0, "Only images can be saved");
2222               myfree(imgs);
2223               RETVAL = 0;
2224               break;
2225             }
2226           }
2227           if (RETVAL) {
2228             RETVAL = i_writetiff_multi_wiol_faxable(ig, imgs, img_count, fine);
2229           }
2230           myfree(imgs);
2231         }
2232       OUTPUT:
2233         RETVAL
2234
2235
2236 #endif /* HAVE_LIBTIFF */
2237
2238
2239 #ifdef HAVE_LIBPNG
2240
2241 Imager::ImgRaw
2242 i_readpng_wiol(ig, length)
2243         Imager::IO     ig
2244                int     length
2245
2246
2247 undef_int
2248 i_writepng_wiol(im, ig)
2249     Imager::ImgRaw     im
2250         Imager::IO     ig
2251
2252
2253 #endif
2254
2255
2256 #ifdef HAVE_LIBGIF
2257
2258 void
2259 i_giflib_version()
2260         PPCODE:
2261           PUSHs(sv_2mortal(newSVnv(IM_GIFMAJOR+IM_GIFMINOR*0.1)));
2262
2263 undef_int
2264 i_writegif(im,fd,colors,pixdev,fixed)
2265     Imager::ImgRaw     im
2266                int     fd
2267                int     colors
2268                int     pixdev
2269              PREINIT:
2270              int     fixedlen;
2271              Imager__Color  fixed;
2272              Imager__Color  tmp;
2273              AV* av;
2274              SV* sv1;
2275              IV  Itmp;
2276              int i;
2277              CODE:
2278              if (!SvROK(ST(4))) croak("Imager: Parameter 4 must be a reference to an array\n");
2279              if (SvTYPE(SvRV(ST(4))) != SVt_PVAV) croak("Imager: Parameter 4 must be a reference to an array\n");
2280              av=(AV*)SvRV(ST(4));
2281              fixedlen=av_len(av)+1;
2282              fixed=mymalloc( fixedlen*sizeof(i_color) );
2283              for(i=0;i<fixedlen;i++) {
2284                sv1=(*(av_fetch(av,i,0)));
2285                if (sv_derived_from(sv1, "Imager::Color")) {
2286                  Itmp = SvIV((SV*)SvRV(sv1));
2287                  tmp = INT2PTR(i_color*, Itmp);
2288                } else croak("Imager: one of the elements of array ref is not of Imager::Color type\n");
2289                fixed[i]=*tmp;
2290              }
2291              RETVAL=i_writegif(im,fd,colors,pixdev,fixedlen,fixed);
2292              myfree(fixed);
2293              ST(0) = sv_newmortal();
2294              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2295              else sv_setiv(ST(0), (IV)RETVAL);
2296
2297
2298
2299
2300 undef_int
2301 i_writegifmc(im,fd,colors)
2302     Imager::ImgRaw    im
2303                int     fd
2304                int     colors
2305
2306
2307 undef_int
2308 i_writegif_gen(fd, ...)
2309                int     fd
2310       PROTOTYPE: $$@
2311       PREINIT:
2312         i_quantize quant;
2313         i_img **imgs = NULL;
2314         int img_count;
2315         int i;
2316         HV *hv;
2317       CODE:
2318         if (items < 3)
2319             croak("Usage: i_writegif_gen(fd,hashref, images...)");
2320         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2321             croak("i_writegif_gen: Second argument must be a hash ref");
2322         hv = (HV *)SvRV(ST(1));
2323         memset(&quant, 0, sizeof(quant));
2324         quant.mc_size = 256;
2325         handle_quant_opts(&quant, hv);
2326         img_count = items - 2;
2327         RETVAL = 1;
2328         if (img_count < 1) {
2329           RETVAL = 0;
2330           i_clear_error();
2331           i_push_error(0, "You need to specify images to save");
2332         }
2333         else {
2334           imgs = mymalloc(sizeof(i_img *) * img_count);
2335           for (i = 0; i < img_count; ++i) {
2336             SV *sv = ST(2+i);
2337             imgs[i] = NULL;
2338             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2339               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2340             }
2341             else {
2342               i_clear_error();
2343               i_push_error(0, "Only images can be saved");
2344               RETVAL = 0;
2345               break;
2346             }
2347           }
2348           if (RETVAL) {
2349             RETVAL = i_writegif_gen(&quant, fd, imgs, img_count);
2350           }
2351           myfree(imgs);
2352           if (RETVAL) {
2353             copy_colors_back(hv, &quant);
2354           }
2355         }
2356         ST(0) = sv_newmortal();
2357         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2358         else sv_setiv(ST(0), (IV)RETVAL);
2359         cleanup_quant_opts(&quant);
2360
2361
2362 undef_int
2363 i_writegif_callback(cb, maxbuffer,...)
2364         int maxbuffer;
2365       PREINIT:
2366         i_quantize quant;
2367         i_img **imgs = NULL;
2368         int img_count;
2369         int i;
2370         HV *hv;
2371         i_writer_data wd;
2372       CODE:
2373         if (items < 4)
2374             croak("Usage: i_writegif_callback(\\&callback,maxbuffer,hashref, images...)");
2375         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2376             croak("i_writegif_callback: Second argument must be a hash ref");
2377         hv = (HV *)SvRV(ST(2));
2378         memset(&quant, 0, sizeof(quant));
2379         quant.mc_size = 256;
2380         handle_quant_opts(&quant, hv);
2381         img_count = items - 3;
2382         RETVAL = 1;
2383         if (img_count < 1) {
2384           RETVAL = 0;
2385         }
2386         else {
2387           imgs = mymalloc(sizeof(i_img *) * img_count);
2388           for (i = 0; i < img_count; ++i) {
2389             SV *sv = ST(3+i);
2390             imgs[i] = NULL;
2391             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2392               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2393             }
2394             else {
2395               RETVAL = 0;
2396               break;
2397             }
2398           }
2399           if (RETVAL) {
2400             wd.sv = ST(0);
2401             RETVAL = i_writegif_callback(&quant, write_callback, (char *)&wd, maxbuffer, imgs, img_count);
2402           }
2403           myfree(imgs);
2404           if (RETVAL) {
2405             copy_colors_back(hv, &quant);
2406           }
2407         }
2408         ST(0) = sv_newmortal();
2409         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2410         else sv_setiv(ST(0), (IV)RETVAL);
2411         cleanup_quant_opts(&quant);
2412
2413 undef_int
2414 i_writegif_wiol(ig, opts,...)
2415         Imager::IO ig
2416       PREINIT:
2417         i_quantize quant;
2418         i_img **imgs = NULL;
2419         int img_count;
2420         int i;
2421         HV *hv;
2422       CODE:
2423         if (items < 3)
2424             croak("Usage: i_writegif_wiol(IO,hashref, images...)");
2425         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2426             croak("i_writegif_callback: Second argument must be a hash ref");
2427         hv = (HV *)SvRV(ST(1));
2428         memset(&quant, 0, sizeof(quant));
2429         quant.mc_size = 256;
2430         handle_quant_opts(&quant, hv);
2431         img_count = items - 2;
2432         RETVAL = 1;
2433         if (img_count < 1) {
2434           RETVAL = 0;
2435         }
2436         else {
2437           imgs = mymalloc(sizeof(i_img *) * img_count);
2438           for (i = 0; i < img_count; ++i) {
2439             SV *sv = ST(2+i);
2440             imgs[i] = NULL;
2441             if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
2442               imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
2443             }
2444             else {
2445               RETVAL = 0;
2446               break;
2447             }
2448           }
2449           if (RETVAL) {
2450             RETVAL = i_writegif_wiol(ig, &quant, imgs, img_count);
2451           }
2452           myfree(imgs);
2453           if (RETVAL) {
2454             copy_colors_back(hv, &quant);
2455           }
2456         }
2457         ST(0) = sv_newmortal();
2458         if (RETVAL == 0) ST(0)=&PL_sv_undef;
2459         else sv_setiv(ST(0), (IV)RETVAL);
2460         cleanup_quant_opts(&quant);
2461
2462 void
2463 i_readgif(fd)
2464                int     fd
2465               PREINIT:
2466                 int*    colour_table;
2467                 int     colours, q, w;
2468               i_img*    rimg;
2469                  SV*    temp[3];
2470                  AV*    ct; 
2471                  SV*    r;
2472                PPCODE:
2473                colour_table = NULL;
2474                colours = 0;
2475
2476         if(GIMME_V == G_ARRAY) {
2477             rimg = i_readgif(fd,&colour_table,&colours);
2478         } else {
2479             /* don't waste time with colours if they aren't wanted */
2480             rimg = i_readgif(fd,NULL,NULL);
2481         }
2482         
2483         if (colour_table == NULL) {
2484             EXTEND(SP,1);
2485             r=sv_newmortal();
2486             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2487             PUSHs(r);
2488         } else {
2489             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2490             /* I don't know if I have the reference counts right or not :( */
2491             /* Neither do I :-) */
2492             /* No Idea here either */
2493
2494             ct=newAV();
2495             av_extend(ct, colours);
2496             for(q=0; q<colours; q++) {
2497                 for(w=0; w<3; w++)
2498                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2499                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2500             }
2501             myfree(colour_table);
2502
2503             EXTEND(SP,2);
2504             r = sv_newmortal();
2505             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2506             PUSHs(r);
2507             PUSHs(newRV_noinc((SV*)ct));
2508         }
2509
2510 void
2511 i_readgif_wiol(ig)
2512      Imager::IO         ig
2513               PREINIT:
2514                 int*    colour_table;
2515                 int     colours, q, w;
2516               i_img*    rimg;
2517                  SV*    temp[3];
2518                  AV*    ct; 
2519                  SV*    r;
2520                PPCODE:
2521                colour_table = NULL;
2522                colours = 0;
2523
2524         if(GIMME_V == G_ARRAY) {
2525             rimg = i_readgif_wiol(ig,&colour_table,&colours);
2526         } else {
2527             /* don't waste time with colours if they aren't wanted */
2528             rimg = i_readgif_wiol(ig,NULL,NULL);
2529         }
2530         
2531         if (colour_table == NULL) {
2532             EXTEND(SP,1);
2533             r=sv_newmortal();
2534             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2535             PUSHs(r);
2536         } else {
2537             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2538             /* I don't know if I have the reference counts right or not :( */
2539             /* Neither do I :-) */
2540             /* No Idea here either */
2541
2542             ct=newAV();
2543             av_extend(ct, colours);
2544             for(q=0; q<colours; q++) {
2545                 for(w=0; w<3; w++)
2546                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2547                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2548             }
2549             myfree(colour_table);
2550
2551             EXTEND(SP,2);
2552             r = sv_newmortal();
2553             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2554             PUSHs(r);
2555             PUSHs(newRV_noinc((SV*)ct));
2556         }
2557
2558 Imager::ImgRaw
2559 i_readgif_single_wiol(ig, page=0)
2560         Imager::IO      ig
2561         int             page
2562
2563 void
2564 i_readgif_scalar(...)
2565           PROTOTYPE: $
2566             PREINIT:
2567                char*    data;
2568              STRLEN     length;
2569                 int*    colour_table;
2570                 int     colours, q, w;
2571               i_img*    rimg;
2572                  SV*    temp[3];
2573                  AV*    ct; 
2574                  SV*    r;
2575                PPCODE:
2576         data = (char *)SvPV(ST(0), length);
2577         colour_table=NULL;
2578         colours=0;
2579
2580         if(GIMME_V == G_ARRAY) {  
2581             rimg=i_readgif_scalar(data,length,&colour_table,&colours);
2582         } else {
2583             /* don't waste time with colours if they aren't wanted */
2584             rimg=i_readgif_scalar(data,length,NULL,NULL);
2585         }
2586
2587         if (colour_table == NULL) {
2588             EXTEND(SP,1);
2589             r=sv_newmortal();
2590             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2591             PUSHs(r);
2592         } else {
2593             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2594             /* I don't know if I have the reference counts right or not :( */
2595             /* Neither do I :-) */
2596             ct=newAV();
2597             av_extend(ct, colours);
2598             for(q=0; q<colours; q++) {
2599                 for(w=0; w<3; w++)
2600                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2601                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2602             }
2603             myfree(colour_table);
2604             
2605             EXTEND(SP,2);
2606             r=sv_newmortal();
2607             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2608             PUSHs(r);
2609             PUSHs(newRV_noinc((SV*)ct));
2610         }
2611
2612 void
2613 i_readgif_callback(...)
2614           PROTOTYPE: &
2615             PREINIT:
2616                 int*    colour_table;
2617                 int     colours, q, w;
2618               i_img*    rimg;
2619                  SV*    temp[3];
2620                  AV*    ct; 
2621                  SV*    r;
2622        i_reader_data    rd;
2623                PPCODE:
2624         rd.sv = ST(0);
2625         colour_table=NULL;
2626         colours=0;
2627
2628         if(GIMME_V == G_ARRAY) {  
2629             rimg=i_readgif_callback(read_callback, (char *)&rd,&colour_table,&colours);
2630         } else {
2631             /* don't waste time with colours if they aren't wanted */
2632             rimg=i_readgif_callback(read_callback, (char *)&rd,NULL,NULL);
2633         }
2634
2635         if (colour_table == NULL) {
2636             EXTEND(SP,1);
2637             r=sv_newmortal();
2638             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2639             PUSHs(r);
2640         } else {
2641             /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
2642             /* I don't know if I have the reference counts right or not :( */
2643             /* Neither do I :-) */
2644             /* Neither do I - maybe I'll move this somewhere */
2645             ct=newAV();
2646             av_extend(ct, colours);
2647             for(q=0; q<colours; q++) {
2648                 for(w=0; w<3; w++)
2649                     temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
2650                 av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
2651             }
2652             myfree(colour_table);
2653             
2654             EXTEND(SP,2);
2655             r=sv_newmortal();
2656             sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
2657             PUSHs(r);
2658             PUSHs(newRV_noinc((SV*)ct));
2659         }
2660
2661 void
2662 i_readgif_multi(fd)
2663         int     fd
2664       PREINIT:
2665         i_img **imgs;
2666         int count;
2667         int i;
2668       PPCODE:
2669         imgs = i_readgif_multi(fd, &count);
2670         if (imgs) {
2671           EXTEND(SP, count);
2672           for (i = 0; i < count; ++i) {
2673             SV *sv = sv_newmortal();
2674             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2675             PUSHs(sv);
2676           }
2677           myfree(imgs);
2678         }
2679
2680 void
2681 i_readgif_multi_scalar(data)
2682       PREINIT:
2683         i_img **imgs;
2684         int count;
2685         char *data;
2686         STRLEN length;
2687         int i;
2688       PPCODE:
2689         data = (char *)SvPV(ST(0), length);
2690         imgs = i_readgif_multi_scalar(data, length, &count);
2691         if (imgs) {
2692           EXTEND(SP, count);
2693           for (i = 0; i < count; ++i) {
2694             SV *sv = sv_newmortal();
2695             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2696             PUSHs(sv);
2697           }
2698           myfree(imgs);
2699         }
2700
2701 void
2702 i_readgif_multi_callback(cb)
2703       PREINIT:
2704         i_reader_data rd;
2705         i_img **imgs;
2706         int count;
2707         int i;
2708       PPCODE:
2709         rd.sv = ST(0);
2710         imgs = i_readgif_multi_callback(read_callback, (char *)&rd, &count);
2711         if (imgs) {
2712           EXTEND(SP, count);
2713           for (i = 0; i < count; ++i) {
2714             SV *sv = sv_newmortal();
2715             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2716             PUSHs(sv);
2717           }
2718           myfree(imgs);
2719         }
2720
2721 void
2722 i_readgif_multi_wiol(ig)
2723         Imager::IO ig
2724       PREINIT:
2725         i_img **imgs;
2726         int count;
2727         int i;
2728       PPCODE:
2729         imgs = i_readgif_multi_wiol(ig, &count);
2730         if (imgs) {
2731           EXTEND(SP, count);
2732           for (i = 0; i < count; ++i) {
2733             SV *sv = sv_newmortal();
2734             sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2735             PUSHs(sv);
2736           }
2737           myfree(imgs);
2738         }
2739
2740
2741 #endif
2742
2743
2744
2745 Imager::ImgRaw
2746 i_readpnm_wiol(ig, length)
2747         Imager::IO     ig
2748                int     length
2749
2750
2751 undef_int
2752 i_writeppm_wiol(im, ig)
2753     Imager::ImgRaw     im
2754         Imager::IO     ig
2755
2756
2757 Imager::ImgRaw
2758 i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
2759         Imager::IO     ig
2760                int     x
2761                int     y
2762                int     datachannels
2763                int     storechannels
2764                int     intrl
2765
2766 undef_int
2767 i_writeraw_wiol(im,ig)
2768     Imager::ImgRaw     im
2769         Imager::IO     ig
2770
2771 undef_int
2772 i_writebmp_wiol(im,ig)
2773     Imager::ImgRaw     im
2774         Imager::IO     ig
2775
2776 Imager::ImgRaw
2777 i_readbmp_wiol(ig)
2778         Imager::IO     ig
2779
2780
2781 undef_int
2782 i_writetga_wiol(im,ig, wierdpack, compress, idstring)
2783     Imager::ImgRaw     im
2784         Imager::IO     ig
2785                int     wierdpack
2786                int     compress
2787               char*    idstring
2788             PREINIT:
2789                 int idlen;
2790                CODE:
2791                 idlen  = SvCUR(ST(4));
2792                 RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
2793                 OUTPUT:
2794                 RETVAL
2795
2796
2797 Imager::ImgRaw
2798 i_readtga_wiol(ig, length)
2799         Imager::IO     ig
2800                int     length
2801
2802
2803 undef_int
2804 i_writergb_wiol(im,ig, wierdpack, compress, idstring)
2805     Imager::ImgRaw     im
2806         Imager::IO     ig
2807                int     wierdpack
2808                int     compress
2809               char*    idstring
2810             PREINIT:
2811                 int idlen;
2812                CODE:
2813                 idlen  = SvCUR(ST(4));
2814                 RETVAL = i_writergb_wiol(im, ig, wierdpack, compress, idstring, idlen);
2815                 OUTPUT:
2816                 RETVAL
2817
2818
2819 Imager::ImgRaw
2820 i_readrgb_wiol(ig, length)
2821         Imager::IO     ig
2822                int     length
2823
2824
2825
2826 Imager::ImgRaw
2827 i_scaleaxis(im,Value,Axis)
2828     Imager::ImgRaw     im
2829              float     Value
2830                int     Axis
2831
2832 Imager::ImgRaw
2833 i_scale_nn(im,scx,scy)
2834     Imager::ImgRaw     im
2835              float     scx
2836              float     scy
2837
2838 Imager::ImgRaw
2839 i_haar(im)
2840     Imager::ImgRaw     im
2841
2842 int
2843 i_count_colors(im,maxc)
2844     Imager::ImgRaw     im
2845                int     maxc
2846
2847
2848 Imager::ImgRaw
2849 i_transform(im,opx,opy,parm)
2850     Imager::ImgRaw     im
2851              PREINIT:
2852              double* parm;
2853              int*    opx;
2854              int*    opy;
2855              int     opxl;
2856              int     opyl;
2857              int     parmlen;
2858              AV* av;
2859              SV* sv1;
2860              int i;
2861              CODE:
2862              if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
2863              if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n");
2864              if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n");
2865              if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
2866              if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n");
2867              if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n");
2868              av=(AV*)SvRV(ST(1));
2869              opxl=av_len(av)+1;
2870              opx=mymalloc( opxl*sizeof(int) );
2871              for(i=0;i<opxl;i++) {
2872                sv1=(*(av_fetch(av,i,0)));
2873                opx[i]=(int)SvIV(sv1);
2874              }
2875              av=(AV*)SvRV(ST(2));
2876              opyl=av_len(av)+1;
2877              opy=mymalloc( opyl*sizeof(int) );
2878              for(i=0;i<opyl;i++) {
2879                sv1=(*(av_fetch(av,i,0)));
2880                opy[i]=(int)SvIV(sv1);
2881              }
2882              av=(AV*)SvRV(ST(3));
2883              parmlen=av_len(av)+1;
2884              parm=mymalloc( parmlen*sizeof(double) );
2885              for(i=0;i<parmlen;i++) { /* FIXME: Bug? */
2886                sv1=(*(av_fetch(av,i,0)));
2887                parm[i]=(double)SvNV(sv1);
2888              }
2889              RETVAL=i_transform(im,opx,opxl,opy,opyl,parm,parmlen);
2890              myfree(parm);
2891              myfree(opy);
2892              myfree(opx);
2893              ST(0) = sv_newmortal();
2894              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2895              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2896
2897 Imager::ImgRaw
2898 i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
2899         SV *sv_width
2900         SV *sv_height
2901         SV *sv_ops
2902         AV *av_n_regs
2903         AV *av_c_regs
2904         AV *av_in_imgs
2905         int channels
2906              PREINIT:
2907              int width;
2908              int height;
2909              struct rm_op *ops;
2910              STRLEN ops_len;
2911              int ops_count;
2912              double *n_regs;
2913              int n_regs_count;
2914              i_color *c_regs;
2915              int c_regs_count;
2916              int in_imgs_count;
2917              i_img **in_imgs;
2918              SV *sv1;
2919              IV tmp;
2920              int i;
2921              CODE:
2922
2923              in_imgs_count = av_len(av_in_imgs)+1;
2924              for (i = 0; i < in_imgs_count; ++i) {
2925                sv1 = *av_fetch(av_in_imgs, i, 0);
2926                if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2927                  croak("sv_in_img must contain only images");
2928                }
2929              }
2930              if (in_imgs_count > 0) {
2931                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2932                for (i = 0; i < in_imgs_count; ++i) {              
2933                  sv1 = *av_fetch(av_in_imgs,i,0);
2934                  if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2935                    croak("Parameter 5 must contain only images");
2936                  }
2937                  tmp = SvIV((SV*)SvRV(sv1));
2938                  in_imgs[i] = INT2PTR(i_img*, tmp);
2939                }
2940              }
2941              else {
2942                /* no input images */
2943                in_imgs = NULL;
2944              }
2945              /* default the output size from the first input if possible */
2946              if (SvOK(sv_width))
2947                width = SvIV(sv_width);
2948              else if (in_imgs_count)
2949                width = in_imgs[0]->xsize;
2950              else
2951                croak("No output image width supplied");
2952
2953              if (SvOK(sv_height))
2954                height = SvIV(sv_height);
2955              else if (in_imgs_count)
2956                height = in_imgs[0]->ysize;
2957              else
2958                croak("No output image height supplied");
2959
2960              ops = (struct rm_op *)SvPV(sv_ops, ops_len);
2961              if (ops_len % sizeof(struct rm_op))
2962                  croak("Imager: Parameter 3 must be a bitmap of regops\n");
2963              ops_count = ops_len / sizeof(struct rm_op);
2964
2965              n_regs_count = av_len(av_n_regs)+1;
2966              n_regs = mymalloc(n_regs_count * sizeof(double));
2967              for (i = 0; i < n_regs_count; ++i) {
2968                sv1 = *av_fetch(av_n_regs,i,0);
2969                if (SvOK(sv1))
2970                  n_regs[i] = SvNV(sv1);
2971              }
2972              c_regs_count = av_len(av_c_regs)+1;
2973              c_regs = mymalloc(c_regs_count * sizeof(i_color));
2974              /* I don't bother initializing the colou?r registers */
2975
2976              RETVAL=i_transform2(width, height, channels, ops, ops_count, 
2977                                  n_regs, n_regs_count, 
2978                                  c_regs, c_regs_count, in_imgs, in_imgs_count);
2979              if (in_imgs)
2980                  myfree(in_imgs);
2981              myfree(n_regs);
2982              myfree(c_regs);
2983              ST(0) = sv_newmortal();
2984              if (RETVAL == 0) ST(0)=&PL_sv_undef;
2985              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
2986
2987
2988 void
2989 i_contrast(im,intensity)
2990     Imager::ImgRaw     im
2991              float     intensity
2992
2993 void
2994 i_hardinvert(im)
2995     Imager::ImgRaw     im
2996
2997 void
2998 i_noise(im,amount,type)
2999     Imager::ImgRaw     im
3000              float     amount
3001      unsigned char     type
3002
3003 void
3004 i_bumpmap(im,bump,channel,light_x,light_y,strength)
3005     Imager::ImgRaw     im
3006     Imager::ImgRaw     bump
3007                int     channel
3008                int     light_x
3009                int     light_y
3010                int     strength
3011
3012
3013 void
3014 i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
3015     Imager::ImgRaw     im
3016     Imager::ImgRaw     bump
3017                int     channel
3018                int     tx
3019                int     ty
3020              float     Lx
3021              float     Ly
3022              float     Lz
3023              float     cd
3024              float     cs
3025              float     n
3026      Imager::Color     Ia
3027      Imager::Color     Il
3028      Imager::Color     Is
3029
3030
3031
3032 void
3033 i_postlevels(im,levels)
3034     Imager::ImgRaw     im
3035              int       levels
3036
3037 void
3038 i_mosaic(im,size)
3039     Imager::ImgRaw     im
3040                int     size
3041
3042 void
3043 i_watermark(im,wmark,tx,ty,pixdiff)
3044     Imager::ImgRaw     im
3045     Imager::ImgRaw     wmark
3046                int     tx
3047                int     ty
3048                int     pixdiff
3049
3050
3051 void
3052 i_autolevels(im,lsat,usat,skew)
3053     Imager::ImgRaw     im
3054              float     lsat
3055              float     usat
3056              float     skew
3057
3058 void
3059 i_radnoise(im,xo,yo,rscale,ascale)
3060     Imager::ImgRaw     im
3061              float     xo
3062              float     yo
3063              float     rscale
3064              float     ascale
3065
3066 void
3067 i_turbnoise(im, xo, yo, scale)
3068     Imager::ImgRaw     im
3069              float     xo
3070              float     yo
3071              float     scale
3072
3073
3074 void
3075 i_gradgen(im, ...)
3076     Imager::ImgRaw     im
3077       PREINIT:
3078         int num;
3079         int *xo;
3080         int *yo;
3081         i_color *ival;
3082         int dmeasure;
3083         int i;
3084         SV *sv;
3085         AV *axx;
3086         AV *ayy;
3087         AV *ac;
3088       CODE:
3089         if (items != 5)
3090             croak("Usage: i_gradgen(im, xo, yo, ival, dmeasure)");
3091         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3092             croak("i_gradgen: Second argument must be an array ref");
3093         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
3094             croak("i_gradgen: Third argument must be an array ref");
3095         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
3096             croak("i_gradgen: Fourth argument must be an array ref");
3097         axx = (AV *)SvRV(ST(1));
3098         ayy = (AV *)SvRV(ST(2));
3099         ac  = (AV *)SvRV(ST(3));
3100         dmeasure = (int)SvIV(ST(4));
3101         
3102         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
3103         num = num <= av_len(ac) ? num : av_len(ac);
3104         num++; 
3105         if (num < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each");
3106         xo = mymalloc( sizeof(int) * num );
3107         yo = mymalloc( sizeof(int) * num );
3108         ival = mymalloc( sizeof(i_color) * num );
3109         for(i = 0; i<num; i++) {
3110           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
3111           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
3112           sv = *av_fetch(ac, i, 0);
3113           if ( !sv_derived_from(sv, "Imager::Color") ) {
3114             free(axx); free(ayy); free(ac);
3115             croak("i_gradgen: Element of fourth argument is not derived from Imager::Color");
3116           }
3117           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
3118         }
3119         i_gradgen(im, num, xo, yo, ival, dmeasure);
3120         myfree(xo);
3121         myfree(yo);
3122         myfree(ival);
3123
3124 Imager::ImgRaw
3125 i_diff_image(im, im2, mindist=0)
3126     Imager::ImgRaw     im
3127     Imager::ImgRaw     im2
3128                int     mindist
3129
3130 undef_int
3131 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
3132     Imager::ImgRaw     im
3133             double     xa
3134             double     ya
3135             double     xb
3136             double     yb
3137                int     type
3138                int     repeat
3139                int     combine
3140                int     super_sample
3141             double     ssample_param
3142       PREINIT:
3143         AV *asegs;
3144         int count;
3145         i_fountain_seg *segs;
3146       CODE:
3147         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
3148             croak("i_fountain: argument 11 must be an array ref");
3149         
3150         asegs = (AV *)SvRV(ST(10));
3151         segs = load_fount_segs(asegs, &count);
3152         RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, 
3153                             super_sample, ssample_param, count, segs);
3154         myfree(segs);
3155       OUTPUT:
3156         RETVAL
3157
3158 Imager::FillHandle
3159 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
3160             double     xa
3161             double     ya
3162             double     xb
3163             double     yb
3164                int     type
3165                int     repeat
3166                int     combine
3167                int     super_sample
3168             double     ssample_param
3169       PREINIT:
3170         AV *asegs;
3171         int count;
3172         i_fountain_seg *segs;
3173       CODE:
3174         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
3175             croak("i_fountain: argument 11 must be an array ref");
3176         
3177         asegs = (AV *)SvRV(ST(9));
3178         segs = load_fount_segs(asegs, &count);
3179         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
3180                                   super_sample, ssample_param, count, segs);
3181         myfree(segs);        
3182       OUTPUT:
3183         RETVAL
3184
3185 void
3186 i_errors()
3187       PREINIT:
3188         i_errmsg *errors;
3189         int i;
3190         AV *av;
3191         SV *sv;
3192       PPCODE:
3193         errors = i_errors();
3194         i = 0;
3195         while (errors[i].msg) {
3196           av = newAV();
3197           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
3198           if (!av_store(av, 0, sv)) {
3199             SvREFCNT_dec(sv);
3200           }
3201           sv = newSViv(errors[i].code);
3202           if (!av_store(av, 1, sv)) {
3203             SvREFCNT_dec(sv);
3204           }
3205           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
3206           ++i;
3207         }
3208
3209 undef_int
3210 i_nearest_color(im, ...)
3211     Imager::ImgRaw     im
3212       PREINIT:
3213         int num;
3214         int *xo;
3215         int *yo;
3216         i_color *ival;
3217         int dmeasure;
3218         int i;
3219         SV *sv;
3220         AV *axx;
3221         AV *ayy;
3222         AV *ac;
3223       CODE:
3224         if (items != 5)
3225             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
3226         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3227             croak("i_nearest_color: Second argument must be an array ref");
3228         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
3229             croak("i_nearest_color: Third argument must be an array ref");
3230         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
3231             croak("i_nearest_color: Fourth argument must be an array ref");
3232         axx = (AV *)SvRV(ST(1));
3233         ayy = (AV *)SvRV(ST(2));
3234         ac  = (AV *)SvRV(ST(3));
3235         dmeasure = (int)SvIV(ST(4));
3236         
3237         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
3238         num = num <= av_len(ac) ? num : av_len(ac);
3239         num++; 
3240         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
3241         xo = mymalloc( sizeof(int) * num );
3242         yo = mymalloc( sizeof(int) * num );
3243         ival = mymalloc( sizeof(i_color) * num );
3244         for(i = 0; i<num; i++) {
3245           xo[i]   = (int)SvIV(* av_fetch(axx, i, 0));
3246           yo[i]   = (int)SvIV(* av_fetch(ayy, i, 0));
3247           sv = *av_fetch(ac, i, 0);
3248           if ( !sv_derived_from(sv, "Imager::Color") ) {
3249             free(axx); free(ayy); free(ac);
3250             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
3251           }
3252           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
3253         }
3254         RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
3255       OUTPUT:
3256         RETVAL
3257
3258 void
3259 malloc_state()
3260
3261 void
3262 DSO_open(filename)
3263              char*       filename
3264              PREINIT:
3265                void *rc;
3266                char *evstr;
3267              PPCODE:
3268                rc=DSO_open(filename,&evstr);
3269                if (rc!=NULL) {
3270                  if (evstr!=NULL) {
3271                    EXTEND(SP,2); 
3272                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3273                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
3274                  } else {
3275                    EXTEND(SP,1);
3276                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
3277                  }
3278                }
3279
3280
3281 undef_int
3282 DSO_close(dso_handle)
3283              void*       dso_handle
3284
3285 void
3286 DSO_funclist(dso_handle_v)
3287              void*       dso_handle_v
3288              PREINIT:
3289                int i;
3290                DSO_handle *dso_handle;
3291              PPCODE:
3292                dso_handle=(DSO_handle*)dso_handle_v;
3293                i=0;
3294                while( dso_handle->function_list[i].name != NULL) {
3295                  EXTEND(SP,1);
3296                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i].name,0)));
3297                  EXTEND(SP,1);
3298                  PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i++].pcode,0)));
3299                }
3300
3301
3302 void
3303 DSO_call(handle,func_index,hv)
3304                void*  handle
3305                int    func_index
3306              PREINIT:
3307                HV* hv;
3308              PPCODE:
3309                if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
3310                hv=(HV*)SvRV(ST(2));
3311                if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
3312                DSO_call( (DSO_handle *)handle,func_index,hv);
3313
3314
3315
3316 SV *
3317 i_get_pixel(im, x, y)
3318         Imager::ImgRaw im
3319         int x
3320         int y;
3321       PREINIT:
3322         i_color *color;
3323       CODE:
3324         color = (i_color *)mymalloc(sizeof(i_color));
3325         if (i_gpix(im, x, y, color) == 0) {
3326           RETVAL = NEWSV(0, 0);
3327           sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
3328         }
3329         else {
3330           myfree(color);
3331           RETVAL = &PL_sv_undef;
3332         }
3333       OUTPUT:
3334         RETVAL
3335         
3336
3337 int
3338 i_ppix(im, x, y, cl)
3339         Imager::ImgRaw im
3340         int x
3341         int y
3342         Imager::Color cl
3343
3344 Imager::ImgRaw
3345 i_img_pal_new(x, y, channels, maxpal)
3346         int     x
3347         int     y
3348         int     channels
3349         int     maxpal
3350
3351 Imager::ImgRaw
3352 i_img_to_pal(src, quant)
3353         Imager::ImgRaw src
3354       PREINIT:
3355         HV *hv;
3356         i_quantize quant;
3357       CODE:
3358         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3359           croak("i_img_to_pal: second argument must be a hash ref");
3360         hv = (HV *)SvRV(ST(1));
3361         memset(&quant, 0, sizeof(quant));
3362         quant.mc_size = 256;
3363         handle_quant_opts(&quant, hv);
3364         RETVAL = i_img_to_pal(src, &quant);
3365         if (RETVAL) {
3366           copy_colors_back(hv, &quant);
3367         }
3368         cleanup_quant_opts(&quant);
3369       OUTPUT:
3370         RETVAL
3371
3372 Imager::ImgRaw
3373 i_img_to_rgb(src)
3374         Imager::ImgRaw src
3375
3376 void
3377 i_gpal(im, l, r, y)
3378         Imager::ImgRaw  im
3379         int     l
3380         int     r
3381         int     y
3382       PREINIT:
3383         i_palidx *work;
3384         int count, i;
3385       PPCODE:
3386         if (l < r) {
3387           work = mymalloc((r-l) * sizeof(i_palidx));
3388           count = i_gpal(im, l, r, y, work);
3389           if (GIMME_V == G_ARRAY) {
3390             EXTEND(SP, count);
3391             for (i = 0; i < count; ++i) {
3392               PUSHs(sv_2mortal(newSViv(work[i])));
3393             }
3394           }
3395           else {
3396             EXTEND(SP, 1);
3397             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3398           }
3399           myfree(work);
3400         }
3401         else {
3402           if (GIMME_V != G_ARRAY) {
3403             EXTEND(SP, 1);
3404             PUSHs(&PL_sv_undef);
3405           }
3406         }
3407
3408 int
3409 i_ppal(im, l, y, ...)
3410         Imager::ImgRaw  im
3411         int     l
3412         int     y
3413       PREINIT:
3414         i_palidx *work;
3415         int i;
3416       CODE:
3417         if (items > 3) {
3418           work = mymalloc(sizeof(i_palidx) * (items-3));
3419           for (i=0; i < items-3; ++i) {
3420             work[i] = SvIV(ST(i+3));
3421           }
3422           RETVAL = i_ppal(im, l, l+items-3, y, work);
3423           myfree(work);
3424         }
3425         else {
3426           RETVAL = 0;
3427         }
3428       OUTPUT:
3429         RETVAL
3430
3431 SV *
3432 i_addcolors(im, ...)
3433         Imager::ImgRaw  im
3434       PREINIT:
3435         int index;
3436         i_color *colors;
3437         int i;
3438       CODE:
3439         if (items < 2)
3440           croak("i_addcolors: no colors to add");
3441         colors = mymalloc((items-1) * sizeof(i_color));
3442         for (i=0; i < items-1; ++i) {
3443           if (sv_isobject(ST(i+1)) 
3444               && sv_derived_from(ST(i+1), "Imager::Color")) {
3445             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3446             colors[i] = *INT2PTR(i_color *, tmp);
3447           }
3448           else {
3449             myfree(colors);
3450             croak("i_addcolor: pixels must be Imager::Color objects");
3451           }
3452         }
3453         index = i_addcolors(im, colors, items-1);
3454         myfree(colors);
3455         if (index == 0) {
3456           RETVAL = newSVpv("0 but true", 0);
3457         }
3458         else if (index == -1) {
3459           RETVAL = &PL_sv_undef;
3460         }
3461         else {
3462           RETVAL = newSViv(index);
3463         }
3464       OUTPUT:
3465         RETVAL
3466
3467 undef_int 
3468 i_setcolors(im, index, ...)
3469         Imager::ImgRaw  im
3470         int index
3471       PREINIT:
3472         i_color *colors;
3473         int i;
3474       CODE:
3475         if (items < 3)
3476           croak("i_setcolors: no colors to add");
3477         colors = mymalloc((items-2) * sizeof(i_color));
3478         for (i=0; i < items-2; ++i) {
3479           if (sv_isobject(ST(i+2)) 
3480               && sv_derived_from(ST(i+2), "Imager::Color")) {
3481             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3482             colors[i] = *INT2PTR(i_color *, tmp);
3483           }
3484           else {
3485             myfree(colors);
3486             croak("i_setcolors: pixels must be Imager::Color objects");
3487           }
3488         }
3489         RETVAL = i_setcolors(im, index, colors, items-2);
3490         myfree(colors);
3491       OUTPUT:
3492         RETVAL
3493
3494 void
3495 i_getcolors(im, index, ...)
3496         Imager::ImgRaw im
3497         int index
3498       PREINIT:
3499         i_color *colors;
3500         int count = 1;
3501         int i;
3502       PPCODE:
3503         if (items > 3)
3504           croak("i_getcolors: too many arguments");
3505         if (items == 3)
3506           count = SvIV(ST(2));
3507         if (count < 1)
3508           croak("i_getcolors: count must be positive");
3509         colors = mymalloc(sizeof(i_color) * count);
3510         if (i_getcolors(im, index, colors, count)) {
3511           for (i = 0; i < count; ++i) {
3512             i_color *pv;
3513             SV *sv = sv_newmortal();
3514             pv = mymalloc(sizeof(i_color));
3515             *pv = colors[i];
3516             sv_setref_pv(sv, "Imager::Color", (void *)pv);
3517             PUSHs(sv);
3518           }
3519         }
3520         myfree(colors);
3521
3522
3523 undef_neg_int
3524 i_colorcount(im)
3525         Imager::ImgRaw im
3526
3527 undef_neg_int
3528 i_maxcolors(im)
3529         Imager::ImgRaw im
3530
3531 SV *
3532 i_findcolor(im, color)
3533         Imager::ImgRaw im
3534         Imager::Color color
3535       PREINIT:
3536         i_palidx index;
3537       CODE:
3538         if (i_findcolor(im, color, &index)) {
3539           RETVAL = newSViv(index);
3540         }
3541         else {
3542           RETVAL = &PL_sv_undef;
3543         }
3544       OUTPUT:
3545         RETVAL
3546
3547 int
3548 i_img_bits(im)
3549         Imager::ImgRaw  im
3550
3551 int
3552 i_img_type(im)
3553         Imager::ImgRaw  im
3554
3555 int
3556 i_img_virtual(im)
3557         Imager::ImgRaw  im
3558
3559 void
3560 i_gsamp(im, l, r, y, ...)
3561         Imager::ImgRaw im
3562         int l
3563         int r
3564         int y
3565       PREINIT:
3566         int *chans;
3567         int chan_count;
3568         i_sample_t *data;
3569         int count, i;
3570       PPCODE:
3571         if (items < 5)
3572           croak("No channel numbers supplied to g_samp()");
3573         if (l < r) {
3574           chan_count = items - 4;
3575           chans = mymalloc(sizeof(int) * chan_count);
3576           for (i = 0; i < chan_count; ++i)
3577             chans[i] = SvIV(ST(i+4));
3578           data = mymalloc(sizeof(i_sample_t) * (r-l) * chan_count); /* XXX: memleak? */
3579           count = i_gsamp(im, l, r, y, data, chans, chan_count);
3580           myfree(chans);
3581           if (GIMME_V == G_ARRAY) {
3582             EXTEND(SP, count);
3583             for (i = 0; i < count; ++i)
3584               PUSHs(sv_2mortal(newSViv(data[i])));
3585           }
3586           else {
3587             EXTEND(SP, 1);
3588             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3589           }
3590           myfree(data);
3591         }
3592         else {
3593           if (GIMME_V != G_ARRAY) {
3594             EXTEND(SP, 1);
3595             PUSHs(&PL_sv_undef);
3596           }
3597         }
3598
3599
3600 Imager::ImgRaw
3601 i_img_masked_new(targ, mask, x, y, w, h)
3602         Imager::ImgRaw targ
3603         int x
3604         int y
3605         int w
3606         int h
3607       PREINIT:
3608         i_img *mask;
3609       CODE:
3610         if (SvOK(ST(1))) {
3611           if (!sv_isobject(ST(1)) 
3612               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3613             croak("i_img_masked_new: parameter 2 must undef or an image");
3614           }
3615           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3616         }
3617         else
3618           mask = NULL;
3619         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3620       OUTPUT:
3621         RETVAL
3622
3623 int
3624 i_plin(im, l, y, ...)
3625         Imager::ImgRaw  im
3626         int     l
3627         int     y
3628       PREINIT:
3629         i_color *work;
3630         int i;
3631         STRLEN len;
3632         int count;
3633       CODE:
3634         if (items > 3) {
3635           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3636             /* supplied as a byte string */
3637             work = (i_color *)SvPV(ST(3), len);
3638             count = len / sizeof(i_color);
3639             if (count * sizeof(i_color) != len) {
3640               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3641             }
3642             RETVAL = i_plin(im, l, l+count, y, work);
3643           }
3644           else {
3645             work = mymalloc(sizeof(i_color) * (items-3));
3646             for (i=0; i < items-3; ++i) {
3647               if (sv_isobject(ST(i+3)) 
3648                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3649                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3650                 work[i] = *INT2PTR(i_color *, tmp);
3651               }
3652               else {
3653                 myfree(work);
3654                 croak("i_plin: pixels must be Imager::Color objects");
3655               }
3656             }
3657             RETVAL = i_plin(im, l, l+items-3, y, work);
3658             myfree(work);
3659           }
3660         }
3661         else {
3662           RETVAL = 0;
3663         }
3664       OUTPUT:
3665         RETVAL
3666
3667 int
3668 i_ppixf(im, x, y, cl)
3669         Imager::ImgRaw im
3670         int x
3671         int y
3672         Imager::Color::Float cl
3673
3674 void
3675 i_gsampf(im, l, r, y, ...)
3676         Imager::ImgRaw im
3677         int l
3678         int r
3679         int y
3680       PREINIT:
3681         int *chans;
3682         int chan_count;
3683         i_fsample_t *data;
3684         int count, i;
3685       PPCODE:
3686         if (items < 5)
3687           croak("No channel numbers supplied to g_sampf()");
3688         if (l < r) {
3689           chan_count = items - 4;
3690           chans = mymalloc(sizeof(int) * chan_count);
3691           for (i = 0; i < chan_count; ++i)
3692             chans[i] = SvIV(ST(i+4));
3693           data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count);
3694           count = i_gsampf(im, l, r, y, data, chans, chan_count);
3695           myfree(chans);
3696           if (GIMME_V == G_ARRAY) {
3697             EXTEND(SP, count);
3698             for (i = 0; i < count; ++i)
3699               PUSHs(sv_2mortal(newSVnv(data[i])));
3700           }
3701           else {
3702             EXTEND(SP, 1);
3703             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3704           }
3705           myfree(data);
3706         }
3707         else {
3708           if (GIMME_V != G_ARRAY) {
3709             EXTEND(SP, 1);
3710             PUSHs(&PL_sv_undef);
3711           }
3712         }
3713
3714 int
3715 i_plinf(im, l, y, ...)
3716         Imager::ImgRaw  im
3717         int     l
3718         int     y
3719       PREINIT:
3720         i_fcolor *work;
3721         int i;
3722         STRLEN len;
3723         int count;
3724       CODE:
3725         if (items > 3) {
3726           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3727             /* supplied as a byte string */
3728             work = (i_fcolor *)SvPV(ST(3), len);
3729             count = len / sizeof(i_fcolor);
3730             if (count * sizeof(i_fcolor) != len) {
3731               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3732             }
3733             RETVAL = i_plinf(im, l, l+count, y, work);
3734           }
3735           else {
3736             work = mymalloc(sizeof(i_fcolor) * (items-3));
3737             for (i=0; i < items-3; ++i) {
3738               if (sv_isobject(ST(i+3)) 
3739                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3740                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3741                 work[i] = *INT2PTR(i_fcolor *, tmp);
3742               }
3743               else {
3744                 myfree(work);
3745                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3746               }
3747             }
3748             /**(char *)0 = 1;*/
3749             RETVAL = i_plinf(im, l, l+items-3, y, work);
3750             myfree(work);
3751           }
3752         }
3753         else {
3754           RETVAL = 0;
3755         }
3756       OUTPUT:
3757         RETVAL
3758
3759 SV *
3760 i_gpixf(im, x, y)
3761         Imager::ImgRaw im
3762         int x
3763         int y;
3764       PREINIT:
3765         i_fcolor *color;
3766       CODE:
3767         color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3768         if (i_gpixf(im, x, y, color) == 0) {
3769           RETVAL = NEWSV(0,0);
3770           sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
3771         }
3772         else {
3773           myfree(color);
3774           RETVAL = &PL_sv_undef;
3775         }
3776       OUTPUT:
3777         RETVAL
3778
3779 void
3780 i_glin(im, l, r, y)
3781         Imager::ImgRaw im
3782         int l
3783         int r
3784         int y
3785       PREINIT:
3786         i_color *vals;
3787         int count, i;
3788       PPCODE:
3789         if (l < r) {
3790           vals = mymalloc((r-l) * sizeof(i_color));
3791           count = i_glin(im, l, r, y, vals);
3792           if (GIMME_V == G_ARRAY) {
3793             EXTEND(SP, count);
3794             for (i = 0; i < count; ++i) {
3795               SV *sv;
3796               i_color *col = mymalloc(sizeof(i_color));
3797               *col = vals[i];
3798               sv = sv_newmortal();
3799               sv_setref_pv(sv, "Imager::Color", (void *)col);
3800               PUSHs(sv);
3801             }
3802           }
3803           else if (count) {
3804             EXTEND(SP, 1);
3805             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3806           }
3807           myfree(vals);
3808         }
3809
3810 void
3811 i_glinf(im, l, r, y)
3812         Imager::ImgRaw im
3813         int l
3814         int r
3815         int y
3816       PREINIT:
3817         i_fcolor *vals;
3818         int count, i;
3819       PPCODE:
3820         if (l < r) {
3821           vals = mymalloc((r-l) * sizeof(i_fcolor));
3822           count = i_glinf(im, l, r, y, vals);
3823           if (GIMME_V == G_ARRAY) {
3824             EXTEND(SP, count);
3825             for (i = 0; i < count; ++i) {
3826               SV *sv;
3827               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3828               *col = vals[i];
3829               sv = sv_newmortal();
3830               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3831               PUSHs(sv);
3832             }
3833           }
3834           else if (count) {
3835             EXTEND(SP, 1);
3836             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3837           }
3838           myfree(vals);
3839         }
3840
3841 Imager::ImgRaw
3842 i_img_16_new(x, y, ch)
3843         int x
3844         int y
3845         int ch
3846
3847 Imager::ImgRaw
3848 i_img_double_new(x, y, ch)
3849         int x
3850         int y
3851         int ch
3852
3853 undef_int
3854 i_tags_addn(im, name, code, idata)
3855         Imager::ImgRaw im
3856         int     code
3857         int     idata
3858       PREINIT:
3859         char *name;
3860         STRLEN len;
3861       CODE:
3862         if (SvOK(ST(1)))
3863           name = SvPV(ST(1), len);
3864         else
3865           name = NULL;
3866         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3867       OUTPUT:
3868         RETVAL
3869
3870 undef_int
3871 i_tags_add(im, name, code, data, idata)
3872         Imager::ImgRaw  im
3873         int code
3874         int idata
3875       PREINIT:
3876         char *name;
3877         char *data;
3878         STRLEN len;
3879       CODE:
3880         if (SvOK(ST(1)))
3881           name = SvPV(ST(1), len);
3882         else
3883           name = NULL;
3884         if (SvOK(ST(3)))
3885           data = SvPV(ST(3), len);
3886         else {
3887           data = NULL;
3888           len = 0;
3889         }
3890         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3891       OUTPUT:
3892         RETVAL
3893
3894 SV *
3895 i_tags_find(im, name, start)
3896         Imager::ImgRaw  im
3897         char *name
3898         int start
3899       PREINIT:
3900         int entry;
3901       CODE:
3902         if (i_tags_find(&im->tags, name, start, &entry)) {
3903           if (entry == 0)
3904             RETVAL = newSVpv("0 but true", 0);
3905           else
3906             RETVAL = newSViv(entry);
3907         } else {
3908           RETVAL = &PL_sv_undef;
3909         }
3910       OUTPUT:
3911         RETVAL
3912
3913 SV *
3914 i_tags_findn(im, code, start)
3915         Imager::ImgRaw  im
3916         int             code
3917         int             start
3918       PREINIT:
3919         int entry;
3920       CODE:
3921         if (i_tags_findn(&im->tags, code, start, &entry)) {
3922           if (entry == 0)
3923             RETVAL = newSVpv("0 but true", 0);
3924           else
3925             RETVAL = newSViv(entry);
3926         }
3927         else {
3928           RETVAL = &PL_sv_undef;
3929         }
3930       OUTPUT:
3931         RETVAL
3932
3933 int
3934 i_tags_delete(im, entry)
3935         Imager::ImgRaw  im
3936         int             entry
3937       CODE:
3938         RETVAL = i_tags_delete(&im->tags, entry);
3939       OUTPUT:
3940         RETVAL
3941
3942 int
3943 i_tags_delbyname(im, name)
3944         Imager::ImgRaw  im
3945         char *          name
3946       CODE:
3947         RETVAL = i_tags_delbyname(&im->tags, name);
3948       OUTPUT:
3949         RETVAL
3950
3951 int
3952 i_tags_delbycode(im, code)
3953         Imager::ImgRaw  im
3954         int             code
3955       CODE:
3956         RETVAL = i_tags_delbycode(&im->tags, code);
3957       OUTPUT:
3958         RETVAL
3959
3960 void
3961 i_tags_get(im, index)
3962         Imager::ImgRaw  im
3963         int             index
3964       PPCODE:
3965         if (index >= 0 && index < im->tags.count) {
3966           i_img_tag *entry = im->tags.tags + index;
3967           EXTEND(SP, 5);
3968         
3969           if (entry->name) {
3970             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3971           }
3972           else {
3973             PUSHs(sv_2mortal(newSViv(entry->code)));
3974           }
3975           if (entry->data) {
3976             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3977           }
3978           else {
3979             PUSHs(sv_2mortal(newSViv(entry->idata)));
3980           }
3981         }
3982
3983 void
3984 i_tags_get_string(im, what_sv)
3985         Imager::ImgRaw  im
3986         SV *what_sv
3987       PREINIT:
3988         char const *name = NULL;
3989         int code;
3990         char buffer[200];
3991       PPCODE:
3992         if (SvIOK(what_sv)) {
3993           code = SvIV(what_sv);
3994           name = NULL;
3995         }
3996         else {
3997           name = SvPV_nolen(what_sv);
3998           code = 0;
3999         }
4000         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
4001           EXTEND(SP, 1);
4002           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
4003         }
4004
4005 int
4006 i_tags_count(im)
4007         Imager::ImgRaw  im
4008       CODE:
4009         RETVAL = im->tags.count;
4010       OUTPUT:
4011         RETVAL
4012
4013 #ifdef HAVE_WIN32
4014
4015 void
4016 i_wf_bbox(face, size, text)
4017         char *face
4018         int size
4019         char *text
4020       PREINIT:
4021         int cords[BOUNDING_BOX_COUNT];
4022         int rc, i;
4023       PPCODE:
4024         if (rc = i_wf_bbox(face, size, text, strlen(text), cords)) {
4025           EXTEND(SP, rc);  
4026           for (i = 0; i < rc; ++i) 
4027             PUSHs(sv_2mortal(newSViv(cords[i])));
4028         }
4029
4030 undef_int
4031 i_wf_text(face, im, tx, ty, cl, size, text, align, aa)
4032         char *face
4033         Imager::ImgRaw im
4034         int tx
4035         int ty
4036         Imager::Color cl
4037         int size
4038         char *text
4039         int align
4040         int aa
4041       CODE:
4042         RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text), 
4043                            align, aa);
4044       OUTPUT:
4045         RETVAL
4046
4047 undef_int
4048 i_wf_cp(face, im, tx, ty, channel, size, text, align, aa)
4049         char *face
4050         Imager::ImgRaw im
4051         int tx
4052         int ty
4053         int channel
4054         int size
4055         char *text
4056         int align
4057         int aa
4058       CODE:
4059         RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text), 
4060                          align, aa);
4061       OUTPUT:
4062         RETVAL
4063
4064 undef_int
4065 i_wf_addfont(font)
4066         char *font
4067
4068 #endif
4069
4070 #ifdef HAVE_FT2
4071
4072 MODULE = Imager         PACKAGE = Imager::Font::FT2     PREFIX=FT2_
4073
4074 #define FT2_DESTROY(font) i_ft2_destroy(font)
4075
4076 void
4077 FT2_DESTROY(font)
4078         Imager::Font::FT2 font
4079
4080 MODULE = Imager         PACKAGE = Imager::Font::FreeType2 
4081
4082 Imager::Font::FT2
4083 i_ft2_new(name, index)
4084         char *name
4085         int index
4086
4087 undef_int
4088 i_ft2_setdpi(font, xdpi, ydpi)
4089         Imager::Font::FT2 font
4090         int xdpi
4091         int ydpi
4092
4093 void
4094 i_ft2_getdpi(font)
4095         Imager::Font::FT2 font
4096       PREINIT:
4097         int xdpi, ydpi;
4098       CODE:
4099         if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
4100           EXTEND(SP, 2);
4101           PUSHs(sv_2mortal(newSViv(xdpi)));
4102           PUSHs(sv_2mortal(newSViv(ydpi)));
4103         }
4104
4105 undef_int
4106 i_ft2_sethinting(font, hinting)
4107         Imager::Font::FT2 font
4108         int hinting
4109
4110 undef_int
4111 i_ft2_settransform(font, matrix)
4112         Imager::Font::FT2 font
4113       PREINIT:
4114         double matrix[6];
4115         int len;
4116         AV *av;
4117         SV *sv1;
4118         int i;
4119       CODE:
4120         if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4121           croak("i_ft2_settransform: parameter 2 must be an array ref\n");
4122         av=(AV*)SvRV(ST(1));
4123         len=av_len(av)+1;
4124         if (len > 6)
4125           len = 6;
4126         for (i = 0; i < len; ++i) {
4127           sv1=(*(av_fetch(av,i,0)));
4128           matrix[i] = SvNV(sv1);
4129         }
4130         for (; i < 6; ++i)
4131           matrix[i] = 0;
4132         RETVAL = i_ft2_settransform(font, matrix);
4133       OUTPUT:
4134         RETVAL
4135
4136 void
4137 i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
4138         Imager::Font::FT2 font
4139         double cheight
4140         double cwidth
4141         SV *text_sv
4142         int utf8
4143       PREINIT:
4144         int bbox[BOUNDING_BOX_COUNT];
4145         int i;
4146         char *text;
4147         STRLEN text_len;
4148         int rc;
4149       PPCODE:
4150         text = SvPV(text_sv, text_len);
4151 #ifdef SvUTF8
4152         if (SvUTF8(text_sv))
4153           utf8 = 1;
4154 #endif
4155         rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8);
4156         if (rc) {
4157           EXTEND(SP, rc);
4158           for (i = 0; i < rc; ++i)
4159             PUSHs(sv_2mortal(newSViv(bbox[i])));
4160         }
4161
4162 void
4163 i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
4164         Imager::Font::FT2 font
4165         double cheight
4166         double cwidth
4167         char *text
4168         int vlayout
4169         int utf8
4170       PREINIT:
4171         int bbox[8];
4172         int i;
4173       PPCODE:
4174 #ifdef SvUTF8
4175         if (SvUTF8(ST(3)))
4176           utf8 = 1;
4177 #endif
4178         if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
4179                          utf8, bbox)) {
4180           EXTEND(SP, 8);
4181           for (i = 0; i < 8; ++i)
4182             PUSHs(sv_2mortal(newSViv(bbox[i])));
4183         }
4184
4185 undef_int
4186 i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
4187         Imager::Font::FT2 font
4188         Imager::ImgRaw im
4189         int tx
4190         int ty
4191         Imager::Color cl
4192         double cheight
4193         double cwidth
4194         int align
4195         int aa
4196         int vlayout
4197         int utf8
4198       PREINIT:
4199         char *text;
4200         STRLEN len;
4201       CODE:
4202 #ifdef SvUTF8
4203         if (SvUTF8(ST(7))) {
4204           utf8 = 1;
4205         }
4206 #endif
4207         text = SvPV(ST(7), len);
4208         RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
4209                             len, align, aa, vlayout, utf8);
4210       OUTPUT:
4211         RETVAL
4212
4213 undef_int
4214 i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8)
4215         Imager::Font::FT2 font
4216         Imager::ImgRaw im
4217         int tx
4218         int ty
4219         int channel
4220         double cheight
4221         double cwidth
4222         char *text
4223         int align
4224         int aa
4225         int vlayout
4226         int utf8
4227       CODE:
4228 #ifdef SvUTF8
4229         if (SvUTF8(ST(7)))
4230           utf8 = 1;
4231 #endif
4232         RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
4233                           strlen(text), align, aa, vlayout, 1);
4234       OUTPUT:
4235         RETVAL
4236
4237 void
4238 ft2_transform_box(font, x0, x1, x2, x3)
4239         Imager::Font::FT2 font
4240         int x0
4241         int x1
4242         int x2
4243         int x3
4244       PREINIT:
4245         int box[4];
4246       PPCODE:
4247         box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
4248         ft2_transform_box(font, box);
4249           EXTEND(SP, 4);
4250           PUSHs(sv_2mortal(newSViv(box[0])));
4251           PUSHs(sv_2mortal(newSViv(box[1])));
4252           PUSHs(sv_2mortal(newSViv(box[2])));
4253           PUSHs(sv_2mortal(newSViv(box[3])));
4254
4255 void
4256 i_ft2_has_chars(handle, text_sv, utf8)
4257         Imager::Font::FT2 handle
4258         SV  *text_sv
4259         int utf8
4260       PREINIT:
4261         char *text;
4262         STRLEN len;
4263         char *work;
4264         int count;
4265         int i;
4266       PPCODE:
4267 #ifdef SvUTF8
4268         if (SvUTF8(text_sv))
4269           utf8 = 1;
4270 #endif
4271         text = SvPV(text_sv, len);
4272         work = mymalloc(len);
4273         count = i_ft2_has_chars(handle, text, len, utf8, work);
4274         if (GIMME_V == G_ARRAY) {
4275           EXTEND(SP, count);
4276           for (i = 0; i < count; ++i) {
4277             PUSHs(sv_2mortal(newSViv(work[i])));
4278           }
4279         }
4280         else {
4281           EXTEND(SP, 1);
4282           PUSHs(sv_2mortal(newSVpv(work, count)));
4283         }
4284         myfree(work);
4285
4286 void
4287 i_ft2_face_name(handle)
4288         Imager::Font::FT2 handle
4289       PREINIT:
4290         char name[255];
4291         int len;
4292       PPCODE:
4293         len = i_ft2_face_name(handle, name, sizeof(name));
4294         if (len) {
4295           EXTEND(SP, 1);
4296           PUSHs(sv_2mortal(newSVpv(name, 0)));
4297         }
4298
4299 undef_int
4300 i_ft2_can_face_name()
4301
4302 void
4303 i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
4304         Imager::Font::FT2 handle
4305         SV *text_sv
4306         int utf8
4307         int reliable_only
4308       PREINIT:
4309         char const *text;
4310         STRLEN work_len;
4311         int len;
4312         char name[255];
4313       PPCODE:
4314 #ifdef SvUTF8
4315         if (SvUTF8(text_sv))
4316           utf8 = 1;
4317 #endif
4318         text = SvPV(text_sv, work_len);
4319         len = work_len;
4320         while (len) {
4321           unsigned long ch;
4322           if (utf8) {
4323             ch = i_utf8_advance(&text, &len);
4324             if (ch == ~0UL) {
4325               i_push_error(0, "invalid UTF8 character");
4326               break;
4327             }
4328           }
4329           else {
4330             ch = *text++;
4331             --len;
4332           }
4333           EXTEND(SP, 1);
4334           if (i_ft2_glyph_name(handle, ch, name, sizeof(name), 
4335                                          reliable_only)) {
4336             PUSHs(sv_2mortal(newSVpv(name, 0)));
4337           }
4338           else {
4339             PUSHs(&PL_sv_undef);
4340           } 
4341         }
4342
4343 int
4344 i_ft2_can_do_glyph_names()
4345
4346 int
4347 i_ft2_face_has_glyph_names(handle)
4348         Imager::Font::FT2 handle
4349
4350 int
4351 i_ft2_is_multiple_master(handle)
4352         Imager::Font::FT2 handle
4353
4354 void
4355 i_ft2_get_multiple_masters(handle)
4356         Imager::Font::FT2 handle
4357       PREINIT:
4358         i_font_mm mm;
4359         int i;
4360       PPCODE:
4361         if (i_ft2_get_multiple_masters(handle, &mm)) {
4362           EXTEND(SP, 2+mm.num_axis);
4363           PUSHs(sv_2mortal(newSViv(mm.num_axis)));
4364           PUSHs(sv_2mortal(newSViv(mm.num_designs)));
4365           for (i = 0; i < mm.num_axis; ++i) {
4366             AV *av = newAV();
4367             SV *sv;
4368             av_extend(av, 3);
4369             sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name));
4370             SvREFCNT_inc(sv);
4371             av_store(av, 0, sv);
4372             sv = newSViv(mm.axis[i].minimum);
4373             SvREFCNT_inc(sv);
4374             av_store(av, 1, sv);
4375             sv = newSViv(mm.axis[i].maximum);
4376             SvREFCNT_inc(sv);
4377             av_store(av, 2, sv);
4378             PUSHs(newRV_noinc((SV *)av));
4379           }
4380         }
4381
4382 undef_int
4383 i_ft2_set_mm_coords(handle, ...)
4384         Imager::Font::FT2 handle
4385       PROTOTYPE: DISABLE
4386       PREINIT:
4387         long *coords;
4388         int ix_coords, i;
4389       CODE:
4390         /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so
4391            transfer the array manually */
4392         ix_coords = items-1;
4393         coords = mymalloc(sizeof(long) * ix_coords);
4394         for (i = 0; i < ix_coords; ++i) {
4395           coords[i] = (long)SvIV(ST(1+i));
4396         }
4397         RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords);
4398         myfree(coords);
4399       OUTPUT:
4400         RETVAL
4401
4402 #endif
4403
4404 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
4405
4406 void
4407 IFILL_DESTROY(fill)
4408         Imager::FillHandle fill
4409
4410 MODULE = Imager         PACKAGE = Imager
4411
4412 Imager::FillHandle
4413 i_new_fill_solid(cl, combine)
4414         Imager::Color cl
4415         int combine
4416
4417 Imager::FillHandle
4418 i_new_fill_solidf(cl, combine)
4419         Imager::Color::Float cl
4420         int combine
4421
4422 Imager::FillHandle
4423 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
4424         Imager::Color fg
4425         Imager::Color bg
4426         int combine
4427         int hatch
4428         int dx
4429         int dy
4430       PREINIT:
4431         unsigned char *cust_hatch;
4432         STRLEN len;
4433       CODE:
4434         if (SvOK(ST(4))) {
4435           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4436         }
4437         else
4438           cust_hatch = NULL;
4439         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
4440       OUTPUT:
4441         RETVAL
4442
4443 Imager::FillHandle
4444 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
4445         Imager::Color::Float fg
4446         Imager::Color::Float bg
4447         int combine
4448         int hatch
4449         int dx
4450         int dy
4451       PREINIT:
4452         unsigned char *cust_hatch;
4453         STRLEN len;
4454       CODE:
4455         if (SvOK(ST(4))) {
4456           cust_hatch = (unsigned char *)SvPV(ST(4), len);
4457         }
4458         else
4459           cust_hatch = NULL;
4460         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
4461       OUTPUT:
4462         RETVAL
4463
4464 Imager::FillHandle
4465 i_new_fill_image(src, matrix, xoff, yoff, combine)
4466         Imager::ImgRaw src
4467         int xoff
4468         int yoff
4469         int combine
4470       PREINIT:
4471         double matrix[9];
4472         double *matrixp;
4473         AV *av;
4474         IV len;
4475         SV *sv1;
4476         int i;
4477       CODE:
4478         if (!SvOK(ST(1))) {
4479           matrixp = NULL;
4480         }
4481         else {
4482           if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
4483             croak("i_new_fill_image: parameter must be an arrayref");
4484           av=(AV*)SvRV(ST(1));
4485           len=av_len(av)+1;
4486           if (len > 9)
4487             len = 9;
4488           for (i = 0; i < len; ++i) {
4489             sv1=(*(av_fetch(av,i,0)));
4490             matrix[i] = SvNV(sv1);
4491           }
4492           for (; i < 9; ++i)
4493             matrix[i] = 0;
4494           matrixp = matrix;
4495         }
4496         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4497       OUTPUT:
4498         RETVAL
4499
4500 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
4501
4502 # this class is only exposed for testing
4503
4504 int
4505 i_int_hlines_testing()
4506
4507 #if i_int_hlines_testing()
4508
4509 Imager::Internal::Hlines
4510 i_int_hlines_new(start_y, count_y, start_x, count_x)
4511         int start_y
4512         int count_y
4513         int start_x
4514         int count_x
4515
4516 Imager::Internal::Hlines
4517 i_int_hlines_new_img(im)
4518         Imager::ImgRaw im
4519
4520 void
4521 i_int_hlines_add(hlines, y, minx, width)
4522         Imager::Internal::Hlines hlines
4523         int y
4524         int minx
4525         int width
4526
4527 void
4528 i_int_hlines_DESTROY(hlines)
4529         Imager::Internal::Hlines hlines
4530
4531 SV *
4532 i_int_hlines_dump(hlines)
4533         Imager::Internal::Hlines hlines
4534
4535 #endif
4536
4537 BOOT:
4538         PERL_SET_GLOBAL_CALLBACKS;