]> git.imager.perl.org - imager.git/blobdiff - Imager.xs
new samples
[imager.git] / Imager.xs
index 4330fef38edb76eab6e3c86c7095a88eb0ee3709..b0666a45fb71b30687d49757030f5634e00ef4ee 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -18,13 +18,7 @@ typedef io_glue* Imager__IO;
 typedef i_color* Imager__Color;
 typedef i_fcolor* Imager__Color__Float;
 typedef i_img*   Imager__ImgRaw;
-
-/* later perls define this macro to prevent warning when converting
-from IV to pointer types */
-
-#ifndef INT2PTR
-#define INT2PTR(type,value) (type)(value)
-#endif
+typedef int undef_neg_int;
 
 #ifdef HAVE_LIBTT
 typedef TT_Fonthandle* Imager__Font__TT;
@@ -34,13 +28,89 @@ typedef TT_Fonthandle* Imager__Font__TT;
 typedef FT2_Fonthandle* Imager__Font__FT2;
 #endif
 
+/* These functions are all shared - then comes platform dependant code */
+static int getstr(void *hv_t,char *key,char **store) {
+  SV** svpp;
+  HV* hv=(HV*)hv_t;
+
+  mm_log((1,"getstr(hv_t 0x%X, key %s, store 0x%X)\n",hv_t,key,store));
+
+  if ( !hv_exists(hv,key,strlen(key)) ) return 0;
+
+  svpp=hv_fetch(hv, key, strlen(key), 0);
+  *store=SvPV(*svpp, PL_na );
+
+  return 1;
+}
+
+static int getint(void *hv_t,char *key,int *store) {
+  SV** svpp;
+  HV* hv=(HV*)hv_t;  
+
+  mm_log((1,"getint(hv_t 0x%X, key %s, store 0x%X)\n",hv_t,key,store));
+
+  if ( !hv_exists(hv,key,strlen(key)) ) return 0;
+
+  svpp=hv_fetch(hv, key, strlen(key), 0);
+  *store=(int)SvIV(*svpp);
+  return 1;
+}
+
+static int getdouble(void *hv_t,char* key,double *store) {
+  SV** svpp;
+  HV* hv=(HV*)hv_t;
+
+  mm_log((1,"getdouble(hv_t 0x%X, key %s, store 0x%X)\n",hv_t,key,store));
+
+  if ( !hv_exists(hv,key,strlen(key)) ) return 0;
+  svpp=hv_fetch(hv, key, strlen(key), 0);
+  *store=(float)SvNV(*svpp);
+  return 1;
+}
+
+static int getvoid(void *hv_t,char* key,void **store) {
+  SV** svpp;
+  HV* hv=(HV*)hv_t;
+
+  mm_log((1,"getvoid(hv_t 0x%X, key %s, store 0x%X)\n",hv_t,key,store));
+
+  if ( !hv_exists(hv,key,strlen(key)) ) return 0;
+
+  svpp=hv_fetch(hv, key, strlen(key), 0);
+  *store = INT2PTR(void*, SvIV(*svpp));
+
+  return 1;
+}
+
+static int getobj(void *hv_t,char *key,char *type,void **store) {
+  SV** svpp;
+  HV* hv=(HV*)hv_t;
+
+  mm_log((1,"getobj(hv_t 0x%X, key %s,type %s, store 0x%X)\n",hv_t,key,type,store));
+
+  if ( !hv_exists(hv,key,strlen(key)) ) return 0;
+
+  svpp=hv_fetch(hv, key, strlen(key), 0);
+
+  if (sv_derived_from(*svpp,type)) {
+    IV tmp = SvIV((SV*)SvRV(*svpp));
+    *store = INT2PTR(void*, tmp);
+  } else {
+    mm_log((1,"getobj: key exists in hash but is not of correct type"));
+    return 0;
+  }
+
+  return 1;
+}
+
+UTIL_table_t i_UTIL_table={getstr,getint,getdouble,getvoid,getobj};
 
 void my_SvREFCNT_dec(void *p) {
   SvREFCNT_dec((SV*)p);
 }
 
 
-void
+static void
 log_entry(char *string, int level) {
   mm_log((level, string));
 }
