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