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