@@ -343,7 +413,6 @@ static ssize_t io_reader(void *p, void *data, size_t size) {
   struct cbdata *cbd = p;
   ssize_t total;
   char *out = data; /* so we can do pointer arithmetic */
-  int i;
 
   if (cbd->writing) {
     if (write_flush(cbd) <= 0)
@@ -372,7 +441,7 @@ static ssize_t io_reader(void *p, void *data, size_t size) {
       cbd->where = 0;
       cbd->used  = did_read;
 
-      copy_size = min(size, cbd->used);
+      copy_size = i_min(size, cbd->used);
       memcpy(out, cbd->buffer, copy_size);
       cbd->where += copy_size;
       out   += copy_size;
@@ -425,6 +494,7 @@ static void io_destroyer(void *p) {
   SvREFCNT_dec(cbd->readcb);
   SvREFCNT_dec(cbd->seekcb);
   SvREFCNT_dec(cbd->closecb);
+  myfree(cbd);
 }
 
 struct value_name {
@@ -489,6 +559,7 @@ static struct value_name orddith_names[] =
   { "custom", od_custom, },
 };
 
+#if 0
 static int
 hv_fetch_bool(HV *hv, char *name, int def) {
   SV **sv;
@@ -512,6 +583,7 @@ hv_fetch_int(HV *hv, char *name, int def) {
   else
     return def;
 }
+#endif
 
 /* look through the hash for quantization options */
 static void handle_quant_opts(i_quantize *quant, HV *hv)
@@ -766,7 +838,8 @@ static void copy_colors_back(HV *hv, i_quantize *quant) {
 }
 
 /* loads the segments of a fountain fill into an array */
-i_fountain_seg *load_fount_segs(AV *asegs, int *count) {
+static i_fountain_seg *
+load_fount_segs(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
@@ -775,7 +848,6 @@ i_fountain_seg *load_fount_segs(AV *asegs, int *count) {
   */
   int i, j;
   AV *aseg;
-  SV *sv;
   i_fountain_seg *segs;
   double work[3];
   int worki[2];
@@ -855,6 +927,10 @@ i_fountain_seg *load_fount_segs(AV *asegs, int *count) {
 #define IFILL_DESTROY(fill) i_fill_destroy(fill);
 typedef i_fill_t* Imager__FillHandle;
 
+/* the m_init_log() function was called init_log(), renamed to reduce
+    potential naming conflicts */
+#define init_log m_init_log
+
 MODULE = Imager                PACKAGE = Imager::Color PREFIX = ICL_
 
 Imager::Color
@@ -1011,7 +1087,6 @@ io_new_buffer(data)
          char   *data
        PREINIT:
          size_t length;
-         SV* sv;
        CODE:
          SvPV(ST(0), length);
           SvREFCNT_inc(ST(0));
@@ -1057,7 +1132,7 @@ io_slurp(ig)
              data    = NULL;
               tlength = io_slurp(ig, &data);
               EXTEND(SP,1);
-              PUSHs(sv_2mortal(newSVpv(data,tlength)));
+              PUSHs(sv_2mortal(newSVpv((char *)data,tlength)));
               myfree(data);
 
 
@@ -1106,8 +1181,21 @@ i_img_empty_ch(im,x,y,ch)
               int     y
               int     ch
 
+Imager::ImgRaw
+i_sametype(im, x, y)
+    Imager::ImgRaw im
+               int x
+               int y
+
+Imager::ImgRaw
+i_sametype_chans(im, x, y, channels)
+    Imager::ImgRaw im
+               int x
+               int y
+               int channels
+
 void
-init_log(name,level)
+m_init_log(name,level)
              char*    name
               int     level
 
@@ -1159,27 +1247,30 @@ i_img_getdata(im)
     Imager::ImgRaw     im
              PPCODE:
               EXTEND(SP, 1);
-               PUSHs(im->idata ? sv_2mortal(newSVpv(im->idata, im->bytes)) 
+               PUSHs(im->idata ? 
+                    sv_2mortal(newSVpv((char *)im->idata, im->bytes)) 
                     : &PL_sv_undef);
 
 
 void
-i_draw(im,x1,y1,x2,y2,val)
+i_line(im,x1,y1,x2,y2,val,endp)
     Imager::ImgRaw     im
               int     x1
               int     y1
               int     x2
               int     y2
      Imager::Color     val
+              int     endp
 
 void
-i_line_aa(im,x1,y1,x2,y2,val)
+i_line_aa(im,x1,y1,x2,y2,val,endp)
     Imager::ImgRaw     im
               int     x1
               int     y1
               int     x2
               int     y2
      Imager::Color     val
+              int     endp
 
 void
 i_box(im,x1,y1,x2,y2,val)
@@ -1344,14 +1435,14 @@ i_poly_aa_cfill(im,xc,yc,fill)
 
 
 
-void
+undef_int
 i_flood_fill(im,seedx,seedy,dcol)
     Imager::ImgRaw     im
               int     seedx
               int     seedy
      Imager::Color     dcol
 
-void
+undef_int
 i_flood_cfill(im,seedx,seedy,fill)
     Imager::ImgRaw     im
               int     seedx
@@ -1390,11 +1481,16 @@ i_copy(im,src)
 
 
 undef_int
-i_rubthru(im,src,tx,ty)
+i_rubthru(im,src,tx,ty,src_minx,src_miny,src_maxx,src_maxy)
     Imager::ImgRaw     im
     Imager::ImgRaw     src
               int     tx
               int     ty
+              int     src_minx
+              int     src_miny
+              int     src_maxx
+              int     src_maxy
+
 
 undef_int
 i_flipxy(im, direction)
@@ -1407,12 +1503,34 @@ i_rotate90(im, degrees)
                int      degrees
 
 Imager::ImgRaw
-i_rotate_exact(im, amount)
+i_rotate_exact(im, amount, ...)
     Imager::ImgRaw      im
             double      amount
+      PREINIT:
+       i_color *backp = NULL;
+       i_fcolor *fbackp = NULL;
+       int i;
+       SV * sv1;
+      CODE:
+       /* extract the bg colors if any */
+       /* yes, this is kind of strange */
+       for (i = 2; i < items; ++i) {
+          sv1 = ST(i);
+          if (sv_derived_from(sv1, "Imager::Color")) {
+           IV tmp = SvIV((SV*)SvRV(sv1));
+           backp = INT2PTR(i_color *, tmp);
+         }
+         else if (sv_derived_from(sv1, "Imager::Color::Float")) {
+           IV tmp = SvIV((SV*)SvRV(sv1));
+           fbackp = INT2PTR(i_fcolor *, tmp);
+         }
+       }
+       RETVAL = i_rotate_exact_bg(im, amount, backp, fbackp);
+      OUTPUT:
+       RETVAL
 
 Imager::ImgRaw
-i_matrix_transform(im, xsize, ysize, matrix)
+i_matrix_transform(im, xsize, ysize, matrix, ...)
     Imager::ImgRaw      im
                int      xsize
                int      ysize
@@ -1422,6 +1540,8 @@ i_matrix_transform(im, xsize, ysize, matrix)
         IV len;
         SV *sv1;
         int i;
+       i_color *backp = NULL;
+       i_fcolor *fbackp = NULL;
       CODE:
         if (!SvROK(ST(3)) || SvTYPE(SvRV(ST(3))) != SVt_PVAV)
           croak("i_matrix_transform: parameter 4 must be an array ref\n");
@@ -1435,7 +1555,20 @@ i_matrix_transform(im, xsize, ysize, matrix)
         }
         for (; i < 9; ++i)
           matrix[i] = 0;
-        RETVAL = i_matrix_transform(im, xsize, ysize, matrix);        
+       /* extract the bg colors if any */
+       /* yes, this is kind of strange */
+       for (i = 4; i < items; ++i) {
+          sv1 = ST(i);
+          if (sv_derived_from(sv1, "Imager::Color")) {
+           IV tmp = SvIV((SV*)SvRV(sv1));
+           backp = INT2PTR(i_color *, tmp);
+         }
+         else if (sv_derived_from(sv1, "Imager::Color::Float")) {
+           IV tmp = SvIV((SV*)SvRV(sv1));
+           fbackp = INT2PTR(i_fcolor *, tmp);
+         }
+       }
+        RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp);
       OUTPUT:
         RETVAL
 
@@ -1482,7 +1615,6 @@ i_convert(im, src, coeff)
          int inchan;
          AV *avmain;
           SV **temp;
-         SV *svsub;
           AV *avsub;
          int len;
          int i, j;
@@ -1591,48 +1723,169 @@ i_t1_destroy(font_id)
 
 
 undef_int
-i_t1_cp(im,xb,yb,channel,fontnum,points,str,len,align)
+i_t1_cp(im,xb,yb,channel,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
     Imager::ImgRaw     im
               int     xb
               int     yb
               int     channel
               int     fontnum
              float     points
-             char*    str
-              int     len
+               SV*    str_sv
               int     align
+               int     utf8
+              char*    flags
+             PREINIT:
+               char *str;
+               STRLEN len;
+             CODE:
+#ifdef SvUTF8
+               if (SvUTF8(str_sv))
+                 utf8 = 1;
+#endif
+               str = SvPV(str_sv, len);
+               RETVAL = i_t1_cp(im, xb,yb,channel,fontnum,points,str,len,align,
+                                  utf8,flags);
+           OUTPUT:
+             RETVAL
+
 
 void
-i_t1_bbox(fontnum,point,str,len)
+i_t1_bbox(fontnum,point,str_sv,len_ignored,utf8=0,flags="")
                int     fontnum
             float     point
-             char*    str
-              int     len
+               SV*    str_sv
+               int     utf8
+              char*    flags
             PREINIT:
-              int     cords[6];
+               char *str;
+               STRLEN len;
+              int     cords[BOUNDING_BOX_COUNT];
+               int i;
+               int rc;
             PPCODE:
-              i_t1_bbox(fontnum,point,str,len,cords);
-               EXTEND(SP, 4);
-               PUSHs(sv_2mortal(newSViv(cords[0])));
-               PUSHs(sv_2mortal(newSViv(cords[1])));
-               PUSHs(sv_2mortal(newSViv(cords[2])));
-               PUSHs(sv_2mortal(newSViv(cords[3])));
-               PUSHs(sv_2mortal(newSViv(cords[4])));
-               PUSHs(sv_2mortal(newSViv(cords[5])));
+#ifdef SvUTF8
+               if (SvUTF8(str_sv))
+                 utf8 = 1;
+#endif
+               str = SvPV(str_sv, len);
+               rc = i_t1_bbox(fontnum,point,str,len,cords,utf8,flags);
+               if (rc > 0) {
+                 EXTEND(SP, rc);
+                 for (i = 0; i < rc; ++i)
+                   PUSHs(sv_2mortal(newSViv(cords[i])));
+               }
 
 
 
 undef_int
-i_t1_text(im,xb,yb,cl,fontnum,points,str,len,align)
+i_t1_text(im,xb,yb,cl,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
     Imager::ImgRaw     im
               int     xb
               int     yb
      Imager::Color    cl
               int     fontnum
              float     points
-             char*    str
-              int     len
+               SV*    str_sv
               int     align
+               int     utf8
+              char*    flags
+             PREINIT:
+               char *str;
+               STRLEN len;
+             CODE:
+#ifdef SvUTF8
+               if (SvUTF8(str_sv))
+                 utf8 = 1;
+#endif
+               str = SvPV(str_sv, len);
+               RETVAL = i_t1_text(im, xb,yb,cl,fontnum,points,str,len,align,
+                                  utf8,flags);
+           OUTPUT:
+             RETVAL
+
+void
+i_t1_has_chars(handle, text_sv, utf8 = 0)
+        int handle
+        SV  *text_sv
+        int utf8
+      PREINIT:
+        char const *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_t1_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_t1_face_name(handle)
+        int handle
+      PREINIT:
+        char name[255];
+        int len;
+      PPCODE:
+        len = i_t1_face_name(handle, name, sizeof(name));
+        if (len) {
+          EXTEND(SP, 1);
+          PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
+        }
+
+void
+i_t1_glyph_name(handle, text_sv, utf8 = 0)
+        int handle
+        SV *text_sv
+        int utf8
+      PREINIT:
+        char const *text;
+        STRLEN work_len;
+        int len;
+        int outsize;
+        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 (outsize = i_t1_glyph_name(handle, ch, name, sizeof(name))) {
+            PUSHs(sv_2mortal(newSVpv(name, 0)));
+          }
+          else {
+            PUSHs(&PL_sv_undef);
+          } 
+        }
 
 #endif 
 
@@ -1657,55 +1910,173 @@ MODULE = Imager         PACKAGE = Imager
 
 
 undef_int
-i_tt_text(handle,im,xb,yb,cl,points,str,len,smooth)
+i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8)
   Imager::Font::TT     handle
     Imager::ImgRaw     im
               int     xb
               int     yb
      Imager::Color     cl
              float     points
-             char*    str
-              int     len
+             SV *     str_sv
+              int     len_ignored
               int     smooth
+               int     utf8
+             PREINIT:
+               char *str;
+               STRLEN len;
+             CODE:
+#ifdef SvUTF8
+               if (SvUTF8(str_sv))
+                 utf8 = 1;
+#endif
+               str = SvPV(str_sv, len);
+               RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, 
+                                  len, smooth, utf8);
+             OUTPUT:
+               RETVAL                
 
 
 undef_int
-i_tt_cp(handle,im,xb,yb,channel,points,str,len,smooth)
+i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8)
   Imager::Font::TT     handle
     Imager::ImgRaw     im
               int     xb
               int     yb
               int     channel
              float     points
-             char*    str
-              int     len
+             SV *     str_sv
+              int     len_ignored
               int     smooth
+               int     utf8
+             PREINIT:
+               char *str;
+               STRLEN len;
+             CODE:
+#ifdef SvUTF8
+               if (SvUTF8(str_sv))
+                 utf8 = 1;
+#endif
+               str = SvPV(str_sv, len);
+               RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len,
+                                smooth, utf8);
+             OUTPUT:
+                RETVAL
 
 
-
-undef_int
-i_tt_bbox(handle,point,str,len)
+void
+i_tt_bbox(handle,point,str_sv,len_ignored, utf8)
   Imager::Font::TT     handle
             float     point
-             char*    str
-              int     len
+              SV*    str_sv
+              int     len_ignored
+               int     utf8
             PREINIT:
-              int     cords[6],rc;
+              int     cords[BOUNDING_BOX_COUNT],rc;
+               char *  str;
+               STRLEN len;
+               int i;
             PPCODE:
-              if ((rc=i_tt_bbox(handle,point,str,len,cords))) {
-                 EXTEND(SP, 4);
-                 PUSHs(sv_2mortal(newSViv(cords[0])));
-                 PUSHs(sv_2mortal(newSViv(cords[1])));
-                 PUSHs(sv_2mortal(newSViv(cords[2])));
-                 PUSHs(sv_2mortal(newSViv(cords[3])));
-                 PUSHs(sv_2mortal(newSViv(cords[4])));
-                 PUSHs(sv_2mortal(newSViv(cords[5])));
+#ifdef SvUTF8
+               if (SvUTF8(ST(2)))
+                 utf8 = 1;
+#endif
+               str = SvPV(str_sv, len);
+              if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) {
+                 EXTEND(SP, rc);
+                 for (i = 0; i < rc; ++i) {
+                   PUSHs(sv_2mortal(newSViv(cords[i])));
+                 }
                }
 
+void
+i_tt_has_chars(handle, text_sv, utf8)
+        Imager::Font::TT handle
+        SV  *text_sv
+        int utf8
+      PREINIT:
+        char const *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_tt_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);
 
-#endif 
+void
+i_tt_dump_names(handle)
+        Imager::Font::TT handle
 
+void
+i_tt_face_name(handle)
+        Imager::Font::TT handle
+      PREINIT:
+        char name[255];
+        int len;
+      PPCODE:
+        len = i_tt_face_name(handle, name, sizeof(name));
+        if (len) {
+          EXTEND(SP, 1);
+          PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
+        }
 
+void
+i_tt_glyph_name(handle, text_sv, utf8 = 0)
+        Imager::Font::TT handle
+        SV *text_sv
+        int utf8
+      PREINIT:
+        char const *text;
+        STRLEN work_len;
+        int len;
+        int outsize;
+        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 (outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) {
+            PUSHs(sv_2mortal(newSVpv(name, 0)));
+          }
+          else {
+            PUSHs(&PL_sv_undef);
+          } 
+        }
+
+#endif 
 
 
 #ifdef HAVE_LIBJPEG
@@ -1745,6 +2116,11 @@ i_readjpeg_wiol(ig)
 #endif
 
 
+char *
+i_test_format_probe(ig, length)
+        Imager::IO     ig
+              int     length
+
 
 
 #ifdef HAVE_LIBTIFF
@@ -1921,7 +2297,7 @@ i_writegif(im,fd,colors,pixdev,fixed)
               sv1=(*(av_fetch(av,i,0)));
                if (sv_derived_from(sv1, "Imager::Color")) {
                  Itmp = SvIV((SV*)SvRV(sv1));
-                 tmp = (i_color*) Itmp;
+                 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;
             }
@@ -2197,7 +2573,7 @@ i_readgif_scalar(...)
           PROTOTYPE: $
             PREINIT:
                char*    data;
-       unsigned int     length;
+             STRLEN     length;
                int*    colour_table;
                int     colours, q, w;
              i_img*    rimg;
@@ -2245,8 +2621,6 @@ void
 i_readgif_callback(...)
           PROTOTYPE: &
             PREINIT:
-               char*    data;
-               int     length;
                int*    colour_table;
                int     colours, q, w;
              i_img*    rimg;
@@ -2317,7 +2691,7 @@ i_readgif_multi_scalar(data)
         i_img **imgs;
         int count;
         char *data;
-        unsigned int length;
+        STRLEN length;
         int i;
       PPCODE:
         data = (char *)SvPV(ST(0), length);
@@ -2420,8 +2794,6 @@ i_writetga_wiol(im,ig, wierdpack, compress, idstring)
                int     compress
               char*    idstring
             PREINIT:
-                SV* sv1;
-                int rc;
                 int idlen;
               CODE:
                 idlen  = SvCUR(ST(4));
@@ -2444,8 +2816,6 @@ i_writergb_wiol(im,ig, wierdpack, compress, idstring)
                int     compress
               char*    idstring
             PREINIT:
-                SV* sv1;
-                int rc;
                 int idlen;
               CODE:
                 idlen  = SvCUR(ST(4));
@@ -2533,11 +2903,17 @@ i_transform(im,opx,opy,parm)
              else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL);
 
 Imager::ImgRaw
-i_transform2(width,height,ops,n_regs,c_regs,in_imgs)
+i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
+       SV *sv_width
+       SV *sv_height
+       SV *sv_ops
+       AV *av_n_regs
+       AV *av_c_regs
+       AV *av_in_imgs
+       int channels
             PREINIT:
              int width;
              int height;
-            double* parm;
             struct rm_op *ops;
             STRLEN ops_len;
             int ops_count;
@@ -2547,42 +2923,27 @@ i_transform2(width,height,ops,n_regs,c_regs,in_imgs)
             int c_regs_count;
              int in_imgs_count;
              i_img **in_imgs;
-            AV* av;
-            SV* sv1;
+             SV *sv1;
              IV tmp;
             int i;
              CODE:
-            if (!SvROK(ST(3))) croak("Imager: Parameter 4 must be a reference to an array\n");
-            if (!SvROK(ST(4))) croak("Imager: Parameter 5 must be a reference to an array\n");
-            if (!SvROK(ST(5))) croak("Imager: Parameter 6 must be a reference to an array of images\n");
-            if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 4 must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(4))) != SVt_PVAV) croak("Imager: Parameter 5 must be a reference to an array\n");
-
-       /*if (SvTYPE(SvRV(ST(5))) != SVt_PVAV) croak("Imager: Parameter 6 must be a reference to an array\n");*/
-
-             if (SvTYPE(SvRV(ST(5))) == SVt_PVAV) {
-              av = (AV*)SvRV(ST(5));
-               in_imgs_count = av_len(av)+1;
-              for (i = 0; i < in_imgs_count; ++i) {
-                sv1 = *av_fetch(av, i, 0);
-                if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
-                  croak("Parameter 5 must contain only images");
-                }
+
+             in_imgs_count = av_len(av_in_imgs)+1;
+            for (i = 0; i < in_imgs_count; ++i) {
+              sv1 = *av_fetch(av_in_imgs, i, 0);
+              if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
+                croak("sv_in_img must contain only images");
               }
             }
