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