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