-            else {
-              in_imgs_count = 0;
-             }
              if (in_imgs_count > 0) {
-               av = (AV*)SvRV(ST(5));
                in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
                for (i = 0; i < in_imgs_count; ++i) {              
-                sv1 = *av_fetch(av,i,0);
+                sv1 = *av_fetch(av_in_imgs,i,0);
                 if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
                   croak("Parameter 5 must contain only images");
                 }
                  tmp = SvIV((SV*)SvRV(sv1));
-                in_imgs[i] = (i_img*)tmp;
+                in_imgs[i] = INT2PTR(i_img*, tmp);
               }
             }
              else {
@@ -2590,38 +2951,37 @@ i_transform2(width,height,ops,n_regs,c_regs,in_imgs)
               in_imgs = NULL;
              }
              /* default the output size from the first input if possible */
-             if (SvOK(ST(0)))
-              width = SvIV(ST(0));
+             if (SvOK(sv_width))
+              width = SvIV(sv_width);
              else if (in_imgs_count)
               width = in_imgs[0]->xsize;
              else
               croak("No output image width supplied");
 
-             if (SvOK(ST(1)))
-              height = SvIV(ST(1));
+             if (SvOK(sv_height))
+              height = SvIV(sv_height);
              else if (in_imgs_count)
               height = in_imgs[0]->ysize;
              else
               croak("No output image height supplied");
 
