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