[RT #92738] improve XS for i_io_read()/i_io_raw_read()
[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
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_radnoise(im,xo,yo,rscale,ascale)
2708     Imager::ImgRaw     im
2709              float     xo
2710              float     yo
2711              float     rscale
2712              float     ascale
2713
2714 void
2715 i_turbnoise(im, xo, yo, scale)
2716     Imager::ImgRaw     im
2717              float     xo
2718              float     yo
2719              float     scale
2720
2721
2722 void
2723 i_gradgen(im, xo, yo, ac, dmeasure)
2724     Imager::ImgRaw     im
2725     i_img_dim *xo
2726     i_img_dim *yo
2727     i_color *ac
2728     int dmeasure
2729       PREINIT:
2730         STRLEN size_xo;
2731         STRLEN size_yo;
2732         STRLEN size_ac;
2733       CODE:
2734         if (size_xo != size_yo || size_xo != size_ac)
2735           croak("i_gradgen: x, y and color arrays must be the same size");
2736         if (size_xo < 2)
2737           croak("Usage: i_gradgen array refs must have more than 1 entry each");
2738         i_gradgen(im, size_xo, xo, yo, ac, dmeasure);
2739
2740 Imager::ImgRaw
2741 i_diff_image(im, im2, mindist=0)
2742     Imager::ImgRaw     im
2743     Imager::ImgRaw     im2
2744             double     mindist
2745
2746 undef_int
2747 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2748     Imager::ImgRaw     im
2749             double     xa
2750             double     ya
2751             double     xb
2752             double     yb
2753                int     type
2754                int     repeat
2755                int     combine
2756                int     super_sample
2757             double     ssample_param
2758       PREINIT:
2759         AV *asegs;
2760         int count;
2761         i_fountain_seg *segs;
2762       CODE:
2763         if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
2764             croak("i_fountain: argument 11 must be an array ref");
2765         
2766         asegs = (AV *)SvRV(ST(10));
2767         segs = load_fount_segs(aTHX_ asegs, &count);
2768         RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, 
2769                             super_sample, ssample_param, count, segs);
2770         myfree(segs);
2771       OUTPUT:
2772         RETVAL
2773
2774 Imager::FillHandle
2775 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2776             double     xa
2777             double     ya
2778             double     xb
2779             double     yb
2780                int     type
2781                int     repeat
2782                int     combine
2783                int     super_sample
2784             double     ssample_param
2785       PREINIT:
2786         AV *asegs;
2787         int count;
2788         i_fountain_seg *segs;
2789       CODE:
2790         if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
2791             croak("i_fountain: argument 11 must be an array ref");
2792         
2793         asegs = (AV *)SvRV(ST(9));
2794         segs = load_fount_segs(aTHX_ asegs, &count);
2795         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
2796                                   super_sample, ssample_param, count, segs);
2797         myfree(segs);        
2798       OUTPUT:
2799         RETVAL
2800
2801 Imager::FillHandle
2802 i_new_fill_opacity(other_fill, alpha_mult)
2803     Imager::FillHandle other_fill
2804     double alpha_mult
2805
2806 void
2807 i_errors()
2808       PREINIT:
2809         i_errmsg *errors;
2810         int i;
2811         AV *av;
2812         SV *sv;
2813       PPCODE:
2814         errors = i_errors();
2815         i = 0;
2816         while (errors[i].msg) {
2817           av = newAV();
2818           sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
2819           if (!av_store(av, 0, sv)) {
2820             SvREFCNT_dec(sv);
2821           }
2822           sv = newSViv(errors[i].code);
2823           if (!av_store(av, 1, sv)) {
2824             SvREFCNT_dec(sv);
2825           }
2826           PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
2827           ++i;
2828         }
2829
2830 void
2831 i_clear_error()
2832
2833 void
2834 i_push_error(code, msg)
2835         int code
2836         const char *msg
2837
2838 undef_int
2839 i_nearest_color(im, ...)
2840     Imager::ImgRaw     im
2841       PREINIT:
2842         int num;
2843         i_img_dim *xo;
2844         i_img_dim *yo;
2845         i_color *ival;
2846         int dmeasure;
2847         int i;
2848         SV *sv;
2849         AV *axx;
2850         AV *ayy;
2851         AV *ac;
2852       CODE:
2853         if (items != 5)
2854             croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
2855         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2856             croak("i_nearest_color: Second argument must be an array ref");
2857         if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2858             croak("i_nearest_color: Third argument must be an array ref");
2859         if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2860             croak("i_nearest_color: Fourth argument must be an array ref");
2861         axx = (AV *)SvRV(ST(1));
2862         ayy = (AV *)SvRV(ST(2));
2863         ac  = (AV *)SvRV(ST(3));
2864         dmeasure = (int)SvIV(ST(4));
2865         
2866         num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2867         num = num <= av_len(ac) ? num : av_len(ac);
2868         num++; 
2869         if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
2870         xo = mymalloc( sizeof(i_img_dim) * num );
2871         yo = mymalloc( sizeof(i_img_dim) * num );
2872         ival = mymalloc( sizeof(i_color) * num );
2873         for(i = 0; i<num; i++) {
2874           xo[i]   = (i_img_dim)SvIV(* av_fetch(axx, i, 0));
2875           yo[i]   = (i_img_dim)SvIV(* av_fetch(ayy, i, 0));
2876           sv = *av_fetch(ac, i, 0);
2877           if ( !sv_derived_from(sv, "Imager::Color") ) {
2878             free(axx); free(ayy); free(ac);
2879             croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
2880           }
2881           ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
2882         }
2883         RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
2884       OUTPUT:
2885         RETVAL
2886
2887 void
2888 malloc_state()
2889
2890 void
2891 DSO_open(filename)
2892              char*       filename
2893              PREINIT:
2894                void *rc;
2895                char *evstr;
2896              PPCODE:
2897                rc=DSO_open(filename,&evstr);
2898                if (rc!=NULL) {
2899                  if (evstr!=NULL) {
2900                    EXTEND(SP,2); 
2901                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
2902                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
2903                  } else {
2904                    EXTEND(SP,1);
2905                    PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
2906                  }
2907                }
2908
2909
2910 undef_int
2911 DSO_close(dso_handle)
2912              void*       dso_handle
2913
2914 void
2915 DSO_funclist(dso_handle_v)
2916              void*       dso_handle_v
2917              PREINIT:
2918                int i;
2919                DSO_handle *dso_handle;
2920                func_ptr *functions;
2921              PPCODE:
2922                dso_handle=(DSO_handle*)dso_handle_v;
2923                functions = DSO_funclist(dso_handle);
2924                i=0;
2925                while( functions[i].name != NULL) {
2926                  EXTEND(SP,1);
2927                  PUSHs(sv_2mortal(newSVpv(functions[i].name,0)));
2928                  EXTEND(SP,1);
2929                  PUSHs(sv_2mortal(newSVpv(functions[i++].pcode,0)));
2930                }
2931
2932 void
2933 DSO_call(handle,func_index,hv)
2934                void*  handle
2935                int    func_index
2936                HV *hv
2937              PPCODE:
2938                DSO_call( (DSO_handle *)handle,func_index,hv);
2939
2940 Imager::Color
2941 i_get_pixel(im, x, y)
2942         Imager::ImgRaw im
2943         i_img_dim x
2944         i_img_dim y;
2945       CODE:
2946         RETVAL = (i_color *)mymalloc(sizeof(i_color));
2947         if (i_gpix(im, x, y, RETVAL) != 0) {
2948           myfree(RETVAL);
2949           XSRETURN_UNDEF;
2950         }
2951       OUTPUT:
2952         RETVAL
2953         
2954
2955 int
2956 i_ppix(im, x, y, cl)
2957         Imager::ImgRaw im
2958         i_img_dim x
2959         i_img_dim y
2960         Imager::Color cl
2961
2962 Imager::ImgRaw
2963 i_img_pal_new(x, y, channels, maxpal)
2964         i_img_dim x
2965         i_img_dim y
2966         int     channels
2967         int     maxpal
2968
2969 Imager::ImgRaw
2970 i_img_to_pal(src, quant)
2971         Imager::ImgRaw src
2972       PREINIT:
2973         HV *hv;
2974         i_quantize quant;
2975       CODE:
2976         if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2977           croak("i_img_to_pal: second argument must be a hash ref");
2978         hv = (HV *)SvRV(ST(1));
2979         memset(&quant, 0, sizeof(quant));
2980         quant.version = 1;
2981         quant.mc_size = 256;
2982         ip_handle_quant_opts(aTHX_ &quant, hv);
2983         RETVAL = i_img_to_pal(src, &quant);
2984         if (RETVAL) {
2985           ip_copy_colors_back(aTHX_ hv, &quant);
2986         }
2987         ip_cleanup_quant_opts(aTHX_ &quant);
2988       OUTPUT:
2989         RETVAL
2990
2991 Imager::ImgRaw
2992 i_img_to_rgb(src)
2993         Imager::ImgRaw src
2994
2995 void
2996 i_img_make_palette(HV *quant_hv, ...)
2997       PREINIT:
2998         size_t count = items - 1;
2999         i_quantize quant;
3000         i_img **imgs = NULL;
3001         ssize_t i;
3002       PPCODE:
3003         if (count <= 0)
3004           croak("Please supply at least one image (%d)", (int)count);
3005         imgs = mymalloc(sizeof(i_img *) * count);
3006         for (i = 0; i < count; ++i) {
3007           SV *img_sv = ST(i + 1);
3008           if (SvROK(img_sv) && sv_derived_from(img_sv, "Imager::ImgRaw")) {
3009             imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(img_sv)));
3010           }
3011           else {
3012             myfree(imgs);
3013             croak("Image %d is not an image object", (int)i+1);
3014           }
3015         }
3016         memset(&quant, 0, sizeof(quant));
3017         quant.version = 1;
3018         quant.mc_size = 256;
3019         ip_handle_quant_opts(aTHX_ &quant, quant_hv);
3020         i_quant_makemap(&quant, imgs, count);
3021         EXTEND(SP, quant.mc_count);
3022         for (i = 0; i < quant.mc_count; ++i) {
3023           SV *sv_c = make_i_color_sv(aTHX_ quant.mc_colors + i);
3024           PUSHs(sv_c);
3025         }
3026         ip_cleanup_quant_opts(aTHX_ &quant);
3027         
3028
3029 void
3030 i_gpal(im, l, r, y)
3031         Imager::ImgRaw  im
3032         i_img_dim     l
3033         i_img_dim     r
3034         i_img_dim     y
3035       PREINIT:
3036         i_palidx *work;
3037         int count, i;
3038       PPCODE:
3039         if (l < r) {
3040           work = mymalloc((r-l) * sizeof(i_palidx));
3041           count = i_gpal(im, l, r, y, work);
3042           if (GIMME_V == G_ARRAY) {
3043             EXTEND(SP, count);
3044             for (i = 0; i < count; ++i) {
3045               PUSHs(sv_2mortal(newSViv(work[i])));
3046             }
3047           }
3048           else {
3049             EXTEND(SP, 1);
3050             PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
3051           }
3052           myfree(work);
3053         }
3054         else {
3055           if (GIMME_V != G_ARRAY) {
3056             EXTEND(SP, 1);
3057             PUSHs(&PL_sv_undef);
3058           }
3059         }
3060
3061 int
3062 i_ppal(im, l, y, ...)
3063         Imager::ImgRaw  im
3064         i_img_dim     l
3065         i_img_dim     y
3066       PREINIT:
3067         i_palidx *work;
3068         i_img_dim i;
3069       CODE:
3070         if (items > 3) {
3071           work = malloc_temp(aTHX_ sizeof(i_palidx) * (items-3));
3072           for (i=0; i < items-3; ++i) {
3073             work[i] = SvIV(ST(i+3));
3074           }
3075           validate_i_ppal(im, work, items - 3);
3076           RETVAL = i_ppal(im, l, l+items-3, y, work);
3077         }
3078         else {
3079           RETVAL = 0;
3080         }
3081       OUTPUT:
3082         RETVAL
3083
3084 int
3085 i_ppal_p(im, l, y, data)
3086         Imager::ImgRaw  im
3087         i_img_dim     l
3088         i_img_dim     y
3089         SV *data
3090       PREINIT:
3091         i_palidx const *work;
3092         STRLEN len;
3093       CODE:
3094         work = (i_palidx const *)SvPV(data, len);
3095         len /= sizeof(i_palidx);
3096         if (len > 0) {
3097           validate_i_ppal(im, work, len);
3098           RETVAL = i_ppal(im, l, l+len, y, work);
3099         }
3100         else {
3101           RETVAL = 0;
3102         }
3103       OUTPUT:
3104         RETVAL
3105
3106 SysRet
3107 i_addcolors(im, ...)
3108         Imager::ImgRaw  im
3109       PREINIT:
3110         i_color *colors;
3111         int i;
3112       CODE:
3113         if (items < 2)
3114           croak("i_addcolors: no colors to add");
3115         colors = mymalloc((items-1) * sizeof(i_color));
3116         for (i=0; i < items-1; ++i) {
3117           if (sv_isobject(ST(i+1)) 
3118               && sv_derived_from(ST(i+1), "Imager::Color")) {
3119             IV tmp = SvIV((SV *)SvRV(ST(i+1)));
3120             colors[i] = *INT2PTR(i_color *, tmp);
3121           }
3122           else {
3123             myfree(colors);
3124             croak("i_addcolor: pixels must be Imager::Color objects");
3125           }
3126         }
3127         RETVAL = i_addcolors(im, colors, items-1);
3128       OUTPUT:
3129         RETVAL
3130
3131 undef_int 
3132 i_setcolors(im, index, ...)
3133         Imager::ImgRaw  im
3134         int index
3135       PREINIT:
3136         i_color *colors;
3137         int i;
3138       CODE:
3139         if (items < 3)
3140           croak("i_setcolors: no colors to add");
3141         colors = mymalloc((items-2) * sizeof(i_color));
3142         for (i=0; i < items-2; ++i) {
3143           if (sv_isobject(ST(i+2)) 
3144               && sv_derived_from(ST(i+2), "Imager::Color")) {
3145             IV tmp = SvIV((SV *)SvRV(ST(i+2)));
3146             colors[i] = *INT2PTR(i_color *, tmp);
3147           }
3148           else {
3149             myfree(colors);
3150             croak("i_setcolors: pixels must be Imager::Color objects");
3151           }
3152         }
3153         RETVAL = i_setcolors(im, index, colors, items-2);
3154         myfree(colors);
3155       OUTPUT:
3156         RETVAL
3157
3158 void
3159 i_getcolors(im, index, count=1)
3160         Imager::ImgRaw im
3161         int index
3162         int count
3163       PREINIT:
3164         i_color *colors;
3165         int i;
3166       PPCODE:
3167         if (count < 1)
3168           croak("i_getcolors: count must be positive");
3169         colors = malloc_temp(aTHX_ sizeof(i_color) * count);
3170         if (i_getcolors(im, index, colors, count)) {
3171           EXTEND(SP, count);
3172           for (i = 0; i < count; ++i) {
3173             SV *sv = make_i_color_sv(aTHX_ colors+i);
3174             PUSHs(sv);
3175           }
3176         }
3177
3178 undef_neg_int
3179 i_colorcount(im)
3180         Imager::ImgRaw im
3181
3182 undef_neg_int
3183 i_maxcolors(im)
3184         Imager::ImgRaw im
3185
3186 i_palidx
3187 i_findcolor(im, color)
3188         Imager::ImgRaw im
3189         Imager::Color color
3190       CODE:
3191         if (!i_findcolor(im, color, &RETVAL)) {
3192           XSRETURN_UNDEF;
3193         }
3194       OUTPUT:
3195         RETVAL
3196
3197 int
3198 i_img_bits(im)
3199         Imager::ImgRaw  im
3200
3201 int
3202 i_img_type(im)
3203         Imager::ImgRaw  im
3204
3205 int
3206 i_img_virtual(im)
3207         Imager::ImgRaw  im
3208
3209 void
3210 i_gsamp(im, l, r, y, channels)
3211         Imager::ImgRaw im
3212         i_img_dim l
3213         i_img_dim r
3214         i_img_dim y
3215         i_channel_list channels
3216       PREINIT:
3217         i_sample_t *data;
3218         i_img_dim count, i;
3219       PPCODE:
3220         if (l < r) {
3221           data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count);
3222           count = i_gsamp(im, l, r, y, data, channels.channels, channels.count);
3223           if (GIMME_V == G_ARRAY) {
3224             EXTEND(SP, count);
3225             for (i = 0; i < count; ++i)
3226               PUSHs(sv_2mortal(newSViv(data[i])));
3227           }
3228           else {
3229             EXTEND(SP, 1);
3230             PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
3231           }
3232           myfree(data);
3233         }
3234         else {
3235           if (GIMME_V != G_ARRAY) {
3236             XSRETURN_UNDEF;
3237           }
3238         }
3239
3240 undef_neg_int
3241 i_gsamp_bits(im, l, r, y, bits, target, offset, channels)
3242         Imager::ImgRaw im
3243         i_img_dim l
3244         i_img_dim r
3245         i_img_dim y
3246         int bits
3247         AV *target
3248         STRLEN offset
3249         i_channel_list channels
3250       PREINIT:
3251         unsigned *data;
3252         i_img_dim count, i;
3253       CODE:
3254         i_clear_error();
3255         if (items < 8)
3256           croak("No channel numbers supplied to g_samp()");
3257         if (l < r) {
3258           data = mymalloc(sizeof(unsigned) * (r-l) * channels.count);
3259           count = i_gsamp_bits(im, l, r, y, data, channels.channels, channels.count, bits);
3260           for (i = 0; i < count; ++i) {
3261             av_store(target, i+offset, newSVuv(data[i]));
3262           }
3263           myfree(data);
3264           RETVAL = count;
3265         }
3266         else {
3267           RETVAL = 0;
3268         }
3269       OUTPUT:
3270         RETVAL
3271
3272 undef_neg_int
3273 i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -1)
3274         Imager::ImgRaw im
3275         i_img_dim l
3276         i_img_dim y
3277         int bits
3278         i_channel_list channels
3279         AV *data_av
3280         i_img_dim data_offset
3281         i_img_dim pixel_count
3282       PREINIT:
3283         STRLEN data_count;
3284         size_t data_used;
3285         unsigned *data;
3286         ptrdiff_t i;
3287       CODE:
3288         i_clear_error();
3289
3290         data_count = av_len(data_av) + 1;
3291         if (data_offset < 0) {
3292           croak("data_offset must be non-negative");
3293         }
3294         if (data_offset > data_count) {
3295           croak("data_offset greater than number of samples supplied");
3296         }
3297         if (pixel_count == -1 || 
3298             data_offset + pixel_count * channels.count > data_count) {
3299           pixel_count = (data_count - data_offset) / channels.count;
3300         }
3301
3302         data_used = pixel_count * channels.count;
3303         data = mymalloc(sizeof(unsigned) * data_count);
3304         for (i = 0; i < data_used; ++i)
3305           data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0));
3306
3307         RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels.channels, 
3308                               channels.count, bits);
3309
3310         if (data)
3311           myfree(data);
3312       OUTPUT:
3313         RETVAL
3314
3315 undef_neg_int
3316 i_psamp(im, x, y, channels, data, offset = 0, width = -1)
3317         Imager::ImgRaw im
3318         i_img_dim x
3319         i_img_dim y
3320         i_channel_list channels
3321         i_sample_list data
3322         i_img_dim offset
3323         i_img_dim width
3324     PREINIT:
3325         i_img_dim r;
3326     CODE:
3327         i_clear_error();
3328         if (offset < 0) {
3329           i_push_error(0, "offset must be non-negative");
3330           XSRETURN_UNDEF;
3331         }
3332         if (offset > 0) {
3333           if (offset > data.count) {
3334             i_push_error(0, "offset greater than number of samples supplied");
3335             XSRETURN_UNDEF;
3336           }
3337           data.samples += offset;
3338           data.count -= offset;
3339         }
3340         if (width == -1 ||
3341             width * channels.count > data.count) {
3342           width = data.count / channels.count;
3343         }
3344         r = x + width;
3345         RETVAL = i_psamp(im, x, r, y, data.samples, channels.channels, channels.count);
3346     OUTPUT:
3347         RETVAL
3348
3349 undef_neg_int
3350 i_psampf(im, x, y, channels, data, offset = 0, width = -1)
3351         Imager::ImgRaw im
3352         i_img_dim x
3353         i_img_dim y
3354         i_channel_list channels
3355         i_fsample_list data
3356         i_img_dim offset
3357         i_img_dim width
3358     PREINIT:
3359         i_img_dim r;
3360     CODE:
3361         i_clear_error();
3362         if (offset < 0) {
3363           i_push_error(0, "offset must be non-negative");
3364           XSRETURN_UNDEF;
3365         }
3366         if (offset > 0) {
3367           if (offset > data.count) {
3368             i_push_error(0, "offset greater than number of samples supplied");
3369             XSRETURN_UNDEF;
3370           }
3371           data.samples += offset;
3372           data.count -= offset;
3373         }
3374         if (width == -1 ||
3375             width * channels.count > data.count) {
3376           width = data.count / channels.count;
3377         }
3378         r = x + width;
3379         RETVAL = i_psampf(im, x, r, y, data.samples, channels.channels, channels.count);
3380     OUTPUT:
3381         RETVAL
3382
3383 Imager::ImgRaw
3384 i_img_masked_new(targ, mask, x, y, w, h)
3385         Imager::ImgRaw targ
3386         i_img_dim x
3387         i_img_dim y
3388         i_img_dim w
3389         i_img_dim h
3390       PREINIT:
3391         i_img *mask;
3392       CODE:
3393         if (SvOK(ST(1))) {
3394           if (!sv_isobject(ST(1)) 
3395               || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3396             croak("i_img_masked_new: parameter 2 must undef or an image");
3397           }
3398           mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
3399         }
3400         else
3401           mask = NULL;
3402         RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3403       OUTPUT:
3404         RETVAL
3405
3406 int
3407 i_plin(im, l, y, ...)
3408         Imager::ImgRaw  im
3409         i_img_dim     l
3410         i_img_dim     y
3411       PREINIT:
3412         i_color *work;
3413         STRLEN i;
3414         STRLEN len;
3415         size_t count;
3416       CODE:
3417         if (items > 3) {
3418           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3419             /* supplied as a byte string */
3420             work = (i_color *)SvPV(ST(3), len);
3421             count = len / sizeof(i_color);
3422             if (count * sizeof(i_color) != len) {
3423               croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
3424             }
3425             RETVAL = i_plin(im, l, l+count, y, work);
3426           }
3427           else {
3428             work = mymalloc(sizeof(i_color) * (items-3));
3429             for (i=0; i < items-3; ++i) {
3430               if (sv_isobject(ST(i+3)) 
3431                   && sv_derived_from(ST(i+3), "Imager::Color")) {
3432                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3433                 work[i] = *INT2PTR(i_color *, tmp);
3434               }
3435               else {
3436                 myfree(work);
3437                 croak("i_plin: pixels must be Imager::Color objects");
3438               }
3439             }
3440             RETVAL = i_plin(im, l, l+items-3, y, work);
3441             myfree(work);
3442           }
3443         }
3444         else {
3445           RETVAL = 0;
3446         }
3447       OUTPUT:
3448         RETVAL
3449
3450 int
3451 i_ppixf(im, x, y, cl)
3452         Imager::ImgRaw im
3453         i_img_dim x
3454         i_img_dim y
3455         Imager::Color::Float cl
3456
3457 void
3458 i_gsampf(im, l, r, y, channels)
3459         Imager::ImgRaw im
3460         i_img_dim l
3461         i_img_dim r
3462         i_img_dim y
3463         i_channel_list channels
3464       PREINIT:
3465         i_fsample_t *data;
3466         i_img_dim count, i;
3467       PPCODE:
3468         if (l < r) {
3469           data = mymalloc(sizeof(i_fsample_t) * (r-l) * channels.count);
3470           count = i_gsampf(im, l, r, y, data, channels.channels, channels.count);
3471           if (GIMME_V == G_ARRAY) {
3472             EXTEND(SP, count);
3473             for (i = 0; i < count; ++i)
3474               PUSHs(sv_2mortal(newSVnv(data[i])));
3475           }
3476           else {
3477             EXTEND(SP, 1);
3478             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3479           }
3480           myfree(data);
3481         }
3482         else {
3483           if (GIMME_V != G_ARRAY) {
3484             XSRETURN_UNDEF;
3485           }
3486         }
3487
3488 int
3489 i_plinf(im, l, y, ...)
3490         Imager::ImgRaw  im
3491         i_img_dim     l
3492         i_img_dim     y
3493       PREINIT:
3494         i_fcolor *work;
3495         i_img_dim i;
3496         STRLEN len;
3497         size_t count;
3498       CODE:
3499         if (items > 3) {
3500           if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3501             /* supplied as a byte string */
3502             work = (i_fcolor *)SvPV(ST(3), len);
3503             count = len / sizeof(i_fcolor);
3504             if (count * sizeof(i_fcolor) != len) {
3505               croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
3506             }
3507             RETVAL = i_plinf(im, l, l+count, y, work);
3508           }
3509           else {
3510             work = mymalloc(sizeof(i_fcolor) * (items-3));
3511             for (i=0; i < items-3; ++i) {
3512               if (sv_isobject(ST(i+3)) 
3513                   && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3514                 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3515                 work[i] = *INT2PTR(i_fcolor *, tmp);
3516               }
3517               else {
3518                 myfree(work);
3519                 croak("i_plinf: pixels must be Imager::Color::Float objects");
3520               }
3521             }
3522             /**(char *)0 = 1;*/
3523             RETVAL = i_plinf(im, l, l+items-3, y, work);
3524             myfree(work);
3525           }
3526         }
3527         else {
3528           RETVAL = 0;
3529         }
3530       OUTPUT:
3531         RETVAL
3532
3533 Imager::Color::Float
3534 i_gpixf(im, x, y)
3535         Imager::ImgRaw im
3536         i_img_dim x
3537         i_img_dim y;
3538       CODE:
3539         RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3540         if (i_gpixf(im, x, y, RETVAL) != 0) {
3541           myfree(RETVAL);
3542           XSRETURN_UNDEF;
3543         }
3544       OUTPUT:
3545         RETVAL
3546
3547 void
3548 i_glin(im, l, r, y)
3549         Imager::ImgRaw im
3550         i_img_dim l
3551         i_img_dim r
3552         i_img_dim y
3553       PREINIT:
3554         i_color *vals;
3555         i_img_dim count, i;
3556       PPCODE:
3557         if (l < r) {
3558           vals = mymalloc((r-l) * sizeof(i_color));
3559           memset(vals, 0, (r-l) * sizeof(i_color));
3560           count = i_glin(im, l, r, y, vals);
3561           if (GIMME_V == G_ARRAY) {
3562             EXTEND(SP, count);
3563             for (i = 0; i < count; ++i) {
3564               SV *sv = make_i_color_sv(aTHX_ vals+i);
3565               PUSHs(sv);
3566             }
3567           }
3568           else if (count) {
3569             EXTEND(SP, 1);
3570             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
3571           }
3572           myfree(vals);
3573         }
3574
3575 void
3576 i_glinf(im, l, r, y)
3577         Imager::ImgRaw im
3578         i_img_dim l
3579         i_img_dim r
3580         i_img_dim y
3581       PREINIT:
3582         i_fcolor *vals;
3583         i_img_dim count, i;
3584         i_fcolor zero;
3585       PPCODE:
3586         for (i = 0; i < MAXCHANNELS; ++i)
3587           zero.channel[i] = 0;
3588         if (l < r) {
3589           vals = mymalloc((r-l) * sizeof(i_fcolor));
3590           for (i = 0; i < r-l; ++i)
3591             vals[i] = zero;
3592           count = i_glinf(im, l, r, y, vals);
3593           if (GIMME_V == G_ARRAY) {
3594             EXTEND(SP, count);
3595             for (i = 0; i < count; ++i) {
3596               SV *sv;
3597               i_fcolor *col = mymalloc(sizeof(i_fcolor));
3598               *col = vals[i];
3599               sv = sv_newmortal();
3600               sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3601               PUSHs(sv);
3602             }
3603           }
3604           else if (count) {
3605             EXTEND(SP, 1);
3606             PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
3607           }
3608           myfree(vals);
3609         }
3610
3611 Imager::ImgRaw
3612 i_img_8_new(x, y, ch)
3613         i_img_dim x
3614         i_img_dim y
3615         int ch
3616
3617 Imager::ImgRaw
3618 i_img_16_new(x, y, ch)
3619         i_img_dim x
3620         i_img_dim y
3621         int ch
3622
3623 Imager::ImgRaw
3624 i_img_to_rgb16(im)
3625        Imager::ImgRaw im
3626
3627 Imager::ImgRaw
3628 i_img_double_new(x, y, ch)
3629         i_img_dim x
3630         i_img_dim y
3631         int ch
3632
3633 Imager::ImgRaw
3634 i_img_to_drgb(im)
3635        Imager::ImgRaw im
3636
3637 undef_int
3638 i_tags_addn(im, name_sv, code, idata)
3639         Imager::ImgRaw im
3640         SV *name_sv
3641         int     code
3642         int     idata
3643       PREINIT:
3644         char *name;
3645         STRLEN len;
3646       CODE:
3647         SvGETMAGIC(name_sv);
3648         if (SvOK(name_sv))
3649           name = SvPV_nomg(name_sv, len);
3650         else
3651           name = NULL;
3652         RETVAL = i_tags_addn(&im->tags, name, code, idata);
3653       OUTPUT:
3654         RETVAL
3655
3656 undef_int
3657 i_tags_add(im, name_sv, code, data_sv, idata)
3658         Imager::ImgRaw  im
3659         SV *name_sv
3660         int code
3661         SV *data_sv
3662         int idata
3663       PREINIT:
3664         char *name;
3665         char *data;
3666         STRLEN len;
3667       CODE:
3668         SvGETMAGIC(name_sv);
3669         if (SvOK(name_sv))
3670           name = SvPV_nomg(name_sv, len);
3671         else
3672           name = NULL;
3673         SvGETMAGIC(data_sv);
3674         if (SvOK(data_sv))
3675           data = SvPV(data_sv, len);
3676         else {
3677           data = NULL;
3678           len = 0;
3679         }
3680         RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3681       OUTPUT:
3682         RETVAL
3683
3684 SysRet
3685 i_tags_find(im, name, start)
3686         Imager::ImgRaw  im
3687         char *name
3688         int start
3689       PREINIT:
3690         int entry;
3691       CODE:
3692         if (i_tags_find(&im->tags, name, start, &entry)) {
3693           RETVAL = entry;
3694         } else {
3695           XSRETURN_UNDEF;
3696         }
3697       OUTPUT:
3698         RETVAL
3699
3700 SysRet
3701 i_tags_findn(im, code, start)
3702         Imager::ImgRaw  im
3703         int             code
3704         int             start
3705       PREINIT:
3706         int entry;
3707       CODE:
3708         if (i_tags_findn(&im->tags, code, start, &entry)) {
3709           RETVAL = entry;
3710         }
3711         else {
3712           XSRETURN_UNDEF;
3713         }
3714       OUTPUT:
3715         RETVAL
3716
3717 int
3718 i_tags_delete(im, entry)
3719         Imager::ImgRaw  im
3720         int             entry
3721       CODE:
3722         RETVAL = i_tags_delete(&im->tags, entry);
3723       OUTPUT:
3724         RETVAL
3725
3726 int
3727 i_tags_delbyname(im, name)
3728         Imager::ImgRaw  im
3729         char *          name
3730       CODE:
3731         RETVAL = i_tags_delbyname(&im->tags, name);
3732       OUTPUT:
3733         RETVAL
3734
3735 int
3736 i_tags_delbycode(im, code)
3737         Imager::ImgRaw  im
3738         int             code
3739       CODE:
3740         RETVAL = i_tags_delbycode(&im->tags, code);
3741       OUTPUT:
3742         RETVAL
3743
3744 void
3745 i_tags_get(im, index)
3746         Imager::ImgRaw  im
3747         int             index
3748       PPCODE:
3749         if (index >= 0 && index < im->tags.count) {
3750           i_img_tag *entry = im->tags.tags + index;
3751           EXTEND(SP, 5);
3752         
3753           if (entry->name) {
3754             PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3755           }
3756           else {
3757             PUSHs(sv_2mortal(newSViv(entry->code)));
3758           }
3759           if (entry->data) {
3760             PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3761           }
3762           else {
3763             PUSHs(sv_2mortal(newSViv(entry->idata)));
3764           }
3765         }
3766
3767 void
3768 i_tags_get_string(im, what_sv)
3769         Imager::ImgRaw  im
3770         SV *what_sv
3771       PREINIT:
3772         char const *name = NULL;
3773         int code;
3774         char buffer[200];
3775       PPCODE:
3776         if (SvIOK(what_sv)) {
3777           code = SvIV(what_sv);
3778           name = NULL;
3779         }
3780         else {
3781           name = SvPV_nolen(what_sv);
3782           code = 0;
3783         }
3784         if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
3785           EXTEND(SP, 1);
3786           PUSHs(sv_2mortal(newSVpv(buffer, 0)));
3787         }
3788
3789 int
3790 i_tags_count(im)
3791         Imager::ImgRaw  im
3792       CODE:
3793         RETVAL = im->tags.count;
3794       OUTPUT:
3795         RETVAL
3796
3797
3798
3799 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
3800
3801 void
3802 IFILL_DESTROY(fill)
3803         Imager::FillHandle fill
3804
3805 int
3806 IFILL_CLONE_SKIP(...)
3807     CODE:
3808         (void)items; /* avoid unused warning for XS variable */
3809         RETVAL = 1;
3810     OUTPUT:
3811         RETVAL
3812
3813 MODULE = Imager         PACKAGE = Imager
3814
3815 Imager::FillHandle
3816 i_new_fill_solid(cl, combine)
3817         Imager::Color cl
3818         int combine
3819
3820 Imager::FillHandle
3821 i_new_fill_solidf(cl, combine)
3822         Imager::Color::Float cl
3823         int combine
3824
3825 Imager::FillHandle
3826 i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
3827         Imager::Color fg
3828         Imager::Color bg
3829         int combine
3830         int hatch
3831         SV *cust_hatch_sv
3832         i_img_dim dx
3833         i_img_dim dy
3834       PREINIT:
3835         unsigned char *cust_hatch;
3836         STRLEN len;
3837       CODE:
3838         SvGETMAGIC(cust_hatch_sv);
3839         if (SvOK(cust_hatch_sv)) {
3840           cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len);
3841         }
3842         else
3843           cust_hatch = NULL;
3844         RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
3845       OUTPUT:
3846         RETVAL
3847
3848 Imager::FillHandle
3849 i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
3850         Imager::Color::Float fg
3851         Imager::Color::Float bg
3852         int combine
3853         int hatch
3854         SV *cust_hatch_sv
3855         i_img_dim dx
3856         i_img_dim dy
3857       PREINIT:
3858         unsigned char *cust_hatch;
3859         STRLEN len;
3860       CODE:
3861         SvGETMAGIC(cust_hatch_sv);
3862         if (SvOK(cust_hatch_sv)) {
3863           cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len);
3864         }
3865         else
3866           cust_hatch = NULL;
3867         RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
3868       OUTPUT:
3869         RETVAL
3870
3871 Imager::FillHandle
3872 i_new_fill_image(src, matrix_sv, xoff, yoff, combine)
3873         Imager::ImgRaw src
3874         SV *matrix_sv
3875         i_img_dim xoff
3876         i_img_dim yoff
3877         int combine
3878       PREINIT:
3879         double matrix[9];
3880         double *matrixp;
3881         AV *av;
3882         IV len;
3883         SV *sv1;
3884         int i;
3885       CODE:
3886         SvGETMAGIC(matrix_sv);
3887         if (!SvOK(matrix_sv)) {
3888           matrixp = NULL;
3889         }
3890         else {
3891           if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV)
3892             croak("i_new_fill_image: matrix parameter must be an arrayref or undef");
3893           av=(AV*)SvRV(matrix_sv);
3894           len=av_len(av)+1;
3895           if (len > 9)
3896             len = 9;
3897           for (i = 0; i < len; ++i) {
3898             sv1=(*(av_fetch(av,i,0)));
3899             matrix[i] = SvNV(sv1);
3900           }
3901           for (; i < 9; ++i)
3902             matrix[i] = 0;
3903           matrixp = matrix;
3904         }
3905         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
3906       OUTPUT:
3907         RETVAL
3908
3909 MODULE = Imager  PACKAGE = Imager::Internal::Hlines  PREFIX=i_int_hlines_
3910
3911 # this class is only exposed for testing
3912
3913 int
3914 i_int_hlines_testing()
3915
3916 #if i_int_hlines_testing()
3917
3918 Imager::Internal::Hlines
3919 i_int_hlines_new(start_y, count_y, start_x, count_x)
3920         i_img_dim start_y
3921         int count_y
3922         i_img_dim start_x
3923         int count_x
3924
3925 Imager::Internal::Hlines
3926 i_int_hlines_new_img(im)
3927         Imager::ImgRaw im
3928
3929 void
3930 i_int_hlines_add(hlines, y, minx, width)
3931         Imager::Internal::Hlines hlines
3932         i_img_dim y
3933         i_img_dim minx
3934         i_img_dim width
3935
3936 void
3937 i_int_hlines_DESTROY(hlines)
3938         Imager::Internal::Hlines hlines
3939
3940 SV *
3941 i_int_hlines_dump(hlines)
3942         Imager::Internal::Hlines hlines
3943
3944 int
3945 i_int_hlines_CLONE_SKIP(cls)
3946
3947 #endif
3948
3949 MODULE = Imager  PACKAGE = Imager::Context PREFIX=im_context_
3950
3951 void
3952 im_context_DESTROY(ctx)
3953    Imager::Context ctx
3954
3955 #ifdef PERL_IMPLICIT_CONTEXT
3956
3957 void
3958 im_context_CLONE(...)
3959     CODE:
3960       MY_CXT_CLONE;
3961       (void)items;
3962       /* the following sv_setref_pv() will free this inc */
3963       im_context_refinc(MY_CXT.ctx, "CLONE");
3964       MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE");
3965       sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
3966
3967 #endif
3968
3969 BOOT:
3970         PERL_SET_GLOBAL_CALLBACKS;
3971         PERL_PL_SET_GLOBAL_CALLBACKS;
3972 #ifdef PERL_IMPLICIT_CONTEXT
3973         {
3974           MY_CXT_INIT;
3975           (void)MY_CXT;
3976         }
3977 #endif
3978         start_context(aTHX);
3979         im_get_context = perl_get_context;
3980 #ifdef HAVE_LIBTT
3981         i_tt_start();
3982 #endif