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