-            ops = (struct rm_op *)SvPV(ST(2), ops_len);
+            ops = (struct rm_op *)SvPV(sv_ops, ops_len);
              if (ops_len % sizeof(struct rm_op))
                 croak("Imager: Parameter 3 must be a bitmap of regops\n");
             ops_count = ops_len / sizeof(struct rm_op);
-            av = (AV*)SvRV(ST(3));
-            n_regs_count = av_len(av)+1;
+
+            n_regs_count = av_len(av_n_regs)+1;
              n_regs = mymalloc(n_regs_count * sizeof(double));
             for (i = 0; i < n_regs_count; ++i) {
-              sv1 = *av_fetch(av,i,0);
+              sv1 = *av_fetch(av_n_regs,i,0);
               if (SvOK(sv1))
                 n_regs[i] = SvNV(sv1);
             }
-             av = (AV*)SvRV(ST(4));
-             c_regs_count = av_len(av)+1;
+             c_regs_count = av_len(av_c_regs)+1;
              c_regs = mymalloc(c_regs_count * sizeof(i_color));
              /* I don't bother initializing the colou?r registers */
 
-            RETVAL=i_transform2(width, height, 3, ops, ops_count, 
+            RETVAL=i_transform2(width, height, channels, ops, ops_count, 
                                 n_regs, n_regs_count, 
                                 c_regs, c_regs_count, in_imgs, in_imgs_count);
             if (in_imgs)
@@ -2769,12 +3129,11 @@ i_gradgen(im, ...)
         myfree(yo);
         myfree(ival);
 
-
-void
-i_diff_image(im, im2, mindiff=0)
+Imager::ImgRaw
+i_diff_image(im, im2, mindist=0)
     Imager::ImgRaw     im
     Imager::ImgRaw     im2
-               int     mindiff
+               int     mindist
 
 void
 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
@@ -2835,7 +3194,6 @@ i_errors()
         i_errmsg *errors;
        int i;
        AV *av;
-       SV *ref;
        SV *sv;
       PPCODE:
        errors = i_errors();
@@ -2930,11 +3288,11 @@ DSO_open(filename)
                if (rc!=NULL) {
                  if (evstr!=NULL) {
                    EXTEND(SP,2); 
-                   PUSHs(sv_2mortal(newSViv((IV)rc)));
+                   PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
                    PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
                  } else {
                    EXTEND(SP,1);
-                   PUSHs(sv_2mortal(newSViv((IV)rc)));
+                   PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
                  }
                }
 
@@ -2974,7 +3332,6 @@ DSO_call(handle,func_index,hv)
 
 
 
-# this is mostly for testing...
 SV *
 i_get_pixel(im, x, y)
        Imager::ImgRaw im
@@ -2985,13 +3342,15 @@ i_get_pixel(im, x, y)
       CODE:
        color = (i_color *)mymalloc(sizeof(i_color));
        if (i_gpix(im, x, y, color) == 0) {
-          ST(0) = sv_newmortal();
-          sv_setref_pv(ST(0), "Imager::Color", (void *)color);
+          RETVAL = NEWSV(0, 0);
+          sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
         }
         else {
           myfree(color);
-          ST(0) = &PL_sv_undef;
+          RETVAL = &PL_sv_undef;
         }
+      OUTPUT:
+        RETVAL
         
 
 int
@@ -3054,7 +3413,7 @@ i_gpal(im, l, r, y)
           }
           else {
             EXTEND(SP, 1);
-            PUSHs(sv_2mortal(newSVpv(work, count * sizeof(i_palidx))));
+            PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
           }
           myfree(work);
         }
