re-work malloc_temp(), calloc_temp() to avoid SV overhead
[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         
3209
3210 void
3211 i_gpal(im, l, r, y)
3212         Imager::ImgRaw  im
3213         i_img_dim     l
3214         i_img_dim     r
3215         i_img_dim     y
3216       PREINIT:
3217         i_palidx *work;
3218         int count, i;
3219       PPCODE:
3220         if (l < r) {
3221           work = mymalloc((r-l) * sizeof(i_palidx));
3222           count = i_gpal(im, l, r, y, work);
3223           if (GIMME_V == G_ARRAY) {
3224             EXTEND(SP, count);
3225             for (i = 0; i < count; ++i) {
3226               PUSHs(sv_2mortal(newSViv(work[i])));
3227             }
3228           }
3229           else {
3230             EXTEND(SP, 1);
3231             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3232           }
3233           myfree(work);
3234         }
3235         else {
3236           if (GIMME_V != G_ARRAY) {
3237             EXTEND(SP, 1);
3238             PUSHs(&PL_sv_undef);
3239           }
3240         }
3241
3242 int
3243 i_ppal(im, l, y, ...)
3244         Imager::ImgRaw  im
3245         i_img_dim     l
3246         i_img_dim     y
3247       PREINIT:
3248         i_palidx *work;
3249         i_img_dim i;
3250       CODE:
3251         if (items > 3) {
3252           work = malloc_temp(aTHX_ sizeof(i_palidx) * (items-3));
3253           for (i=0; i < items-3; ++i) {
3254             work[i] = SvIV(ST(i+3));
3255           }
3256           validate_i_ppal(im, work, items - 3);
3257           RETVAL = i_ppal(im, l, l+items-3, y, work);
3258         }
3259         else {
3260           RETVAL = 0;
3261         }
3262       OUTPUT:
3263         RETVAL
3264
3265 int
3266 i_ppal_p(im, l, y, data)
3267         Imager::ImgRaw  im
3268         i_img_dim     l
3269         i_img_dim     y
3270         SV *data
3271       PREINIT:
3272         i_palidx const *work;
3273         STRLEN len;
3274       CODE:
3275         work = (i_palidx const *)SvPV(data, len);
3276         len /= sizeof(i_palidx);
3277         if (len > 0) {
3278           validate_i_ppal(im, work, len);
3279           RETVAL = i_ppal(im, l, l+len, y, work);
3280         }
3281         else {
3282           RETVAL = 0;
3283         }
3284       OUTPUT:
3285         RETVAL
3286
3287 SysRet
3288 i_addcolors(im, ...)
3289         Imager::ImgRaw  im
3290       PREINIT:
3291         i_color *colors;
3292         int i;
3293       CODE:
3294         if (items < 2)
3295           croak("i_addcolors: no colors to add");
3296         colors = mymalloc((items-1) * sizeof(i_color));
3297         for (i=0; i < items-1; ++i) {
3298           if (sv_isobject(ST(i+1)) 
3299               && sv_derived_from(ST(i+1), "Imager::Color")) {
3300             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3301             colors[i] = *INT2PTR(i_color *, tmp);
3302           }
3303           else {
3304             myfree(colors);
3305             croak("i_addcolor: pixels must be Imager::Color objects");
3306           }
3307         }
3308         RETVAL = i_addcolors(im, colors, items-1);
3309         myfree(colors);
3310       OUTPUT:
3311         RETVAL
3312
3313 undef_int 
3314 i_setcolors(im, index, ...)
3315         Imager::ImgRaw  im
3316         int index
3317       PREINIT:
3318         i_color *colors;
3319         int i;
3320       CODE:
3321         if (items < 3)
3322           croak("i_setcolors: no colors to add");
3323         colors = mymalloc((items-2) * sizeof(i_color));
3324         for (i=0; i < items-2; ++i) {
3325           if (sv_isobject(ST(i+2)) 
3326               && sv_derived_from(ST(i+2), "Imager::Color")) {
3327             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3328             colors[i] = *INT2PTR(i_color *, tmp);
3329           }
3330           else {
3331             myfree(colors);
3332             croak("i_setcolors: pixels must be Imager::Color objects");
3333           }
3334         }
3335         RETVAL = i_setcolors(im, index, colors, items-2);
3336         myfree(colors);
3337       OUTPUT:
3338         RETVAL
3339
3340 void
3341 i_getcolors(im, index, count=1)
3342         Imager::ImgRaw im
3343         int index
3344         int count
3345       PREINIT:
3346         i_color *colors;
3347         int i;
3348       PPCODE:
3349         if (count < 1)
3350           croak("i_getcolors: count must be positive");
3351         colors = malloc_temp(aTHX_ sizeof(i_color) * count);
3352         if (i_getcolors(im, index, colors, count)) {
3353           EXTEND(SP, count);
3354           for (i = 0; i < count; ++i) {
3355             SV *sv = make_i_color_sv(aTHX_ colors+i);
3356             PUSHs(sv);
3357           }
3358         }
3359
3360 undef_neg_int
3361 i_colorcount(im)
3362         Imager::ImgRaw im
3363
3364 undef_neg_int
3365 i_maxcolors(im)
3366         Imager::ImgRaw im
3367
3368 i_palidx
3369 i_findcolor(im, color)
3370         Imager::ImgRaw im
3371         Imager::Color color
3372       CODE:
3373         if (!i_findcolor(im, color, &RETVAL)) {
3374           XSRETURN_UNDEF;
3375         }
3376       OUTPUT:
3377         RETVAL
3378
3379 int
3380 i_img_bits(im)
3381         Imager::ImgRaw  im
3382
3383 int
3384 i_img_type(im)
3385         Imager::ImgRaw  im
3386
3387 int
3388 i_img_virtual(im)
3389         Imager::ImgRaw  im
3390
3391 void
3392 i_gsamp(im, l, r, y, channels)
3393         Imager::ImgRaw im
3394         i_img_dim l
3395         i_img_dim r
3396         i_img_dim y
3397         i_channel_list channels
3398       PREINIT:
3399         i_sample_t *data;
3400         i_img_dim count, i;
3401       PPCODE:
3402         if (l < r) {
3403           data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count);
3404           count = i_gsamp(im, l, r, y, data, channels.channels, channels.count);
3405           if (GIMME_V == G_ARRAY) {
3406             EXTEND(SP, count);
3407             for (i = 0; i < count; ++i)
3408               PUSHs(sv_2mortal(newSViv(data[i])));
3409           }
3410           else {
3411             EXTEND(SP, 1);
3412             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3413           }
3414           myfree(data);
3415         }
3416         else {
3417           if (GIMME_V != G_ARRAY) {
3418             XSRETURN_UNDEF;
3419           }
3420         }
3421
3422 undef_neg_int
3423 i_gsamp_bits(im, l, r, y, bits, target, offset, channels)
3424         Imager::ImgRaw im
3425         i_img_dim l
3426         i_img_dim r
3427         i_img_dim y
3428         int bits
3429         AV *target
3430         STRLEN offset
3431         i_channel_list channels
3432       PREINIT:
3433         unsigned *data;
3434         i_img_dim count, i;
3435       CODE:
3436         i_clear_error();
3437         if (items < 8)
3438           croak("No channel numbers supplied to g_samp()");
3439         if (l < r) {
3440           data = mymalloc(sizeof(unsigned) * (r-l) * channels.count);
3441           count = i_gsamp_bits(im, l, r, y, data, channels.channels, channels.count, bits);
3442           for (i = 0; i < count; ++i) {
3443             av_store(target, i+offset, newSVuv(data[i]));
3444           }
3445           myfree(data);
3446           RETVAL = count;
3447         }
3448         else {
3449           RETVAL = 0;
3450         }
3451       OUTPUT:
3452         RETVAL
3453
3454 undef_neg_int
3455 i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -1)
3456         Imager::ImgRaw im
3457         i_img_dim l
3458         i_img_dim y
3459         int bits
3460         i_channel_list channels
3461         AV *data_av
3462         i_img_dim data_offset
3463         i_img_dim pixel_count
3464       PREINIT:
3465         STRLEN data_count;
3466         size_t data_used;
3467         unsigned *data;
3468         ptrdiff_t i;
3469       CODE:
3470         i_clear_error();
3471
3472         data_count = av_len(data_av) + 1;
3473         if (data_offset < 0) {
3474           croak("data_offset must be non-negative");
3475         }
3476         if (data_offset > data_count) {
3477           croak("data_offset greater than number of samples supplied");
3478         }
3479         if (pixel_count == -1 || 
3480             data_offset + pixel_count * channels.count > data_count) {
3481           pixel_count = (data_count - data_offset) / channels.count;
3482         }
3483
3484         data_used = pixel_count * channels.count;
3485         data = mymalloc(sizeof(unsigned) * data_count);
3486         for (i = 0; i < data_used; ++i)
3487           data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0));
3488
3489         RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels.channels, 
3490                               channels.count, bits);
3491
3492         if (data)
3493           myfree(data);
3494       OUTPUT:
3495         RETVAL
3496
3497 undef_neg_int
3498 i_psamp(im, x, y, channels, data, offset = 0, width = -1)
3499         Imager::ImgRaw im
3500         i_img_dim x
3501         i_img_dim y
3502         i_channel_list channels
3503         i_sample_list data
3504         i_img_dim offset
3505         i_img_dim width
3506     PREINIT:
3507         i_img_dim r;
3508     CODE:
3509         i_clear_error();
3510         if (offset < 0) {
3511           i_push_error(0, "offset must be non-negative");
3512           XSRETURN_UNDEF;
3513         }
3514         if (offset > 0) {
3515           if (offset > data.count) {
3516             i_push_error(0, "offset greater than number of samples supplied");
3517             XSRETURN_UNDEF;
3518           }
3519           data.samples += offset;
3520           data.count -= offset;
3521         }
3522         if (width == -1 ||
3523             width * channels.count > data.count) {
3524           width = data.count / channels.count;
3525         }
3526         r = x + width;
3527         RETVAL = i_psamp(im, x, r, y, data.samples, channels.channels, channels.count);
3528     OUTPUT:
3529         RETVAL
3530
3531 undef_neg_int
3532 i_psampf(im, x, y, channels, data, offset = 0, width = -1)
3533         Imager::ImgRaw im
3534         i_img_dim x
3535         i_img_dim y
3536         i_channel_list channels
3537         i_fsample_list data
3538         i_img_dim offset
3539         i_img_dim width
3540     PREINIT:
3541         i_img_dim r;
3542     CODE:
3543         i_clear_error();
3544         if (offset < 0) {
3545           i_push_error(0, "offset must be non-negative");
3546           XSRETURN_UNDEF;
3547         }
3548         if (offset > 0) {
3549           if (offset > data.count) {
3550             i_push_error(0, "offset greater than number of samples supplied");
3551             XSRETURN_UNDEF;
3552           }
3553           data.samples += offset;
3554           data.count -= offset;
3555         }
3556         if (width == -1 ||
3557             width * channels.count > data.count) {
3558           width = data.count / channels.count;
3559         }
3560         r = x + width;
3561         RETVAL = i_psampf(im, x, r, y, data.samples, channels.channels, channels.count);
3562     OUTPUT:
3563         RETVAL
3564
3565 Imager::ImgRaw
3566 i_img_masked_new(targ, mask, x, y, w, h)
3567         Imager::ImgRaw targ
3568         i_img_dim x
3569         i_img_dim y
3570         i_img_dim w
3571         i_img_dim h
3572       PREINIT:
3573         i_img *mask;
3574       CODE:
3575         if (SvOK(ST(1))) {
3576           if (!sv_isobject(ST(1)) 
3577               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3578             croak("i_img_masked_new: parameter 2 must undef or an image");
3579           }
3580           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3581         }
3582         else
3583           mask = NULL;
3584         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3585       OUTPUT:
3586         RETVAL
3587
3588 int
3589 i_plin(im, l, y, ...)
3590         Imager::ImgRaw  im
3591         i_img_dim     l
3592         i_img_dim     y
3593       PREINIT:
3594         i_color *work;
3595         STRLEN i;
3596         STRLEN len;
3597         size_t count;
3598       CODE:
3599         if (items > 3) {
3600           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3601             /* supplied as a byte string */
3602             work = (i_color *)SvPV(ST(3), len);
3603             count = len / sizeof(i_color);
3604             if (count * sizeof(i_color) != len) {
3605               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3606             }
3607             RETVAL = i_plin(im, l, l+count, y, work);
3608           }
3609           else {
3610             work = mymalloc(sizeof(i_color) * (items-3));
3611             for (i=0; i < items-3; ++i) {
3612               if (sv_isobject(ST(i+3)) 
3613                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3614                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3615                 work[i] = *INT2PTR(i_color *, tmp);
3616               }
3617               else {
3618                 myfree(work);
3619                 croak("i_plin: pixels must be Imager::Color objects");
3620               }
3621             }
3622             RETVAL = i_plin(im, l, l+items-3, y, work);
3623             myfree(work);
3624           }
3625         }
3626         else {
3627           RETVAL = 0;
3628         }
3629       OUTPUT:
3630         RETVAL
3631
3632 int
3633 i_ppixf(im, x, y, cl)
3634         Imager::ImgRaw im
3635         i_img_dim x
3636         i_img_dim y
3637         Imager::Color::Float cl
3638
3639 void
3640 i_gsampf(im, l, r, y, channels)
3641         Imager::ImgRaw im
3642         i_img_dim l
3643         i_img_dim r
3644         i_img_dim y
3645         i_channel_list channels
3646       PREINIT:
3647         i_fsample_t *data;
3648         i_img_dim count, i;
3649       PPCODE:
3650         if (l < r) {
3651           data = mymalloc(sizeof(i_fsample_t) * (r-l) * channels.count);
3652           count = i_gsampf(im, l, r, y, data, channels.channels, channels.count);
3653           if (GIMME_V == G_ARRAY) {
3654             EXTEND(SP, count);
3655             for (i = 0; i < count; ++i)
3656               PUSHs(sv_2mortal(newSVnv(data[i])));
3657           }
3658           else {
3659             EXTEND(SP, 1);
3660             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3661           }
3662           myfree(data);
3663         }
3664         else {
3665           if (GIMME_V != G_ARRAY) {
3666             XSRETURN_UNDEF;
3667           }
3668         }
3669
3670 int
3671 i_plinf(im, l, y, ...)
3672         Imager::ImgRaw  im
3673         i_img_dim     l
3674         i_img_dim     y
3675       PREINIT:
3676         i_fcolor *work;
3677         i_img_dim i;
3678         STRLEN len;
3679         size_t count;
3680       CODE:
3681         if (items > 3) {
3682           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3683             /* supplied as a byte string */
3684             work = (i_fcolor *)SvPV(ST(3), len);
3685             count = len / sizeof(i_fcolor);
3686             if (count * sizeof(i_fcolor) != len) {
3687               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3688             }
3689             RETVAL = i_plinf(im, l, l+count, y, work);
3690           }
3691           else {
3692             work = mymalloc(sizeof(i_fcolor) * (items-3));
3693             for (i=0; i < items-3; ++i) {
3694               if (sv_isobject(ST(i+3)) 
3695                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3696                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3697                 work[i] = *INT2PTR(i_fcolor *, tmp);
3698               }
3699               else {
3700                 myfree(work);
3701                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3702               }
3703             }
3704             /**(char *)0 = 1;*/
3705             RETVAL = i_plinf(im, l, l+items-3, y, work);
3706             myfree(work);
3707           }
3708         }
3709         else {
3710           RETVAL = 0;
3711         }
3712       OUTPUT:
3713         RETVAL
3714
3715 Imager::Color::Float
3716 i_gpixf(im, x, y)
3717         Imager::ImgRaw im
3718         i_img_dim x
3719         i_img_dim y;
3720       CODE:
3721         RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3722         memset(RETVAL, 0, sizeof(*RETVAL));
3723         if (i_gpixf(im, x, y, RETVAL) != 0) {
3724           myfree(RETVAL);
3725           XSRETURN_UNDEF;
3726         }
3727       OUTPUT:
3728         RETVAL
3729
3730 void
3731 i_glin(im, l, r, y)
3732         Imager::ImgRaw im
3733         i_img_dim l
3734         i_img_dim r
3735         i_img_dim y
3736       PREINIT:
3737         i_color *vals;
3738         i_img_dim count, i;
3739       PPCODE:
3740         if (l < r) {
3741           vals = mymalloc((r-l) * sizeof(i_color));
3742           memset(vals, 0, (r-l) * sizeof(i_color));
3743           count = i_glin(im, l, r, y, vals);
3744           if (GIMME_V == G_ARRAY) {
3745             EXTEND(SP, count);
3746             for (i = 0; i < count; ++i) {
3747               SV *sv = make_i_color_sv(aTHX_ vals+i);
3748               PUSHs(sv);
3749             }
3750           }
3751           else if (count) {
3752             EXTEND(SP, 1);
3753             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3754           }
3755           myfree(vals);
3756         }
3757
3758 void
3759 i_glinf(im, l, r, y)
3760         Imager::ImgRaw im
3761         i_img_dim l
3762         i_img_dim r
3763         i_img_dim y
3764       PREINIT:
3765         i_fcolor *vals;
3766         i_img_dim count, i;
3767         i_fcolor zero;
3768       PPCODE:
3769         for (i = 0; i < MAXCHANNELS; ++i)
3770           zero.channel[i] = 0;
3771         if (l < r) {
3772           vals = mymalloc((r-l) * sizeof(i_fcolor));
3773           for (i = 0; i < r-l; ++i)
3774             vals[i] = zero;
3775           count = i_glinf(im, l, r, y, vals);
3776           if (GIMME_V == G_ARRAY) {
3777             EXTEND(SP, count);
3778             for (i = 0; i < count; ++i) {
3779               SV *sv;
3780               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3781               *col = vals[i];
3782               sv = sv_newmortal();
3783               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3784               PUSHs(sv);
3785             }
3786           }
3787           else if (count) {
3788             EXTEND(SP, 1);
3789             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3790           }
3791           myfree(vals);
3792         }
3793
3794 Imager::ImgRaw
3795 i_img_8_new(x, y, ch)
3796         i_img_dim x
3797         i_img_dim y
3798         int ch
3799
3800 Imager::ImgRaw
3801 i_img_16_new(x, y, ch)
3802         i_img_dim x
3803         i_img_dim y
3804         int ch
3805
3806 Imager::ImgRaw
3807 i_img_to_rgb16(im)
3808        Imager::ImgRaw im
3809
3810 Imager::ImgRaw
3811 i_img_double_new(x, y, ch)
3812         i_img_dim x
3813         i_img_dim y
3814         int ch
3815
3816 Imager::ImgRaw
3817 i_img_to_drgb(im)
3818        Imager::ImgRaw im
3819
3820 undef_int
3821 i_tags_addn(im, name_sv, code, idata)
3822         Imager::ImgRaw im
3823         SV *name_sv
3824         int     code
3825         int     idata
3826       PREINIT:
3827         char *name;
3828         STRLEN len;
3829       CODE:
3830         SvGETMAGIC(name_sv);
3831         if (SvOK(name_sv))
3832           name = SvPV_nomg(name_sv, len);
3833         else
3834           name = NULL;
3835         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3836       OUTPUT:
3837         RETVAL
3838
3839 undef_int
3840 i_tags_add(im, name_sv, code, data_sv, idata)
3841         Imager::ImgRaw  im
3842         SV *name_sv
3843         int code
3844         SV *data_sv
3845         int idata
3846       PREINIT:
3847         char *name;
3848         char *data;
3849         STRLEN len;
3850       CODE:
3851         SvGETMAGIC(name_sv);
3852         if (SvOK(name_sv))
3853           name = SvPV_nomg(name_sv, len);
3854         else
3855           name = NULL;
3856         SvGETMAGIC(data_sv);
3857         if (SvOK(data_sv))
3858           data = SvPV(data_sv, len);
3859         else {
3860           data = NULL;
3861           len = 0;
3862         }
3863         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3864       OUTPUT:
3865         RETVAL
3866
3867 SysRet
3868 i_tags_find(im, name, start)
3869         Imager::ImgRaw  im
3870         char *name
3871         int start
3872       PREINIT:
3873         int entry;
3874       CODE:
3875         if (i_tags_find(&im->tags, name, start, &entry)) {
3876           RETVAL = entry;
3877         } else {
3878           XSRETURN_UNDEF;
3879         }
3880       OUTPUT:
3881         RETVAL
3882
3883 SysRet
3884 i_tags_findn(im, code, start)
3885         Imager::ImgRaw  im
3886         int             code
3887         int             start
3888       PREINIT:
3889         int entry;
3890       CODE:
3891         if (i_tags_findn(&im->tags, code, start, &entry)) {
3892           RETVAL = entry;
3893         }
3894         else {
3895           XSRETURN_UNDEF;
3896         }
3897       OUTPUT:
3898         RETVAL
3899
3900 int
3901 i_tags_delete(im, entry)
3902         Imager::ImgRaw  im
3903         int             entry
3904       CODE:
3905         RETVAL = i_tags_delete(&im->tags, entry);
3906       OUTPUT:
3907         RETVAL
3908
3909 int
3910 i_tags_delbyname(im, name)
3911         Imager::ImgRaw  im
3912         char *          name
3913       CODE:
3914         RETVAL = i_tags_delbyname(&im->tags, name);
3915       OUTPUT:
3916         RETVAL
3917
3918 int
3919 i_tags_delbycode(im, code)
3920         Imager::ImgRaw  im
3921         int             code
3922       CODE:
3923         RETVAL = i_tags_delbycode(&im->tags, code);
3924       OUTPUT:
3925         RETVAL
3926
3927 void
3928 i_tags_get(im, index)
3929         Imager::ImgRaw  im
3930         int             index
3931       PPCODE:
3932         if (index >= 0 && index < im->tags.count) {
3933           i_img_tag *entry = im->tags.tags + index;
3934           EXTEND(SP, 5);
3935         
3936           if (entry->name) {
3937             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3938           }
3939           else {
3940             PUSHs(sv_2mortal(newSViv(entry->code)));
3941           }
3942           if (entry->data) {
3943             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3944           }
3945           else {
3946             PUSHs(sv_2mortal(newSViv(entry->idata)));
3947           }
3948         }
3949
3950 void
3951 i_tags_get_string(im, what_sv)
3952         Imager::ImgRaw  im
3953         SV *what_sv
3954       PREINIT:
3955         char const *name = NULL;
3956         int code;
3957         char buffer[200];
3958       PPCODE:
3959         if (SvIOK(what_sv)) {
3960           code = SvIV(what_sv);
3961           name = NULL;
3962         }
3963         else {
3964           name = SvPV_nolen(what_sv);
3965           code = 0;
3966         }
3967         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
3968           EXTEND(SP, 1);
3969           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
3970         }
3971
3972 int
3973 i_tags_count(im)
3974         Imager::ImgRaw  im
3975       CODE:
3976         RETVAL = im->tags.count;
3977       OUTPUT:
3978         RETVAL
3979
3980
3981
3982 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
3983
3984 void
3985 IFILL_DESTROY(fill)
3986         Imager::FillHandle fill
3987
3988 int
3989 IFILL_CLONE_SKIP(...)
3990     CODE:
3991         (void)items; /* avoid unused warning for XS variable */
3992         RETVAL = 1;
3993     OUTPUT:
3994         RETVAL
3995
3996 MODULE = Imager         PACKAGE = Imager
3997
3998 Imager::FillHandle
3999 i_new_fill_solid(cl, combine)
4000         Imager::Color cl
4001         int combine
4002
4003 Imager::FillHandle
4004 i_new_fill_solidf(cl, combine)
4005         Imager::Color::Float cl
4006         int combine
4007
4008 Imager::FillHandle
4009 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
4010         Imager::Color fg
4011         Imager::Color bg
4012         int combine
4013         int hatch
4014         SV *cust_hatch_sv
4015         i_img_dim dx
4016         i_img_dim dy
4017       PREINIT:
4018         unsigned char *cust_hatch;
4019         STRLEN len;
4020       CODE:
4021         SvGETMAGIC(cust_hatch_sv);
4022         if (SvOK(cust_hatch_sv)) {
4023           cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len);
4024         }
4025         else
4026           cust_hatch = NULL;
4027         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
4028       OUTPUT:
4029         RETVAL
4030
4031 Imager::FillHandle
4032 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
4033         Imager::Color::Float fg
4034         Imager::Color::Float bg
4035         int combine
4036         int hatch
4037         SV *cust_hatch_sv
4038         i_img_dim dx
4039         i_img_dim dy
4040       PREINIT:
4041         unsigned char *cust_hatch;
4042         STRLEN len;
4043       CODE:
4044         SvGETMAGIC(cust_hatch_sv);
4045         if (SvOK(cust_hatch_sv)) {
4046           cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len);
4047         }
4048         else
4049           cust_hatch = NULL;
4050         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
4051       OUTPUT:
4052         RETVAL
4053
4054 Imager::FillHandle
4055 i_new_fill_image(src, matrix_sv, xoff, yoff, combine)
4056         Imager::ImgRaw src
4057         SV *matrix_sv
4058         i_img_dim xoff
4059         i_img_dim yoff
4060         int combine
4061       PREINIT:
4062         double matrix[9];
4063         double *matrixp;
4064         AV *av;
4065         IV len;
4066         SV *sv1;
4067         int i;
4068       CODE:
4069         SvGETMAGIC(matrix_sv);
4070         if (!SvOK(matrix_sv)) {
4071           matrixp = NULL;
4072         }
4073         else {
4074           if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV)
4075             croak("i_new_fill_image: matrix parameter must be an arrayref or undef");
4076           av=(AV*)SvRV(matrix_sv);
4077           len=av_len(av)+1;
4078           if (len > 9)
4079             len = 9;
4080           for (i = 0; i < len; ++i) {
4081             sv1=(*(av_fetch(av,i,0)));
4082             matrix[i] = SvNV(sv1);
4083           }
4084           for (; i < 9; ++i)
4085             matrix[i] = 0;
4086           matrixp = matrix;
4087         }
4088         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
4089       OUTPUT:
4090         RETVAL
4091
4092 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
4093
4094 # this class is only exposed for testing
4095
4096 int
4097 i_int_hlines_testing()
4098
4099 #if i_int_hlines_testing()
4100
4101 Imager::Internal::Hlines
4102 i_int_hlines_new(start_y, count_y, start_x, count_x)
4103         i_img_dim start_y
4104         int count_y
4105         i_img_dim start_x
4106         int count_x
4107
4108 Imager::Internal::Hlines
4109 i_int_hlines_new_img(im)
4110         Imager::ImgRaw im
4111
4112 void
4113 i_int_hlines_add(hlines, y, minx, width)
4114         Imager::Internal::Hlines hlines
4115         i_img_dim y
4116         i_img_dim minx
4117         i_img_dim width
4118
4119 void
4120 i_int_hlines_DESTROY(hlines)
4121         Imager::Internal::Hlines hlines
4122
4123 SV *
4124 i_int_hlines_dump(hlines)
4125         Imager::Internal::Hlines hlines
4126
4127 int
4128 i_int_hlines_CLONE_SKIP(cls)
4129
4130 #endif
4131
4132 MODULE = Imager  PACKAGE = Imager::Context PREFIX=im_context_
4133
4134 void
4135 im_context_DESTROY(ctx)
4136    Imager::Context ctx
4137
4138 #ifdef PERL_IMPLICIT_CONTEXT
4139
4140 void
4141 im_context_CLONE(...)
4142     CODE:
4143       MY_CXT_CLONE;
4144       (void)items;
4145       /* the following sv_setref_pv() will free this inc */
4146       im_context_refinc(MY_CXT.ctx, "CLONE");
4147       MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE");
4148       sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
4149
4150 #endif
4151
4152 BOOT:
4153         PERL_SET_GLOBAL_CALLBACKS;
4154         PERL_PL_SET_GLOBAL_CALLBACKS;
4155 #ifdef PERL_IMPLICIT_CONTEXT
4156         {
4157           MY_CXT_INIT;
4158           (void)MY_CXT;
4159         }
4160 #endif
4161         start_context(aTHX);
4162         im_get_context = perl_get_context;
4163 #ifdef HAVE_LIBTT
4164         i_tt_start();
4165 #endif