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