@@ -3072,7 +3431,7 @@ i_ppal(im, l, y, ...)
         int     y
       PREINIT:
         i_palidx *work;
-        int count, i;
+        int i;
       CODE:
         if (items > 3) {
           work = mymalloc(sizeof(i_palidx) * (items-3));
@@ -3113,16 +3472,18 @@ i_addcolors(im, ...)
         index = i_addcolors(im, colors, items-1);
         myfree(colors);
         if (index == 0) {
-          ST(0) = sv_2mortal(newSVpv("0 but true", 0));
+          RETVAL = newSVpv("0 but true", 0);
         }
         else if (index == -1) {
-          ST(0) = &PL_sv_undef;
+          RETVAL = &PL_sv_undef;
         }
         else {
-          ST(0) = sv_2mortal(newSViv(index));
+          RETVAL = newSViv(index);
         }
+      OUTPUT:
+        RETVAL
 
-int 
+undef_int 
 i_setcolors(im, index, ...)
         Imager::ImgRaw  im
         int index
@@ -3146,6 +3507,8 @@ i_setcolors(im, index, ...)
         }
         RETVAL = i_setcolors(im, index, colors, items-2);
         myfree(colors);
+      OUTPUT:
+       RETVAL
 
 void
 i_getcolors(im, index, ...)
