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