]> git.imager.perl.org - imager.git/blobdiff - Imager.xs
Move freetype 2 support into its own module
[imager.git] / Imager.xs
index 50fcc185fc0c08dc0f1ced20bc70232dbc064d85..970d7df6fa91531b4eefadcb030c6733f8f26d46 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -1,9 +1,12 @@
+#define PERL_NO_GET_CONTEXT
 #ifdef __cplusplus
 extern "C" {
 #endif
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
+#define NEED_newRV_noinc
+#define NEED_sv_2pv_nolen
 #include "ppport.h"
 #ifdef __cplusplus
 }
@@ -16,8 +19,7 @@ extern "C" {
 #include "dynaload.h"
 #include "regmach.h"
 #include "imextdef.h"
-
-typedef io_glue* Imager__IO;
+#include "imextpltypes.h"
 
 #if i_int_hlines_testing()
 #include "imageri.h"
@@ -27,6 +29,7 @@ typedef io_glue* Imager__IO;
 
 /* These functions are all shared - then comes platform dependant code */
 static int getstr(void *hv_t,char *key,char **store) {
+  dTHX;
   SV** svpp;
   HV* hv=(HV*)hv_t;
 
@@ -41,6 +44,7 @@ static int getstr(void *hv_t,char *key,char **store) {
 }
 
 static int getint(void *hv_t,char *key,int *store) {
+  dTHX;
   SV** svpp;
   HV* hv=(HV*)hv_t;  
 
@@ -54,6 +58,7 @@ static int getint(void *hv_t,char *key,int *store) {
 }
 
 static int getdouble(void *hv_t,char* key,double *store) {
+  dTHX;
   SV** svpp;
   HV* hv=(HV*)hv_t;
 
@@ -66,6 +71,7 @@ static int getdouble(void *hv_t,char* key,double *store) {
 }
 
 static int getvoid(void *hv_t,char* key,void **store) {
+  dTHX;
   SV** svpp;
   HV* hv=(HV*)hv_t;
 
@@ -80,6 +86,7 @@ static int getvoid(void *hv_t,char* key,void **store) {
 }
 
 static int getobj(void *hv_t,char *key,char *type,void **store) {
+  dTHX;
   SV** svpp;
   HV* hv=(HV*)hv_t;
 
@@ -103,6 +110,7 @@ static int getobj(void *hv_t,char *key,char *type,void **store) {
 UTIL_table_t i_UTIL_table={getstr,getint,getdouble,getvoid,getobj};
 
 void my_SvREFCNT_dec(void *p) {
+  dTHX;
   SvREFCNT_dec((SV*)p);
 }
 
@@ -121,6 +129,7 @@ typedef struct i_reader_data_tag
 
 /* used by functions that want callbacks */
 static int read_callback(char *userdata, char *buffer, int need, int want) {
+  dTHX;
   i_reader_data *rd = (i_reader_data *)userdata;
   int count;
   int result;
@@ -172,6 +181,7 @@ typedef struct
 
 /* used by functions that want callbacks */
 static int write_callback(char *userdata, char const *data, int size) {
+  dTHX;
   i_writer_data *wd = (i_writer_data *)userdata;
   int count;
   int success;
@@ -243,6 +253,7 @@ Low-level function to call the perl writer callback.
 */
 
 static ssize_t call_writer(struct cbdata *cbd, void const *buf, size_t size) {
+  dTHX;
   int count;
   int success;
   SV *sv;
@@ -272,11 +283,12 @@ static ssize_t call_writer(struct cbdata *cbd, void const *buf, size_t size) {
   FREETMPS;
   LEAVE;
 
-  return success ? size : 0;
+  return success ? size : -1;
 }
 
 static ssize_t call_reader(struct cbdata *cbd, void *buf, size_t size, 
                            size_t maxread) {
+  dTHX;
   int count;
   int result;
   SV *data;
@@ -323,14 +335,21 @@ static ssize_t call_reader(struct cbdata *cbd, void *buf, size_t size,
 }
 
 static ssize_t write_flush(struct cbdata *cbd) {
+  dTHX;
   ssize_t result;
 
-  result = call_writer(cbd, cbd->buffer, cbd->used);
-  cbd->used = 0;
-  return result;
+  if (cbd->used) {
+    result = call_writer(cbd, cbd->buffer, cbd->used);
+    cbd->used = 0;
+    return result;
+  }
+  else {
+    return 1; /* success of some sort */
+  }
 }
 
 static off_t io_seeker(void *p, off_t offset, int whence) {
+  dTHX;
   struct cbdata *cbd = p;
   int count;
   off_t result;
@@ -375,14 +394,14 @@ static off_t io_seeker(void *p, off_t offset, int whence) {
 }
 
 static ssize_t io_writer(void *p, void const *data, size_t size) {
+  dTHX;
   struct cbdata *cbd = p;
 
-  /*printf("io_writer(%p, %p, %u)\n", p, data, size);*/
+  /* printf("io_writer(%p, %p, %u)\n", p, data, size); */
   if (!cbd->writing) {
     if (cbd->reading && cbd->where < cbd->used) {
       /* we read past the place where the caller expected us to be
          so adjust our position a bit */
-        *(char *)0 = 0;
       if (io_seeker(p, cbd->where - cbd->used, SEEK_CUR) < 0) {
         return -1;
       }
@@ -392,8 +411,9 @@ static ssize_t io_writer(void *p, void const *data, size_t size) {
   }
   cbd->writing = 1;
   if (cbd->used && cbd->used + size > cbd->maxlength) {
-    if (write_flush(cbd) <= 0) {
-      return 0;
+    int write_res = write_flush(cbd);
+    if (write_res <= 0) {
+      return write_res;
     }
     cbd->used = 0;
   }
@@ -406,11 +426,14 @@ static ssize_t io_writer(void *p, void const *data, size_t size) {
   return call_writer(cbd, data, size);
 }
 
-static ssize_t io_reader(void *p, void *data, size_t size) {
+static ssize_t 
+io_reader(void *p, void *data, size_t size) {
+  dTHX;
   struct cbdata *cbd = p;
   ssize_t total;
   char *out = data; /* so we can do pointer arithmetic */
 
+  /* printf("io_reader(%p, %p, %d)\n", p, data, size); */
   if (cbd->writing) {
     if (write_flush(cbd) <= 0)
       return 0;
@@ -430,7 +453,7 @@ static ssize_t io_reader(void *p, void *data, size_t size) {
   size  -= cbd->used - cbd->where;
   out   += cbd->used - cbd->where;
   if (size < sizeof(cbd->buffer)) {
-    int did_read;
+    int did_read = 0;
     int copy_size;
     while (size
           && (did_read = call_reader(cbd, cbd->buffer, size, 
@@ -445,6 +468,8 @@ static ssize_t io_reader(void *p, void *data, size_t size) {
       total += copy_size;
       size  -= copy_size;
     }
+    if (did_read < 0)
+      return -1;
   }
   else {
     /* just read the rest - too big for our buffer*/
@@ -454,16 +479,20 @@ static ssize_t io_reader(void *p, void *data, size_t size) {
       total += did_read;
       out   += did_read;
     }
+    if (did_read < 0)
+      return -1;
   }
 
   return total;
 }
 
-static void io_closer(void *p) {
+static int io_closer(void *p) {
+  dTHX;
   struct cbdata *cbd = p;
 
   if (cbd->writing && cbd->used > 0) {
-    write_flush(cbd);
+    if (write_flush(cbd) < 0)
+      return -1;
     cbd->writing = 0;
   }
 
@@ -482,9 +511,12 @@ static void io_closer(void *p) {
     FREETMPS;
     LEAVE;
   }
+
+  return 0;
 }
 
 static void io_destroyer(void *p) {
+  dTHX;
   struct cbdata *cbd = p;
 
   SvREFCNT_dec(cbd->writecb);
@@ -521,13 +553,13 @@ static struct value_name make_color_names[] =
   { "webmap", mc_web_map, },
   { "addi", mc_addi, },
   { "mediancut", mc_median_cut, },
+  { "mono", mc_mono, },
+  { "monochrome", mc_mono, },
 };
 
 static struct value_name translate_names[] =
 {
-#ifdef HAVE_LIBGIF
   { "giflib", pt_giflib, },
-#endif
   { "closest", pt_closest, },
   { "perturb", pt_perturb, },
   { "errdiff", pt_errdiff, },
@@ -557,7 +589,8 @@ static struct value_name orddith_names[] =
 };
 
 /* look through the hash for quantization options */
-static void handle_quant_opts(i_quantize *quant, HV *hv)
+static void
+ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
 {
   /*** POSSIBLY BROKEN: do I need to unref the SV from hv_fetch ***/
   SV **sv;
@@ -688,14 +721,16 @@ static void handle_quant_opts(i_quantize *quant, HV *hv)
     quant->perturb = SvIV(*sv);
 }
 
-static void cleanup_quant_opts(i_quantize *quant) {
+static void
+ip_cleanup_quant_opts(pTHX_ i_quantize *quant) {
   myfree(quant->mc_colors);
   if (quant->ed_map)
     myfree(quant->ed_map);
 }
 
 /* copies the color map from the hv into the colors member of the HV */
-static void copy_colors_back(HV *hv, i_quantize *quant) {
+static void
+ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) {
   SV **sv;
   AV *av;
   int i;
@@ -703,14 +738,12 @@ static void copy_colors_back(HV *hv, i_quantize *quant) {
 
   sv = hv_fetch(hv, "colors", 6, 0);
   if (!sv || !*sv || !SvROK(*sv) || SvTYPE(SvRV(*sv)) != SVt_PVAV) {
-    SV *ref;
-    av = newAV();
-    ref = newRV_inc((SV*) av);
-    sv = hv_store(hv, "colors", 6, ref, 0);
-  }
-  else {
-    av = (AV *)SvRV(*sv);
+    /* nothing to do */
+    return;
   }
+
+  av = (AV *)SvRV(*sv);
+  av_clear(av);
   av_extend(av, quant->mc_count+1);
   for (i = 0; i < quant->mc_count; ++i) {
     i_color *in = quant->mc_colors+i;
@@ -718,15 +751,13 @@ static void copy_colors_back(HV *hv, i_quantize *quant) {
     work = sv_newmortal();
     sv_setref_pv(work, "Imager::Color", (void *)c);
     SvREFCNT_inc(work);
-    if (!av_store(av, i, work)) {
-      SvREFCNT_dec(work);
-    }
+    av_push(av, work);
   }
 }
 
 /* loads the segments of a fountain fill into an array */
 static i_fountain_seg *
-load_fount_segs(AV *asegs, int *count) {
+load_fount_segs(pTHX_ AV *asegs, int *count) {
   /* Each element of segs must contain:
      [ start, middle, end, c0, c1, segtype, colortrans ]
      start, middle, end are doubles from 0 to 1
@@ -800,6 +831,29 @@ load_fount_segs(AV *asegs, int *count) {
   return segs;
 }
 
+/* validates the indexes supplied to i_ppal
+
+i_ppal() doesn't do that for speed, but I'm not comfortable doing that
+for calls from perl.
+
+*/
+static void
+validate_i_ppal(i_img *im, i_palidx const *indexes, int count) {
+  int color_count = i_colorcount(im);
+  int i;
+
+  if (color_count == -1)
+    croak("i_plin() called on direct color image");
+  
+  for (i = 0; i < count; ++i) {
+    if (indexes[i] >= color_count) {
+      croak("i_plin() called with out of range color index %d (max %d)",
+        indexes[i], color_count-1);
+    }
+  }
+}
+
+
 /* I don't think ICLF_* names belong at the C interface
    this makes the XS code think we have them, to let us avoid 
    putting function bodies in the XS code
@@ -838,6 +892,8 @@ i_int_hlines_DESTROY(i_int_hlines *hlines) {
   myfree(hlines);
 }
 
+#define i_int_hlines_CLONE_SKIP(cls) 1
+
 static int seg_compare(const void *vleft, const void *vright) {
   const i_int_hline_seg *left = vleft;
   const i_int_hline_seg *right = vright;
@@ -847,6 +903,7 @@ static int seg_compare(const void *vleft, const void *vright) {
 
 static SV *
 i_int_hlines_dump(i_int_hlines *hlines) {
+  dTHX;
   SV *dump = newSVpvf("start_y: %d limit_y: %d start_x: %d limit_x: %d\n",
        hlines->start_y, hlines->limit_y, hlines->start_x, hlines->limit_x);
   int y;
@@ -873,6 +930,18 @@ i_int_hlines_dump(i_int_hlines *hlines) {
 
 #endif
 
+static im_pl_ext_funcs im_perl_funcs =
+{
+  IMAGER_PL_API_VERSION,
+  IMAGER_PL_API_LEVEL,
+  ip_handle_quant_opts,
+  ip_cleanup_quant_opts,
+  ip_copy_colors_back
+};
+
+#define PERL_PL_SET_GLOBAL_CALLBACKS \
+  sv_setiv(get_sv(PERL_PL_FUNCTION_TABLE_NAME, 1), PTR2IV(&im_perl_funcs));
+
 #ifdef IMEXIF_ENABLE
 #define i_exif_enabled() 1
 #else
@@ -882,6 +951,9 @@ i_int_hlines_dump(i_int_hlines *hlines) {
 /* trying to use more C style names, map them here */
 #define i_io_DESTROY(ig) io_glue_destroy(ig)
 
+#define i_img_get_width(im) ((im)->xsize)
+#define i_img_get_height(im) ((im)->ysize)
+
 MODULE = Imager                PACKAGE = Imager::Color PREFIX = ICL_
 
 Imager::Color
@@ -1117,6 +1189,7 @@ i_io_write(ig, data_sv)
 #ifdef SvUTF8
         if (SvUTF8(data_sv)) {
          data_sv = sv_2mortal(newSVsv(data_sv));
+          /* yes, we want this to croak() if the SV can't be downgraded */
          sv_utf8_downgrade(data_sv, FALSE);
        }
 #endif        
@@ -1125,7 +1198,7 @@ i_io_write(ig, data_sv)
       OUTPUT:
        RETVAL
 
-SV *
+void
 i_io_read(ig, buffer_sv, size)
        Imager::IO ig
        SV *buffer_sv
@@ -1133,8 +1206,8 @@ i_io_read(ig, buffer_sv, size)
       PREINIT:
         void *buffer;
        int result;
-      CODE:
-        if (size < 0)
+      PPCODE:
+        if (size <= 0)
          croak("size negative in call to i_io_read()");
         /* prevent an undefined value warning if they supplied an 
           undef buffer.
@@ -1147,18 +1220,41 @@ i_io_read(ig, buffer_sv, size)
 #endif
        buffer = SvGROW(buffer_sv, size+1);
         result = i_io_read(ig, buffer, size);
-        if (result < 0) {
-         RETVAL = &PL_sv_undef;
+        if (result >= 0) {
+         SvCUR_set(buffer_sv, result);
+         *SvEND(buffer_sv) = '\0';
+         SvPOK_only(buffer_sv);
+         EXTEND(SP, 1);
+         PUSHs(sv_2mortal(newSViv(result)));
        }
-       else {
+       ST(1) = buffer_sv;
+       SvSETMAGIC(ST(1));
+
+void
+i_io_read2(ig, size)
+       Imager::IO ig
+       int size
+      PREINIT:
+       SV *buffer_sv;
+        void *buffer;
+       int result;
+      PPCODE:
+        if (size <= 0)
+         croak("size negative in call to i_io_read2()");
+       buffer_sv = newSV(size);
+       buffer = SvGROW(buffer_sv, size+1);
+        result = i_io_read(ig, buffer, size);
+        if (result >= 0) {
          SvCUR_set(buffer_sv, result);
          *SvEND(buffer_sv) = '\0';
          SvPOK_only(buffer_sv);
-         RETVAL = newSViv(result); /* XS will mortal this */
+         EXTEND(SP, 1);
+         PUSHs(sv_2mortal(buffer_sv));
        }
-      OUTPUT:
-       RETVAL
-       buffer_sv
+       else {
+          /* discard it */
+         SvREFCNT_dec(buffer_sv);
+        }
 
 int
 i_io_seek(ig, position, whence)
@@ -1166,7 +1262,7 @@ i_io_seek(ig, position, whence)
        long position
        int whence
 
-void
+int
 i_io_close(ig)
        Imager::IO ig
 
@@ -1174,6 +1270,12 @@ void
 i_io_DESTROY(ig)
         Imager::IO     ig
 
+int
+i_io_CLONE_SKIP(...)
+    CODE:
+       RETVAL = 1;
+    OUTPUT:
+       RETVAL
 
 MODULE = Imager                PACKAGE = Imager
 
@@ -1225,9 +1327,13 @@ i_sametype_chans(im, x, y, channels)
                int channels
 
 void
-i_init_log(name,level)
-             char*    name
+i_init_log(name_sv,level)
+             SV*    name_sv
               int     level
+       PREINIT:
+         const char *name = SvOK(name_sv) ? SvPV_nolen(name_sv) : NULL;
+       CODE:
+         i_init_log(name, level);
 
 void
 i_log_entry(string,level)
@@ -1281,6 +1387,34 @@ i_img_getdata(im)
                     sv_2mortal(newSVpv((char *)im->idata, im->bytes)) 
                     : &PL_sv_undef);
 
+IV
+i_img_get_width(im)
+    Imager::ImgRaw     im
+
+IV
+i_img_get_height(im)
+    Imager::ImgRaw     im
+
+
+void
+i_img_is_monochrome(im)
+       Imager::ImgRaw im
+      PREINIT:
+       int zero_is_white;
+       int result;
+      PPCODE:
+       result = i_img_is_monochrome(im, &zero_is_white);
+       if (result) {
+         if (GIMME_V == G_ARRAY) {
+           EXTEND(SP, 2);
+           PUSHs(&PL_sv_yes);
+           PUSHs(sv_2mortal(newSViv(zero_is_white)));
+         }
+         else {
+           EXTEND(SP, 1);
+           PUSHs(&PL_sv_yes);
+         }
+       }
 
 void
 i_line(im,x1,y1,x2,y2,val,endp)
@@ -1378,6 +1512,41 @@ i_circle_aa(im,x,y,rad,val)
              float     rad
           Imager::Color    val
 
+int
+i_circle_out(im,x,y,rad,val)
+    Imager::ImgRaw     im
+            i_img_dim     x
+            i_img_dim     y
+             i_img_dim     rad
+          Imager::Color    val
+
+int
+i_circle_out_aa(im,x,y,rad,val)
+    Imager::ImgRaw     im
+            i_img_dim     x
+            i_img_dim     y
+             i_img_dim     rad
+          Imager::Color    val
+
+int
+i_arc_out(im,x,y,rad,d1,d2,val)
+    Imager::ImgRaw     im
+            i_img_dim     x
+            i_img_dim     y
+             i_img_dim     rad
+            float d1
+            float d2
+          Imager::Color    val
+
+int
+i_arc_out_aa(im,x,y,rad,d1,d2,val)
+    Imager::ImgRaw     im
+            i_img_dim     x
+            i_img_dim     y
+             i_img_dim     rad
+            float d1
+            float d2
+          Imager::Color    val
 
 
 void
@@ -1415,7 +1584,7 @@ i_bezier_multi(im,xc,yc,val)
              myfree(y);
 
 
-void
+int
 i_poly_aa(im,xc,yc,val)
     Imager::ImgRaw     im
              Imager::Color  val
@@ -1427,7 +1596,7 @@ i_poly_aa(im,xc,yc,val)
             SV       *sv1;
             SV       *sv2;
             int i;
-            PPCODE:
+            CODE:
             ICL_info(val);
             if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
             if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
@@ -1445,11 +1614,13 @@ i_poly_aa(im,xc,yc,val)
               x[i]=(double)SvNV(sv1);
               y[i]=(double)SvNV(sv2);
             }
-             i_poly_aa(im,len,x,y,val);
+             RETVAL = i_poly_aa(im,len,x,y,val);
              myfree(x);
              myfree(y);
+            OUTPUT:
+              RETVAL
 
-void
+int
 i_poly_aa_cfill(im,xc,yc,fill)
     Imager::ImgRaw     im
      Imager::FillHandle     fill
@@ -1461,7 +1632,7 @@ i_poly_aa_cfill(im,xc,yc,fill)
             SV       *sv1;
             SV       *sv2;
             int i;
-            PPCODE:
+            CODE:
             if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
             if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
             if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
@@ -1478,9 +1649,11 @@ i_poly_aa_cfill(im,xc,yc,fill)
               x[i]=(double)SvNV(sv1);
               y[i]=(double)SvNV(sv2);
             }
-             i_poly_aa_cfill(im,len,x,y,fill);
+             RETVAL = i_poly_aa_cfill(im,len,x,y,fill);
              myfree(x);
              myfree(y);
+            OUTPUT:
+              RETVAL
 
 
 
@@ -1498,6 +1671,22 @@ i_flood_cfill(im,seedx,seedy,fill)
               int     seedy
      Imager::FillHandle     fill
 
+undef_int
+i_flood_fill_border(im,seedx,seedy,dcol, border)
+    Imager::ImgRaw     im
+              int     seedx
+              int     seedy
+     Imager::Color     dcol
+     Imager::Color     border
+
+undef_int
+i_flood_cfill_border(im,seedx,seedy,fill, border)
+    Imager::ImgRaw     im
+              int     seedx
+              int     seedy
+     Imager::FillHandle     fill
+     Imager::Color     border
+
 
 void
 i_copyto(im,src,x1,y1,x2,y2,tx,ty)
@@ -1539,6 +1728,34 @@ i_rubthru(im,src,tx,ty,src_minx,src_miny,src_maxx,src_maxy)
               int     src_maxx
               int     src_maxy
 
+undef_int
+i_compose(out, src, out_left, out_top, src_left, src_top, width, height, combine = ic_normal, opacity = 0.0)
+    Imager::ImgRaw out
+    Imager::ImgRaw src
+       int out_left
+       int out_top
+       int src_left
+       int src_top
+       int width
+       int height
+       int combine
+       double opacity
+
+undef_int
+i_compose_mask(out, src, mask, out_left, out_top, src_left, src_top, mask_left, mask_top, width, height, combine = ic_normal, opacity = 0.0)
+    Imager::ImgRaw out
+    Imager::ImgRaw src
+    Imager::ImgRaw mask
+       int out_left
+       int out_top
+       int src_left
+       int src_top
+       int mask_left
+       int mask_top
+       int width
+       int height
+       int combine
+       double opacity
 
 undef_int
 i_flipxy(im, direction)
@@ -1620,10 +1837,10 @@ i_matrix_transform(im, xsize, ysize, matrix, ...)
       OUTPUT:
         RETVAL
 
-void
+undef_int
 i_gaussian(im,stdev)
     Imager::ImgRaw     im
-            float     stdev
+           double     stdev
 
 void
 i_unsharp_mask(im,stdev,scale)
@@ -1631,45 +1848,40 @@ i_unsharp_mask(im,stdev,scale)
             float     stdev
              double    scale
 
-void
-i_conv(im,pcoef)
-    Imager::ImgRaw     im
-            PREINIT:
-            float*    coeff;
-            int     len;
-            AV* av;
-            SV* sv1;
-            int i;
-            PPCODE:
-            if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
-            av=(AV*)SvRV(ST(1));
-            len=av_len(av)+1;
-            coeff=mymalloc( len*sizeof(float) );
-            for(i=0;i<len;i++) {
-              sv1=(*(av_fetch(av,i,0)));
-              coeff[i]=(float)SvNV(sv1);
-            }
-            i_conv(im,coeff,len);
-            myfree(coeff);
+int
+i_conv(im,coef)
+       Imager::ImgRaw     im
+       AV *coef
+     PREINIT:
+       double*    c_coef;
+       int     len;
+       SV* sv1;
+       int i;
+    CODE:
+       len = av_len(coef) + 1;
+       c_coef=mymalloc( len * sizeof(double) );
+       for(i = 0; i  < len; i++) {
+         sv1 = (*(av_fetch(coef, i, 0)));
+         c_coef[i] = (double)SvNV(sv1);
+       }
+       RETVAL = i_conv(im, c_coef, len);
+       myfree(c_coef);
+    OUTPUT:
+       RETVAL
 
-undef_int
-i_convert(im, src, coeff)
-    Imager::ImgRaw     im
+Imager::ImgRaw
+i_convert(src, avmain)
     Imager::ImgRaw     src
+    AV *avmain
        PREINIT:
          float *coeff;
          int outchan;
          int inchan;
-         AV *avmain;
           SV **temp;
           AV *avsub;
          int len;
          int i, j;
         CODE:
-         if (!SvROK(ST(2)) || SvTYPE(SvRV(ST(2))) != SVt_PVAV)
-           croak("i_convert: parameter 3 must be an arrayref\n");
-          avmain = (AV*)SvRV(ST(2));
          outchan = av_len(avmain)+1;
           /* find the biggest */
           inchan = 0;
@@ -1696,7 +1908,7 @@ i_convert(im, src, coeff)
            while (i < inchan)
              coeff[i++ + j*inchan] = 0;
          }
-         RETVAL = i_convert(im, src, coeff, outchan, inchan);
+         RETVAL = i_convert(src, coeff, outchan, inchan);
           myfree(coeff);
        OUTPUT:
          RETVAL
@@ -1748,12 +1960,26 @@ i_img_diff(im1,im2)
     Imager::ImgRaw     im1
     Imager::ImgRaw     im2
 
-
+double
+i_img_diffd(im1,im2)
+    Imager::ImgRaw     im1
+    Imager::ImgRaw     im2
 
 undef_int        
 i_init_fonts(t1log=0)
     int t1log
 
+bool
+_is_color_object(sv)
+       SV* sv
+    CODE:
+        SvGETMAGIC(sv);
+        RETVAL = SvOK(sv) && SvROK(sv) &&
+          (sv_derived_from(sv, "Imager::Color")
+          || sv_derived_from(sv, "Imager::Color::Float"));
+    OUTPUT:
+        RETVAL
+
 #ifdef HAVE_LIBT1
 
 void
@@ -1903,7 +2129,7 @@ i_t1_glyph_name(handle, text_sv, utf8 = 0)
       PREINIT:
         char const *text;
         STRLEN work_len;
-        int len;
+        size_t len;
         char name[255];
       PPCODE:
 #ifdef SvUTF8
@@ -1952,6 +2178,13 @@ void
 TT_DESTROY(handle)
      Imager::Font::TT   handle
 
+int
+TT_CLONE_SKIP(...)
+    CODE:
+        RETVAL = 1;
+    OUTPUT:
+        RETVAL
+
 
 MODULE = Imager         PACKAGE = Imager
 
@@ -2090,7 +2323,7 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0)
       PREINIT:
         char const *text;
         STRLEN work_len;
-        int len;
+        size_t len;
         int outsize;
         char name[255];
       PPCODE:
@@ -2124,71 +2357,27 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0)
 
 #endif 
 
-
-#ifdef HAVE_LIBJPEG
-undef_int
-i_writejpeg_wiol(im, ig, qfactor)
-    Imager::ImgRaw     im
-        Imager::IO     ig
-              int     qfactor
-
-
-void
-i_readjpeg_wiol(ig)
-        Imager::IO     ig
-            PREINIT:
-             char*    iptc_itext;
-              int     tlength;
-            i_img*    rimg;
-                SV*    r;
-            PPCODE:
-             iptc_itext = NULL;
-             rimg = i_readjpeg_wiol(ig,-1,&iptc_itext,&tlength);
-             if (iptc_itext == NULL) {
-                   r = sv_newmortal();
-                   EXTEND(SP,1);
-                   sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-                   PUSHs(r);
-             } else {
-                   r = sv_newmortal();
-                   EXTEND(SP,2);
-                   sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-                   PUSHs(r);
-                   PUSHs(sv_2mortal(newSVpv(iptc_itext,tlength)));
-                    myfree(iptc_itext);
-             }
-
-int
-i_exif_enabled()
-
-#endif
-
-
-char *
+const char *
 i_test_format_probe(ig, length)
         Imager::IO     ig
               int     length
 
-
-
-#ifdef HAVE_LIBTIFF
-
 Imager::ImgRaw
-i_readtiff_wiol(ig, length, page=0)
+i_readpnm_wiol(ig, allow_incomplete)
         Imager::IO     ig
-              int     length
-               int     page
+              int     allow_incomplete
+
 
 void
-i_readtiff_multi_wiol(ig, length)
-        Imager::IO     ig
-              int     length
+i_readpnm_multi_wiol(ig, allow_incomplete)
+        Imager::IO ig
+              int     allow_incomplete
       PREINIT:
         i_img **imgs;
-        int count;
+        int count=0;
         int i;
       PPCODE:
-        imgs = i_readtiff_multi_wiol(ig, length, &count);
+        imgs = i_readpnm_multi_wiol(ig, &count, allow_incomplete);
         if (imgs) {
           EXTEND(SP, count);
           for (i = 0; i < count; ++i) {
@@ -2199,694 +2388,66 @@ i_readtiff_multi_wiol(ig, length)
           myfree(imgs);
         }
 
-
 undef_int
-i_writetiff_wiol(im, ig)
+i_writeppm_wiol(im, ig)
     Imager::ImgRaw     im
         Imager::IO     ig
 
-undef_int
-i_writetiff_multi_wiol(ig, ...)
+
+
+
+
+Imager::ImgRaw
+i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
         Imager::IO     ig
-      PREINIT:
-        int i;
-        int img_count;
-        i_img **imgs;
-      CODE:
-        if (items < 2)
-          croak("Usage: i_writetiff_multi_wiol(ig, images...)");
-        img_count = items - 1;
-        RETVAL = 1;
-       if (img_count < 1) {
-         RETVAL = 0;
-         i_clear_error();
-         i_push_error(0, "You need to specify images to save");
-       }
-       else {
-          imgs = mymalloc(sizeof(i_img *) * img_count);
-          for (i = 0; i < img_count; ++i) {
-           SV *sv = ST(1+i);
-           imgs[i] = NULL;
-           if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
-             imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
-           }
-           else {
-             i_clear_error();
-             i_push_error(0, "Only images can be saved");
-              myfree(imgs);
-             RETVAL = 0;
-             break;
-            }
-         }
-          if (RETVAL) {
-           RETVAL = i_writetiff_multi_wiol(ig, imgs, img_count);
-          }
-         myfree(imgs);
-       }
-      OUTPUT:
-        RETVAL
+              int     x
+              int     y
+              int     datachannels
+              int     storechannels
+              int     intrl
 
 undef_int
-i_writetiff_wiol_faxable(im, ig, fine)
+i_writeraw_wiol(im,ig)
     Imager::ImgRaw     im
         Imager::IO     ig
-              int     fine
 
 undef_int
-i_writetiff_multi_wiol_faxable(ig, fine, ...)
+i_writebmp_wiol(im,ig)
+    Imager::ImgRaw     im
         Imager::IO     ig
-        int fine
-      PREINIT:
-        int i;
-        int img_count;
-        i_img **imgs;
-      CODE:
-        if (items < 3)
-          croak("Usage: i_writetiff_multi_wiol_faxable(ig, fine, images...)");
-        img_count = items - 2;
-        RETVAL = 1;
-       if (img_count < 1) {
-         RETVAL = 0;
-         i_clear_error();
-         i_push_error(0, "You need to specify images to save");
-       }
-       else {
-          imgs = mymalloc(sizeof(i_img *) * img_count);
-          for (i = 0; i < img_count; ++i) {
-           SV *sv = ST(2+i);
-           imgs[i] = NULL;
-           if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
-             imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
-           }
-           else {
-             i_clear_error();
-             i_push_error(0, "Only images can be saved");
-              myfree(imgs);
-             RETVAL = 0;
-             break;
-            }
-         }
-          if (RETVAL) {
-           RETVAL = i_writetiff_multi_wiol_faxable(ig, imgs, img_count, fine);
-          }
-         myfree(imgs);
-       }
-      OUTPUT:
-        RETVAL
-
-
-#endif /* HAVE_LIBTIFF */
-
-
-#ifdef HAVE_LIBPNG
 
 Imager::ImgRaw
-i_readpng_wiol(ig, length)
+i_readbmp_wiol(ig, allow_incomplete=0)
         Imager::IO     ig
-              int     length
+        int            allow_incomplete
 
 
 undef_int
-i_writepng_wiol(im, ig)
+i_writetga_wiol(im,ig, wierdpack, compress, idstring)
     Imager::ImgRaw     im
         Imager::IO     ig
+               int     wierdpack
+               int     compress
+              char*    idstring
+            PREINIT:
+                int idlen;
+              CODE:
+                idlen  = SvCUR(ST(4));
+                RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
+                OUTPUT:
+                RETVAL
 
 
-#endif
+Imager::ImgRaw
+i_readtga_wiol(ig, length)
+        Imager::IO     ig
+               int     length
 
 
-#ifdef HAVE_LIBGIF
 
-void
-i_giflib_version()
-       PPCODE:
-         PUSHs(sv_2mortal(newSVnv(IM_GIFMAJOR+IM_GIFMINOR*0.1)));
 
-undef_int
-i_writegif(im,fd,colors,pixdev,fixed)
-    Imager::ImgRaw     im
-              int     fd
-              int     colors
-               int     pixdev
-            PREINIT:
-             int     fixedlen;
-            Imager__Color  fixed;
-            Imager__Color  tmp;
-            AV* av;
-            SV* sv1;
-             IV  Itmp;
-            int i;
-            CODE:
-            if (!SvROK(ST(4))) croak("Imager: Parameter 4 must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(4))) != SVt_PVAV) croak("Imager: Parameter 4 must be a reference to an array\n");
-            av=(AV*)SvRV(ST(4));
-            fixedlen=av_len(av)+1;
-            fixed=mymalloc( fixedlen*sizeof(i_color) );
-            for(i=0;i<fixedlen;i++) {
-              sv1=(*(av_fetch(av,i,0)));
-               if (sv_derived_from(sv1, "Imager::Color")) {
-                 Itmp = SvIV((SV*)SvRV(sv1));
-                 tmp = INT2PTR(i_color*, Itmp);
-               } else croak("Imager: one of the elements of array ref is not of Imager::Color type\n");
-               fixed[i]=*tmp;
-            }
-            RETVAL=i_writegif(im,fd,colors,pixdev,fixedlen,fixed);
-             myfree(fixed);
-             ST(0) = sv_newmortal();
-             if (RETVAL == 0) ST(0)=&PL_sv_undef;
-             else sv_setiv(ST(0), (IV)RETVAL);
-
-
-
-
-undef_int
-i_writegifmc(im,fd,colors)
-    Imager::ImgRaw    im
-              int     fd
-              int     colors
-
-
-undef_int
-i_writegif_gen(fd, ...)
-              int     fd
-      PROTOTYPE: $$@
-      PREINIT:
-       i_quantize quant;
-       i_img **imgs = NULL;
-       int img_count;
-       int i;
-       HV *hv;
-      CODE:
-       if (items < 3)
-           croak("Usage: i_writegif_gen(fd,hashref, images...)");
-       if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
-           croak("i_writegif_gen: Second argument must be a hash ref");
-       hv = (HV *)SvRV(ST(1));
-       memset(&quant, 0, sizeof(quant));
-       quant.mc_size = 256;
-       handle_quant_opts(&quant, hv);
-       img_count = items - 2;
-       RETVAL = 1;
-       if (img_count < 1) {
-         RETVAL = 0;
-         i_clear_error();
-         i_push_error(0, "You need to specify images to save");
-       }
-       else {
-          imgs = mymalloc(sizeof(i_img *) * img_count);
-          for (i = 0; i < img_count; ++i) {
-           SV *sv = ST(2+i);
-           imgs[i] = NULL;
-           if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
-             imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
-           }
-           else {
-             i_clear_error();
-             i_push_error(0, "Only images can be saved");
-             RETVAL = 0;
-             break;
-            }
-         }
-          if (RETVAL) {
-           RETVAL = i_writegif_gen(&quant, fd, imgs, img_count);
-          }
-         myfree(imgs);
-          if (RETVAL) {
-           copy_colors_back(hv, &quant);
-          }
-       }
-        ST(0) = sv_newmortal();
-        if (RETVAL == 0) ST(0)=&PL_sv_undef;
-        else sv_setiv(ST(0), (IV)RETVAL);
-       cleanup_quant_opts(&quant);
-
-
-undef_int
-i_writegif_callback(cb, maxbuffer,...)
-       int maxbuffer;
-      PREINIT:
-       i_quantize quant;
-       i_img **imgs = NULL;
-       int img_count;
-       int i;
-       HV *hv;
-        i_writer_data wd;
-      CODE:
-       if (items < 4)
-           croak("Usage: i_writegif_callback(\\&callback,maxbuffer,hashref, images...)");
-       if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
-           croak("i_writegif_callback: Second argument must be a hash ref");
-       hv = (HV *)SvRV(ST(2));
-       memset(&quant, 0, sizeof(quant));
-       quant.mc_size = 256;
-       handle_quant_opts(&quant, hv);
-       img_count = items - 3;
-       RETVAL = 1;
-       if (img_count < 1) {
-         RETVAL = 0;
-       }
-       else {
-          imgs = mymalloc(sizeof(i_img *) * img_count);
-          for (i = 0; i < img_count; ++i) {
-           SV *sv = ST(3+i);
-           imgs[i] = NULL;
-           if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
-             imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
-           }
-           else {
-             RETVAL = 0;
-             break;
-            }
-         }
-          if (RETVAL) {
-           wd.sv = ST(0);
-           RETVAL = i_writegif_callback(&quant, write_callback, (char *)&wd, maxbuffer, imgs, img_count);
-          }
-         myfree(imgs);
-          if (RETVAL) {
-           copy_colors_back(hv, &quant);
-          }
-       }
-       ST(0) = sv_newmortal();
-       if (RETVAL == 0) ST(0)=&PL_sv_undef;
-       else sv_setiv(ST(0), (IV)RETVAL);
-       cleanup_quant_opts(&quant);
-
-undef_int
-i_writegif_wiol(ig, opts,...)
-       Imager::IO ig
-      PREINIT:
-       i_quantize quant;
-       i_img **imgs = NULL;
-       int img_count;
-       int i;
-       HV *hv;
-      CODE:
-       if (items < 3)
-           croak("Usage: i_writegif_wiol(IO,hashref, images...)");
-       if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
-           croak("i_writegif_callback: Second argument must be a hash ref");
-       hv = (HV *)SvRV(ST(1));
-       memset(&quant, 0, sizeof(quant));
-       quant.mc_size = 256;
-       handle_quant_opts(&quant, hv);
-       img_count = items - 2;
-       RETVAL = 1;
-       if (img_count < 1) {
-         RETVAL = 0;
-       }
-       else {
-          imgs = mymalloc(sizeof(i_img *) * img_count);
-          for (i = 0; i < img_count; ++i) {
-           SV *sv = ST(2+i);
-           imgs[i] = NULL;
-           if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) {
-             imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv)));
-           }
-           else {
-             RETVAL = 0;
-             break;
-            }
-         }
-          if (RETVAL) {
-           RETVAL = i_writegif_wiol(ig, &quant, imgs, img_count);
-          }
-         myfree(imgs);
-          if (RETVAL) {
-           copy_colors_back(hv, &quant);
-          }
-       }
-       ST(0) = sv_newmortal();
-       if (RETVAL == 0) ST(0)=&PL_sv_undef;
-       else sv_setiv(ST(0), (IV)RETVAL);
-       cleanup_quant_opts(&quant);
-
-void
-i_readgif(fd)
-              int     fd
-             PREINIT:
-               int*    colour_table;
-               int     colours, q, w;
-             i_img*    rimg;
-                 SV*    temp[3];
-                 AV*    ct; 
-                 SV*    r;
-              PPCODE:
-              colour_table = NULL;
-               colours = 0;
-
-       if(GIMME_V == G_ARRAY) {
-            rimg = i_readgif(fd,&colour_table,&colours);
-        } else {
-            /* don't waste time with colours if they aren't wanted */
-            rimg = i_readgif(fd,NULL,NULL);
-        }
-       
-       if (colour_table == NULL) {
-            EXTEND(SP,1);
-            r=sv_newmortal();
-            sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-            PUSHs(r);
-       } else {
-            /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
-            /* I don't know if I have the reference counts right or not :( */
-            /* Neither do I :-) */
-            /* No Idea here either */
-
-            ct=newAV();
-            av_extend(ct, colours);
-            for(q=0; q<colours; q++) {
-                for(w=0; w<3; w++)
-                    temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
-                av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
-            }
-            myfree(colour_table);
-
-            EXTEND(SP,2);
-            r = sv_newmortal();
-            sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-            PUSHs(r);
-            PUSHs(newRV_noinc((SV*)ct));
-        }
-
-void
-i_readgif_wiol(ig)
-     Imager::IO         ig
-             PREINIT:
-               int*    colour_table;
-               int     colours, q, w;
-             i_img*    rimg;
-                 SV*    temp[3];
-                 AV*    ct; 
-                 SV*    r;
-              PPCODE:
-              colour_table = NULL;
-               colours = 0;
-
-       if(GIMME_V == G_ARRAY) {
-            rimg = i_readgif_wiol(ig,&colour_table,&colours);
-        } else {
-            /* don't waste time with colours if they aren't wanted */
-            rimg = i_readgif_wiol(ig,NULL,NULL);
-        }
-       
-       if (colour_table == NULL) {
-            EXTEND(SP,1);
-            r=sv_newmortal();
-            sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-            PUSHs(r);
-       } else {
-            /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
-            /* I don't know if I have the reference counts right or not :( */
-            /* Neither do I :-) */
-            /* No Idea here either */
-
-            ct=newAV();
-            av_extend(ct, colours);
-            for(q=0; q<colours; q++) {
-                for(w=0; w<3; w++)
-                    temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
-                av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
-            }
-            myfree(colour_table);
-
-            EXTEND(SP,2);
-            r = sv_newmortal();
-            sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-            PUSHs(r);
-            PUSHs(newRV_noinc((SV*)ct));
-        }
-
-Imager::ImgRaw
-i_readgif_single_wiol(ig, page=0)
-       Imager::IO      ig
-        int            page
-
-void
-i_readgif_scalar(...)
-          PROTOTYPE: $
-            PREINIT:
-               char*    data;
-             STRLEN     length;
-               int*    colour_table;
-               int     colours, q, w;
-             i_img*    rimg;
-                 SV*    temp[3];
-                 AV*    ct; 
-                 SV*    r;
-              PPCODE:
-        data = (char *)SvPV(ST(0), length);
-        colour_table=NULL;
-        colours=0;
-
-       if(GIMME_V == G_ARRAY) {  
-            rimg=i_readgif_scalar(data,length,&colour_table,&colours);
-        } else {
-            /* don't waste time with colours if they aren't wanted */
-            rimg=i_readgif_scalar(data,length,NULL,NULL);
-        }
-
-       if (colour_table == NULL) {
-            EXTEND(SP,1);
-            r=sv_newmortal();
-            sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-            PUSHs(r);
-       } else {
-            /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
-            /* I don't know if I have the reference counts right or not :( */
-            /* Neither do I :-) */
-            ct=newAV();
-            av_extend(ct, colours);
-            for(q=0; q<colours; q++) {
-                for(w=0; w<3; w++)
-                    temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
-                av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
-            }
-            myfree(colour_table);
-            
-            EXTEND(SP,2);
-            r=sv_newmortal();
-            sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-            PUSHs(r);
-            PUSHs(newRV_noinc((SV*)ct));
-        }
-
-void
-i_readgif_callback(...)
-          PROTOTYPE: &
-            PREINIT:
-               int*    colour_table;
-               int     colours, q, w;
-             i_img*    rimg;
-                 SV*    temp[3];
-                 AV*    ct; 
-                 SV*    r;
-       i_reader_data    rd;
-              PPCODE:
-       rd.sv = ST(0);
-        colour_table=NULL;
-        colours=0;
-
-       if(GIMME_V == G_ARRAY) {  
-            rimg=i_readgif_callback(read_callback, (char *)&rd,&colour_table,&colours);
-        } else {
-            /* don't waste time with colours if they aren't wanted */
-            rimg=i_readgif_callback(read_callback, (char *)&rd,NULL,NULL);
-        }
-
-       if (colour_table == NULL) {
-            EXTEND(SP,1);
-            r=sv_newmortal();
-            sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-            PUSHs(r);
-       } else {
-            /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */
-            /* I don't know if I have the reference counts right or not :( */
-            /* Neither do I :-) */
-            /* Neither do I - maybe I'll move this somewhere */
-            ct=newAV();
-            av_extend(ct, colours);
-            for(q=0; q<colours; q++) {
-                for(w=0; w<3; w++)
-                    temp[w]=sv_2mortal(newSViv(colour_table[q*3 + w]));
-                av_store(ct, q, (SV*)newRV_noinc((SV*)av_make(3, temp)));
-            }
-            myfree(colour_table);
-            
-            EXTEND(SP,2);
-            r=sv_newmortal();
-            sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-            PUSHs(r);
-            PUSHs(newRV_noinc((SV*)ct));
-        }
-
-void
-i_readgif_multi(fd)
-        int     fd
-      PREINIT:
-        i_img **imgs;
-        int count;
-        int i;
-      PPCODE:
-        imgs = i_readgif_multi(fd, &count);
-        if (imgs) {
-          EXTEND(SP, count);
-          for (i = 0; i < count; ++i) {
-            SV *sv = sv_newmortal();
-            sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
-            PUSHs(sv);
-          }
-          myfree(imgs);
-        }
-
-void
-i_readgif_multi_scalar(data)
-      PREINIT:
-        i_img **imgs;
-        int count;
-        char *data;
-        STRLEN length;
-        int i;
-      PPCODE:
-        data = (char *)SvPV(ST(0), length);
-        imgs = i_readgif_multi_scalar(data, length, &count);
-        if (imgs) {
-          EXTEND(SP, count);
-          for (i = 0; i < count; ++i) {
-            SV *sv = sv_newmortal();
-            sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
-            PUSHs(sv);
-          }
-          myfree(imgs);
-        }
-
-void
-i_readgif_multi_callback(cb)
-      PREINIT:
-        i_reader_data rd;
-        i_img **imgs;
-        int count;
-        int i;
-      PPCODE:
-        rd.sv = ST(0);
-        imgs = i_readgif_multi_callback(read_callback, (char *)&rd, &count);
-        if (imgs) {
-          EXTEND(SP, count);
-          for (i = 0; i < count; ++i) {
-            SV *sv = sv_newmortal();
-            sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
-            PUSHs(sv);
-          }
-          myfree(imgs);
-        }
-
-void
-i_readgif_multi_wiol(ig)
-        Imager::IO ig
-      PREINIT:
-        i_img **imgs;
-        int count;
-        int i;
-      PPCODE:
-        imgs = i_readgif_multi_wiol(ig, &count);
-        if (imgs) {
-          EXTEND(SP, count);
-          for (i = 0; i < count; ++i) {
-            SV *sv = sv_newmortal();
-            sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
-            PUSHs(sv);
-          }
-          myfree(imgs);
-        }
-
-
-#endif
-
-
-
-Imager::ImgRaw
-i_readpnm_wiol(ig, length)
-        Imager::IO     ig
-              int     length
-
-
-undef_int
-i_writeppm_wiol(im, ig)
-    Imager::ImgRaw     im
-        Imager::IO     ig
-
-
-Imager::ImgRaw
-i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
-        Imager::IO     ig
-              int     x
-              int     y
-              int     datachannels
-              int     storechannels
-              int     intrl
-
-undef_int
-i_writeraw_wiol(im,ig)
-    Imager::ImgRaw     im
-        Imager::IO     ig
-
-undef_int
-i_writebmp_wiol(im,ig)
-    Imager::ImgRaw     im
-        Imager::IO     ig
-
-Imager::ImgRaw
-i_readbmp_wiol(ig)
-        Imager::IO     ig
-
-
-undef_int
-i_writetga_wiol(im,ig, wierdpack, compress, idstring)
-    Imager::ImgRaw     im
-        Imager::IO     ig
-               int     wierdpack
-               int     compress
-              char*    idstring
-            PREINIT:
-                int idlen;
-              CODE:
-                idlen  = SvCUR(ST(4));
-                RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
-                OUTPUT:
-                RETVAL
-
-
-Imager::ImgRaw
-i_readtga_wiol(ig, length)
-        Imager::IO     ig
-               int     length
-
-
-undef_int
-i_writergb_wiol(im,ig, wierdpack, compress, idstring)
-    Imager::ImgRaw     im
-        Imager::IO     ig
-               int     wierdpack
-               int     compress
-              char*    idstring
-            PREINIT:
-                int idlen;
-              CODE:
-                idlen  = SvCUR(ST(4));
-                RETVAL = i_writergb_wiol(im, ig, wierdpack, compress, idstring, idlen);
-                OUTPUT:
-                RETVAL
-
-
-Imager::ImgRaw
-i_readrgb_wiol(ig, length)
-        Imager::IO     ig
-               int     length
-
-
-
-Imager::ImgRaw
-i_scaleaxis(im,Value,Axis)
+Imager::ImgRaw
+i_scaleaxis(im,Value,Axis)
     Imager::ImgRaw     im
              float     Value
               int     Axis
@@ -2897,6 +2458,12 @@ i_scale_nn(im,scx,scy)
              float     scx
              float     scy
 
+Imager::ImgRaw
+i_scale_mixing(im, width, height)
+    Imager::ImgRaw     im
+              int     width
+              int     height
+
 Imager::ImgRaw
 i_haar(im)
     Imager::ImgRaw     im
@@ -2906,6 +2473,23 @@ i_count_colors(im,maxc)
     Imager::ImgRaw     im
                int     maxc
 
+void
+i_get_anonymous_color_histo(im, maxc = 0x40000000)
+   Imager::ImgRaw  im
+   int maxc
+    PREINIT:
+        int i;
+        unsigned int * col_usage = NULL;
+        int col_cnt;
+    PPCODE:
+       col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc);
+        EXTEND(SP, col_cnt);
+        for (i = 0; i < col_cnt; i++)  {
+            PUSHs(sv_2mortal(newSViv( col_usage[i])));
+        }
+        myfree(col_usage);
+        XSRETURN(col_cnt);
+
 
 Imager::ImgRaw
 i_transform(im,opx,opy,parm)
@@ -3056,6 +2640,10 @@ void
 i_hardinvert(im)
     Imager::ImgRaw     im
 
+void
+i_hardinvertall(im)
+    Imager::ImgRaw     im
+
 void
 i_noise(im,amount,type)
     Imager::ImgRaw     im
@@ -3187,7 +2775,7 @@ Imager::ImgRaw
 i_diff_image(im, im2, mindist=0)
     Imager::ImgRaw     im
     Imager::ImgRaw     im2
-               int     mindist
+            double     mindist
 
 undef_int
 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
@@ -3210,7 +2798,7 @@ i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_para
            croak("i_fountain: argument 11 must be an array ref");
         
        asegs = (AV *)SvRV(ST(10));
-        segs = load_fount_segs(asegs, &count);
+        segs = load_fount_segs(aTHX_ asegs, &count);
         RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, 
                             super_sample, ssample_param, count, segs);
         myfree(segs);
@@ -3237,13 +2825,18 @@ i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_pa
            croak("i_fountain: argument 11 must be an array ref");
         
        asegs = (AV *)SvRV(ST(9));
-        segs = load_fount_segs(asegs, &count);
+        segs = load_fount_segs(aTHX_ asegs, &count);
         RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, 
                                   super_sample, ssample_param, count, segs);
         myfree(segs);        
       OUTPUT:
         RETVAL
 
+Imager::FillHandle
+i_new_fill_opacity(other_fill, alpha_mult)
+    Imager::FillHandle other_fill
+    double alpha_mult
+
 void
 i_errors()
       PREINIT:
@@ -3268,6 +2861,14 @@ i_errors()
          ++i;
        }
 
+void
+i_clear_error()
+
+void
+i_push_error(code, msg)
+       int code
+       const char *msg
+
 undef_int
 i_nearest_color(im, ...)
     Imager::ImgRaw     im
@@ -3350,17 +2951,18 @@ DSO_funclist(dso_handle_v)
             PREINIT:
               int i;
               DSO_handle *dso_handle;
+              func_ptr *functions;
             PPCODE:
               dso_handle=(DSO_handle*)dso_handle_v;
+              functions = DSO_funclist(dso_handle);
               i=0;
-              while( dso_handle->function_list[i].name != NULL) {
+              while( functions[i].name != NULL) {
                 EXTEND(SP,1);
-                PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i].name,0)));
+                PUSHs(sv_2mortal(newSVpv(functions[i].name,0)));
                 EXTEND(SP,1);
-                PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i++].pcode,0)));
+                PUSHs(sv_2mortal(newSVpv(functions[i++].pcode,0)));
               }
 
-
 void
 DSO_call(handle,func_index,hv)
               void*  handle
@@ -3373,8 +2975,6 @@ DSO_call(handle,func_index,hv)
               if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
               DSO_call( (DSO_handle *)handle,func_index,hv);
 
-
-
 SV *
 i_get_pixel(im, x, y)
        Imager::ImgRaw im
@@ -3421,13 +3021,14 @@ i_img_to_pal(src, quant)
           croak("i_img_to_pal: second argument must be a hash ref");
         hv = (HV *)SvRV(ST(1));
         memset(&quant, 0, sizeof(quant));
+       quant.version = 1;
         quant.mc_size = 256;
-       handle_quant_opts(&quant, hv);
+       ip_handle_quant_opts(aTHX_ &quant, hv);
         RETVAL = i_img_to_pal(src, &quant);
         if (RETVAL) {
-          copy_colors_back(hv, &quant);
+          ip_copy_colors_back(aTHX_ hv, &quant);
         }
-       cleanup_quant_opts(&quant);
+       ip_cleanup_quant_opts(aTHX_ &quant);
       OUTPUT:
         RETVAL
 
@@ -3481,6 +3082,7 @@ i_ppal(im, l, y, ...)
           for (i=0; i < items-3; ++i) {
             work[i] = SvIV(ST(i+3));
           }
+          validate_i_ppal(im, work, items - 3);
           RETVAL = i_ppal(im, l, l+items-3, y, work);
           myfree(work);
         }
@@ -3490,6 +3092,28 @@ i_ppal(im, l, y, ...)
       OUTPUT:
         RETVAL
 
+int
+i_ppal_p(im, l, y, data)
+        Imager::ImgRaw  im
+        int     l
+        int     y
+        SV *data
+      PREINIT:
+        i_palidx const *work;
+        STRLEN len;
+      CODE:
+        work = (i_palidx const *)SvPV(data, len);
+        len /= sizeof(i_palidx);
+        if (len > 0) {
+          validate_i_ppal(im, work, len);
+          RETVAL = i_ppal(im, l, l+len, y, work);
+        }
+        else {
+          RETVAL = 0;
+        }
+      OUTPUT:
+        RETVAL
+
 SV *
 i_addcolors(im, ...)
         Imager::ImgRaw  im
@@ -3658,6 +3282,108 @@ i_gsamp(im, l, r, y, ...)
           }
         }
 
+undef_neg_int
+i_gsamp_bits(im, l, r, y, bits, target, offset, ...)
+        Imager::ImgRaw im
+        int l
+        int r
+        int y
+       int bits
+       AV *target
+       int offset
+      PREINIT:
+        int *chans;
+        int chan_count;
+        unsigned *data;
+        int count, i;
+      CODE:
+       i_clear_error();
+        if (items < 8)
+          croak("No channel numbers supplied to g_samp()");
+        if (l < r) {
+          chan_count = items - 7;
+          chans = mymalloc(sizeof(int) * chan_count);
+          for (i = 0; i < chan_count; ++i)
+            chans[i] = SvIV(ST(i+7));
+          data = mymalloc(sizeof(unsigned) * (r-l) * chan_count);
+          count = i_gsamp_bits(im, l, r, y, data, chans, chan_count, bits);
+         myfree(chans);
+         for (i = 0; i < count; ++i) {
+           av_store(target, i+offset, newSVuv(data[i]));
+         }
+         myfree(data);
+         RETVAL = count;
+        }
+        else {
+         RETVAL = 0;
+        }
+      OUTPUT:
+       RETVAL
+
+undef_neg_int
+i_psamp_bits(im, l, y, bits, channels_sv, data_av, data_offset = 0, pixel_count = -1)
+        Imager::ImgRaw im
+        int l
+        int y
+       int bits
+       SV *channels_sv
+       AV *data_av
+        int data_offset
+        int pixel_count
+      PREINIT:
+       int chan_count;
+       int *channels;
+       int data_count;
+       int data_used;
+       unsigned *data;
+       int i;
+      CODE:
+       i_clear_error();
+       if (SvOK(channels_sv)) {
+         AV *channels_av;
+         if (!SvROK(channels_sv) || SvTYPE(SvRV(channels_sv)) != SVt_PVAV) {
+           croak("channels is not an array ref");
+         }
+         channels_av = (AV *)SvRV(channels_sv);
+         chan_count = av_len(channels_av) + 1;
+         if (chan_count < 1) {
+           croak("i_psamp_bits: no channels provided");
+         }
+         channels = mymalloc(sizeof(int) * chan_count);
+         for (i = 0; i < chan_count; ++i)
+           channels[i] = SvIV(*av_fetch(channels_av, i, 0));
+        }
+       else {
+         chan_count = im->channels;
+         channels = NULL;
+       }
+
+       data_count = av_len(data_av) + 1;
+       if (data_offset < 0) {
+         croak("data_offset must by non-negative");
+       }
+       if (data_offset > data_count) {
+         croak("data_offset greater than number of samples supplied");
+        }
+       if (pixel_count == -1 || 
+           data_offset + pixel_count * chan_count > data_count) {
+         pixel_count = (data_count - data_offset) / chan_count;
+       }
+
+       data_used = pixel_count * chan_count;
+       data = mymalloc(sizeof(unsigned) * data_count);
+       for (i = 0; i < data_used; ++i)
+         data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0));
+
+       RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels, 
+                             chan_count, bits);
+
+       if (data)
+         myfree(data);
+       if (channels)
+         myfree(channels);
+      OUTPUT:
+       RETVAL
 
 Imager::ImgRaw
 i_img_masked_new(targ, mask, x, y, w, h)