@@ -3176,33 +3539,13 @@ i_getcolors(im, index, ...)
         myfree(colors);
 
 
-SV *
+undef_neg_int
 i_colorcount(im)
         Imager::ImgRaw im
-      PREINIT:
-        int count;
-      CODE:
-        count = i_colorcount(im);
-        if (count >= 0) {
-          ST(0) = sv_2mortal(newSViv(count));
-        }
-        else {
-          ST(0) = &PL_sv_undef;
-        }
 
-SV *
+undef_neg_int
 i_maxcolors(im)
         Imager::ImgRaw im
-      PREINIT:
-        int count;
-      CODE:
-        count = i_maxcolors(im);
-        if (count >= 0) {
-          ST(0) = sv_2mortal(newSViv(count));
-        }
-        else {
-          ST(0) = &PL_sv_undef;
-        }
 
 SV *
 i_findcolor(im, color)
@@ -3212,11 +3555,13 @@ i_findcolor(im, color)
         i_palidx index;
       CODE:
         if (i_findcolor(im, color, &index)) {
-          ST(0) = sv_2mortal(newSViv(index));
+          RETVAL = newSViv(index);
         }
         else {
-          ST(0) = &PL_sv_undef;
+          RETVAL = &PL_sv_undef;
         }
+      OUTPUT:
+        RETVAL
 
 int
 i_img_bits(im)
