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