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