@@ -3259,7 +3604,7 @@ i_gsamp(im, l, r, y, ...)
           }
           else {
             EXTEND(SP, 1);
-            PUSHs(sv_2mortal(newSVpv(data, count * sizeof(i_sample_t))));
+            PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
           }
          myfree(data);
         }
@@ -3301,7 +3646,7 @@ i_plin(im, l, y, ...)
         int     y
       PREINIT:
         i_color *work;
-        int count, i;
+        int i;
       CODE:
         if (items > 3) {
           work = mymalloc(sizeof(i_color) * (items-3));
@@ -3378,7 +3723,7 @@ i_plinf(im, l, y, ...)
         int     y
       PREINIT:
         i_fcolor *work;
-        int count, i;
+        int i;
       CODE:
         if (items > 3) {
           work = mymalloc(sizeof(i_fcolor) * (items-3));
@@ -3413,14 +3758,16 @@ i_gpixf(im, x, y)
       CODE:
        color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
        if (i_gpixf(im, x, y, color) == 0) {
-          ST(0) = sv_newmortal();
-          sv_setref_pv(ST(0), "Imager::Color::Float", (void *)color);
+          RETVAL = NEWSV(0,0);
+          sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
         }
         else {
           myfree(color);
-          ST(0) = &PL_sv_undef;
+          RETVAL = &PL_sv_undef;
         }
-        
+      OUTPUT:
+        RETVAL
+
 void
 i_glin(im, l, r, y)
         Imager::ImgRaw im
@@ -3438,6 +3785,7 @@ i_glin(im, l, r, y)
           for (i = 0; i < count; ++i) {
             SV *sv;
             i_color *col = mymalloc(sizeof(i_color));
+            *col = vals[i];
             sv = sv_newmortal();
             sv_setref_pv(sv, "Imager::Color", (void *)col);
             PUSHs(sv);
@@ -3533,12 +3881,14 @@ i_tags_find(im, name, start)
       CODE:
         if (i_tags_find(&im->tags, name, start, &entry)) {
           if (entry == 0)
-            ST(0) = sv_2mortal(newSVpv("0 but true", 0));
+            RETVAL = newSVpv("0 but true", 0);
           else
-            ST(0) = sv_2mortal(newSViv(entry));
+            RETVAL = newSViv(entry);
         } else {
-          ST(0) = &PL_sv_undef;
+          RETVAL = &PL_sv_undef;
         }
+      OUTPUT:
+        RETVAL
 
 SV *
 i_tags_findn(im, code, start)
@@ -3550,12 +3900,15 @@ i_tags_findn(im, code, start)
       CODE:
         if (i_tags_findn(&im->tags, code, start, &entry)) {
           if (entry == 0)
-            ST(0) = sv_2mortal(newSVpv("0 but true", 0));
+            RETVAL = newSVpv("0 but true", 0);
           else
-            ST(0) = sv_2mortal(newSViv(entry));
+            RETVAL = newSViv(entry);
         }
-        else
-          ST(0) = &PL_sv_undef;
+        else {
+          RETVAL = &PL_sv_undef;
+        }
+      OUTPUT:
+        RETVAL
 
 int
 i_tags_delete(im, entry)
@@ -3623,16 +3976,13 @@ i_wf_bbox(face, size, text)
        int size
        char *text
       PREINIT:
-       int cords[6];
+       int cords[BOUNDING_BOX_COUNT];
+        int rc, i;
       PPCODE:
-        if (i_wf_bbox(face, size, text, strlen(text), cords)) {
-          EXTEND(SP, 6);  
-          PUSHs(sv_2mortal(newSViv(cords[0])));
-          PUSHs(sv_2mortal(newSViv(cords[1])));
-          PUSHs(sv_2mortal(newSViv(cords[2])));
-          PUSHs(sv_2mortal(newSViv(cords[3])));
-          PUSHs(sv_2mortal(newSViv(cords[4])));
-          PUSHs(sv_2mortal(newSViv(cords[5])));
+        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
@@ -3739,23 +4089,28 @@ i_ft2_settransform(font, matrix)
         RETVAL
 
 void
-i_ft2_bbox(font, cheight, cwidth, text, utf8)
+i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
         Imager::Font::FT2 font
         double cheight
         double cwidth
-        char *text
+        SV *text_sv
        int utf8
       PREINIT:
-        int bbox[6];
+        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(ST(3)))
+        if (SvUTF8(text_sv))
           utf8 = 1;
 #endif
-        if (i_ft2_bbox(font, cheight, cwidth, text, strlen(text), bbox, utf8)) {
-          EXTEND(SP, 6);
-          for (i = 0; i < 6; ++i)
+        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])));
         }
 
