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