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