@@ -3853,8 +4208,9 @@ ft2_transform_box(font, x0, x1, x2, x3)
           PUSHs(sv_2mortal(newSViv(box[3])));
 
 void
-i_ft2_has_chars(handle, text, utf8)
+i_ft2_has_chars(handle, text_sv, utf8)
         Imager::Font::FT2 handle
+        SV  *text_sv
         int utf8
       PREINIT:
         char *text;
@@ -3864,10 +4220,10 @@ i_ft2_has_chars(handle, text, utf8)
         int i;
       PPCODE:
 #ifdef SvUTF8
-        if (SvUTF8(ST(7)))
+        if (SvUTF8(text_sv))
           utf8 = 1;
 #endif
-        text = SvPV(ST(1), len);
+        text = SvPV(text_sv, len);
         work = mymalloc(len);
         count = i_ft2_has_chars(handle, text, len, utf8, work);
         if (GIMME_V == G_ARRAY) {
@@ -3882,6 +4238,123 @@ i_ft2_has_chars(handle, text, utf8)
         }
         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;
+        int outsize;
+        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 (outsize = 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_
@@ -3915,7 +4388,7 @@ i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
         STRLEN len;
       CODE:
         if (SvOK(ST(4))) {
-          cust_hatch = SvPV(ST(4), len);
+          cust_hatch = (unsigned char *)SvPV(ST(4), len);
         }
         else
           cust_hatch = NULL;
@@ -3936,7 +4409,7 @@ i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
         STRLEN len;
       CODE:
         if (SvOK(ST(4))) {
-          cust_hatch = SvPV(ST(4), len);
+          cust_hatch = (unsigned char *)SvPV(ST(4), len);
         }
         else
           cust_hatch = NULL;
@@ -3979,3 +4452,4 @@ i_new_fill_image(src, matrix, xoff, yoff, combine)
         RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
       OUTPUT:
         RETVAL
+