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