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