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