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