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