@@ -3850,6 +3576,7 @@ i_glin(im, l, r, y)
       PPCODE:
         if (l < r) {
           vals = mymalloc((r-l) * sizeof(i_color));
+          memset(vals, 0, (r-l) * sizeof(i_color));
           count = i_glin(im, l, r, y, vals);
          if (GIMME_V == G_ARRAY) {
             EXTEND(SP, count);
@@ -3878,9 +3605,14 @@ i_glinf(im, l, r, y)
       PREINIT:
         i_fcolor *vals;
         int count, i;
+        i_fcolor zero;
       PPCODE:
+       for (i = 0; i < MAXCHANNELS; ++i)
+         zero.channel[i] = 0;
         if (l < r) {
           vals = mymalloc((r-l) * sizeof(i_fcolor));
+          for (i = 0; i < r-l; ++i)
+           vals[i] = zero;
           count = i_glinf(im, l, r, y, vals);
           if (GIMME_V == G_ARRAY) {
             EXTEND(SP, count);
@@ -3906,6 +3638,10 @@ i_img_16_new(x, y, ch)
         int y
         int ch
 
+Imager::ImgRaw
+i_img_to_rgb16(im)
+       Imager::ImgRaw im
+
 Imager::ImgRaw
 i_img_double_new(x, y, ch)
         int x
@@ -4072,396 +3808,7 @@ i_tags_count(im)
       OUTPUT:
         RETVAL
 
-#ifdef HAVE_WIN32
-
-void
-i_wf_bbox(face, size, text)
-       char *face
-       int size
-       char *text
-      PREINIT:
-       int cords[BOUNDING_BOX_COUNT];
-        int rc, i;
-      PPCODE:
-        if (rc = i_wf_bbox(face, size, text, strlen(text), cords)) {
-          EXTEND(SP, rc);  
-          for (i = 0; i < rc; ++i) 
-            PUSHs(sv_2mortal(newSViv(cords[i])));
-        }
-
-undef_int
-i_wf_text(face, im, tx, ty, cl, size, text, align, aa)
-       char *face
-       Imager::ImgRaw im
-       int tx
-       int ty
-       Imager::Color cl
-       int size
-       char *text
-       int align
-       int aa
-      CODE:
-       RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text), 
-                          align, aa);
-      OUTPUT:
-       RETVAL
-
-undef_int
-i_wf_cp(face, im, tx, ty, channel, size, text, align, aa)
-       char *face
-       Imager::ImgRaw im
-       int tx
-       int ty
-       int channel
-       int size
-       char *text
-       int align
-       int aa
-      CODE:
-       RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text), 
-                        align, aa);
-      OUTPUT:
-       RETVAL
-
-undef_int
-i_wf_addfont(font)
-        char *font
-
-#endif
-
-#ifdef HAVE_FT2
-
-MODULE = Imager         PACKAGE = Imager::Font::FT2     PREFIX=FT2_
-
-#define FT2_DESTROY(font) i_ft2_destroy(font)
-
-void
-FT2_DESTROY(font)
-        Imager::Font::FT2 font
-
-MODULE = Imager         PACKAGE = Imager::Font::FreeType2 
-
-Imager::Font::FT2
-i_ft2_new(name, index)
-        char *name
-        int index
-
-undef_int
-i_ft2_setdpi(font, xdpi, ydpi)
-        Imager::Font::FT2 font
-        int xdpi
-        int ydpi
-
-void
-i_ft2_getdpi(font)
-        Imager::Font::FT2 font
-      PREINIT:
-        int xdpi, ydpi;
-      CODE:
-        if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
-          EXTEND(SP, 2);
-          PUSHs(sv_2mortal(newSViv(xdpi)));
-          PUSHs(sv_2mortal(newSViv(ydpi)));
-        }
-
-undef_int
-i_ft2_sethinting(font, hinting)
-        Imager::Font::FT2 font
-        int hinting
-
-undef_int
-i_ft2_settransform(font, matrix)
-        Imager::Font::FT2 font
-      PREINIT:
-        double matrix[6];
-        int len;
-        AV *av;
-        SV *sv1;
-        int i;
-      CODE:
-        if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
-          croak("i_ft2_settransform: parameter 2 must be an array ref\n");
-       av=(AV*)SvRV(ST(1));
-       len=av_len(av)+1;
-        if (len > 6)
-          len = 6;
-        for (i = 0; i < len; ++i) {
-         sv1=(*(av_fetch(av,i,0)));
-         matrix[i] = SvNV(sv1);
-        }
-        for (; i < 6; ++i)
-          matrix[i] = 0;
-        RETVAL = i_ft2_settransform(font, matrix);
-      OUTPUT:
-        RETVAL
-
-void
-i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
-        Imager::Font::FT2 font
-        double cheight
-        double cwidth
-        SV *text_sv
-       int utf8
-      PREINIT:
-        int bbox[BOUNDING_BOX_COUNT];
-        int i;
-        char *text;
-        STRLEN text_len;
-        int rc;
-      PPCODE:
-        text = SvPV(text_sv, text_len);
-#ifdef SvUTF8
-        if (SvUTF8(text_sv))
-          utf8 = 1;
-#endif
-        rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8);
-        if (rc) {
-          EXTEND(SP, rc);
-          for (i = 0; i < rc; ++i)
-            PUSHs(sv_2mortal(newSViv(bbox[i])));
-        }
-
-void
-i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
-        Imager::Font::FT2 font
-        double cheight
-        double cwidth
-        char *text
-        int vlayout
-        int utf8
-      PREINIT:
-        int bbox[8];
-        int i;
-      PPCODE:
-#ifdef SvUTF8
-        if (SvUTF8(ST(3)))
-          utf8 = 1;
-#endif
-        if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
-                         utf8, bbox)) {
-          EXTEND(SP, 8);
-          for (i = 0; i < 8; ++i)
-            PUSHs(sv_2mortal(newSViv(bbox[i])));
-        }
-
-undef_int
-i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
-        Imager::Font::FT2 font
-        Imager::ImgRaw im
-        int tx
-        int ty
-        Imager::Color cl
-        double cheight
-        double cwidth
-        int align
-        int aa
-        int vlayout
-        int utf8
-      PREINIT:
-        char *text;
-        STRLEN len;
-      CODE:
-#ifdef SvUTF8
-        if (SvUTF8(ST(7))) {
-          utf8 = 1;
-        }
-#endif
-        text = SvPV(ST(7), len);
-        RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
-                            len, align, aa, vlayout, utf8);
-      OUTPUT:
-        RETVAL
-
-undef_int
-i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8)
-        Imager::Font::FT2 font
-        Imager::ImgRaw im
-        int tx
-        int ty
-        int channel
-        double cheight
-        double cwidth
-        char *text
-        int align
-        int aa
-        int vlayout
-        int utf8
-      CODE:
-#ifdef SvUTF8
-        if (SvUTF8(ST(7)))
-          utf8 = 1;
-#endif
-        RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
-                          strlen(text), align, aa, vlayout, 1);
-      OUTPUT:
-        RETVAL
-
-void
-ft2_transform_box(font, x0, x1, x2, x3)
-        Imager::Font::FT2 font
-        int x0
-        int x1
-        int x2
-        int x3
-      PREINIT:
-        int box[4];
-      PPCODE:
-        box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
-        ft2_transform_box(font, box);
-          EXTEND(SP, 4);
-          PUSHs(sv_2mortal(newSViv(box[0])));
-          PUSHs(sv_2mortal(newSViv(box[1])));
-          PUSHs(sv_2mortal(newSViv(box[2])));
-          PUSHs(sv_2mortal(newSViv(box[3])));
-
-void
-i_ft2_has_chars(handle, text_sv, utf8)
-        Imager::Font::FT2 handle
-        SV  *text_sv
-        int utf8
-      PREINIT:
-        char *text;
-        STRLEN len;
-        char *work;
-        int count;
-        int i;
-      PPCODE:
-#ifdef SvUTF8
-        if (SvUTF8(text_sv))
-          utf8 = 1;
-#endif
-        text = SvPV(text_sv, len);
-        work = mymalloc(len);
-        count = i_ft2_has_chars(handle, text, len, utf8, work);
-        if (GIMME_V == G_ARRAY) {
-          EXTEND(SP, count);
-          for (i = 0; i < count; ++i) {
-            PUSHs(sv_2mortal(newSViv(work[i])));
-          }
-        }
-        else {
-          EXTEND(SP, 1);
-          PUSHs(sv_2mortal(newSVpv(work, count)));
-        }
-        myfree(work);
-
-void
-i_ft2_face_name(handle)
-        Imager::Font::FT2 handle
-      PREINIT:
-        char name[255];
-        int len;
-      PPCODE:
-        len = i_ft2_face_name(handle, name, sizeof(name));
-        if (len) {
-          EXTEND(SP, 1);
-          PUSHs(sv_2mortal(newSVpv(name, 0)));
-        }
-
-undef_int
-i_ft2_can_face_name()
-
-void
-i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
-        Imager::Font::FT2 handle
-        SV *text_sv
-        int utf8
-        int reliable_only
-      PREINIT:
-        char const *text;
-        STRLEN work_len;
-        int len;
-        char name[255];
-      PPCODE:
-#ifdef SvUTF8
-        if (SvUTF8(text_sv))
-          utf8 = 1;
-#endif
-        text = SvPV(text_sv, work_len);
-        len = work_len;
-        while (len) {
-          unsigned long ch;
-          if (utf8) {
-            ch = i_utf8_advance(&text, &len);
-            if (ch == ~0UL) {
-              i_push_error(0, "invalid UTF8 character");
-              break;
-            }
-          }
-          else {
-            ch = *text++;
-            --len;
-          }
-          EXTEND(SP, 1);
-          if (i_ft2_glyph_name(handle, ch, name, sizeof(name), 
-                                         reliable_only)) {
-            PUSHs(sv_2mortal(newSVpv(name, 0)));
-          }
-          else {
-            PUSHs(&PL_sv_undef);
-          } 
-        }
-
-int
-i_ft2_can_do_glyph_names()
-
-int
-i_ft2_face_has_glyph_names(handle)
-        Imager::Font::FT2 handle
-
-int
-i_ft2_is_multiple_master(handle)
-        Imager::Font::FT2 handle
-
-void
-i_ft2_get_multiple_masters(handle)
-        Imager::Font::FT2 handle
-      PREINIT:
-        i_font_mm mm;
-        int i;
-      PPCODE:
-        if (i_ft2_get_multiple_masters(handle, &mm)) {
-          EXTEND(SP, 2+mm.num_axis);
-          PUSHs(sv_2mortal(newSViv(mm.num_axis)));
-          PUSHs(sv_2mortal(newSViv(mm.num_designs)));
-          for (i = 0; i < mm.num_axis; ++i) {
-            AV *av = newAV();
-            SV *sv;
-            av_extend(av, 3);
-            sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name));
-            SvREFCNT_inc(sv);
-            av_store(av, 0, sv);
-            sv = newSViv(mm.axis[i].minimum);
-            SvREFCNT_inc(sv);
-            av_store(av, 1, sv);
-            sv = newSViv(mm.axis[i].maximum);
-            SvREFCNT_inc(sv);
-            av_store(av, 2, sv);
-            PUSHs(newRV_noinc((SV *)av));
-          }
-        }
-
-undef_int
-i_ft2_set_mm_coords(handle, ...)
-        Imager::Font::FT2 handle
-      PROTOTYPE: DISABLE
-      PREINIT:
-        long *coords;
-        int ix_coords, i;
-      CODE:
-        /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so
-           transfer the array manually */
-        ix_coords = items-1;
-        coords = mymalloc(sizeof(long) * ix_coords);
-       for (i = 0; i < ix_coords; ++i) {
-          coords[i] = (long)SvIV(ST(1+i));
-        }
-        RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords);
-        myfree(coords);
-      OUTPUT:
-        RETVAL
 
-#endif
 
 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
 
@@ -4469,6 +3816,13 @@ void
 IFILL_DESTROY(fill)
         Imager::FillHandle fill
 
+int
+IFILL_CLONE_SKIP(...)
+    CODE:
+        RETVAL = 1;
+    OUTPUT:
+        RETVAL
+
 MODULE = Imager         PACKAGE = Imager
 
 Imager::FillHandle
@@ -4594,7 +3948,12 @@ SV *
 i_int_hlines_dump(hlines)
        Imager::Internal::Hlines hlines
 
+int
+i_int_hlines_CLONE_SKIP(cls)
+       SV *cls
+
 #endif
 
 BOOT:
         PERL_SET_GLOBAL_CALLBACKS;
+       PERL_PL_SET_GLOBAL_CALLBACKS;
\ No newline at end of file