]> git.imager.perl.org - imager.git/blobdiff - Imager.xs
report library version numbers where we already have the XS for it
[imager.git] / Imager.xs
index da982a9b2c62b8fca4160e200fafac5b1c3f10e9..2de3747f29f0dce2566d75bf9173bd37f9279c6f 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -4,35 +4,26 @@ extern "C" {
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
+#define NEED_newRV_noinc
+#define NEED_sv_2pv_nolen
 #include "ppport.h"
 #ifdef __cplusplus
-
+}
 #endif
 
 #define i_int_hlines_testing() 1
 
-#include "image.h"
+#include "imager.h"
 #include "feat.h"
 #include "dynaload.h"
 #include "regmach.h"
+#include "imextdef.h"
 
 #if i_int_hlines_testing()
-#include "imagei.h"
-#endif
-
-typedef io_glue* Imager__IO;
-typedef i_color* Imager__Color;
-typedef i_fcolor* Imager__Color__Float;
-typedef i_img*   Imager__ImgRaw;
-typedef int undef_neg_int;
-
-#ifdef HAVE_LIBTT
-typedef TT_Fonthandle* Imager__Font__TT;
+#include "imageri.h"
 #endif
 
-#ifdef HAVE_FT2
-typedef FT2_Fonthandle* Imager__Font__FT2;
-#endif
+#include "imperl.h"
 
 /* These functions are all shared - then comes platform dependant code */
 static int getstr(void *hv_t,char *key,char **store) {
@@ -117,7 +108,7 @@ void my_SvREFCNT_dec(void *p) {
 
 
 static void
-log_entry(char *string, int level) {
+i_log_entry(char *string, int level) {
   mm_log((level, string));
 }
 
@@ -281,7 +272,7 @@ 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, 
@@ -334,9 +325,14 @@ static ssize_t call_reader(struct cbdata *cbd, void *buf, size_t size,
 static ssize_t write_flush(struct cbdata *cbd) {
   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) {
@@ -386,12 +382,11 @@ 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) {
   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;
       }
@@ -401,8 +396,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;
   }
@@ -415,11 +411,13 @@ 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) {
   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;
@@ -439,7 +437,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, 
@@ -454,6 +452,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*/
@@ -463,16 +463,19 @@ 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) {
   struct cbdata *cbd = p;
 
   if (cbd->writing && cbd->used > 0) {
-    write_flush(cbd);
+    if (write_flush(cbd) < 0)
+      return -1;
     cbd->writing = 0;
   }
 
@@ -491,6 +494,8 @@ static void io_closer(void *p) {
     FREETMPS;
     LEAVE;
   }
+
+  return 0;
 }
 
 static void io_destroyer(void *p) {
@@ -530,6 +535,8 @@ 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[] =
@@ -712,14 +719,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;
@@ -727,9 +732,7 @@ 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);
   }
 }
 
@@ -809,6 +812,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
@@ -816,12 +842,6 @@ load_fount_segs(AV *asegs, int *count) {
 #define ICLF_new_internal(r, g, b, a) i_fcolor_new((r), (g), (b), (a))
 #define ICLF_DESTROY(cl) i_fcolor_destroy(cl)
 
-/* for the fill objects
-   Since a fill object may later have dependent images, (or fills!)
-   we need perl wrappers - oh well
-*/
-#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 */
@@ -894,6 +914,9 @@ i_int_hlines_dump(i_int_hlines *hlines) {
 #define i_exif_enabled() 0
 #endif
 
+/* trying to use more C style names, map them here */
+#define i_io_DESTROY(ig) io_glue_destroy(ig)
+
 MODULE = Imager                PACKAGE = Imager::Color PREFIX = ICL_
 
 Imager::Color
@@ -1116,18 +1139,103 @@ i_get_image_file_limits()
           PUSHs(sv_2mortal(newSViv(bytes)));
         }
 
-MODULE = Imager                PACKAGE = Imager::IO    PREFIX = io_glue_
+MODULE = Imager                PACKAGE = Imager::IO    PREFIX = i_io_
+
+int
+i_io_write(ig, data_sv)
+       Imager::IO ig
+       SV *data_sv
+      PREINIT:
+        void *data;
+       STRLEN size;
+      CODE:
+#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        
+       data = SvPV(data_sv, size);
+        RETVAL = i_io_write(ig, data, size);
+      OUTPUT:
+       RETVAL
 
 void
-io_glue_DESTROY(ig)
-        Imager::IO     ig
+i_io_read(ig, buffer_sv, size)
+       Imager::IO ig
+       SV *buffer_sv
+       int size
+      PREINIT:
+        void *buffer;
+       int result;
+      PPCODE:
+        if (size <= 0)
+         croak("size negative in call to i_io_read()");
+        /* prevent an undefined value warning if they supplied an 
+          undef buffer.
+           Orginally conditional on !SvOK(), but this will prevent the
+          downgrade from croaking */
+       sv_setpvn(buffer_sv, "", 0);
+#ifdef SvUTF8
+       if (SvUTF8(buffer_sv))
+          sv_utf8_downgrade(buffer_sv, FALSE);
+#endif
+       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);
+         EXTEND(SP, 1);
+         PUSHs(sv_2mortal(newSViv(result)));
+       }
+       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);
+         EXTEND(SP, 1);
+         PUSHs(sv_2mortal(buffer_sv));
+       }
+       else {
+          /* discard it */
+         SvREFCNT_dec(buffer_sv);
+        }
 
-MODULE = Imager                PACKAGE = Imager
+int
+i_io_seek(ig, position, whence)
+       Imager::IO ig
+       long position
+       int whence
 
-PROTOTYPES: ENABLE
+int
+i_io_close(ig)
+       Imager::IO ig
+
+void
+i_io_DESTROY(ig)
+        Imager::IO     ig
 
+MODULE = Imager                PACKAGE = Imager
 
+PROTOTYPES: ENABLE
 
 void
 i_list_formats()
@@ -1175,12 +1283,16 @@ i_sametype_chans(im, x, y, channels)
                int channels
 
 void
-m_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
-log_entry(string,level)
+i_log_entry(string,level)
              char*    string
               int     level
 
@@ -1231,6 +1343,25 @@ i_img_getdata(im)
                     sv_2mortal(newSVpv((char *)im->idata, im->bytes)) 
                     : &PL_sv_undef);
 
+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)
@@ -1448,6 +1579,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)
@@ -1473,9 +1620,8 @@ i_copyto_trans(im,src,x1,y1,x2,y2,tx,ty,trans)
               int     ty
      Imager::Color     trans
 
-void
-i_copy(im,src)
-    Imager::ImgRaw     im
+Imager::ImgRaw
+i_copy(src)
     Imager::ImgRaw     src
 
 
@@ -1490,6 +1636,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)
@@ -1571,10 +1745,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)
@@ -1604,23 +1778,19 @@ i_conv(im,pcoef)
             i_conv(im,coeff,len);
             myfree(coeff);
 
-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;
@@ -1647,7 +1817,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
@@ -1855,7 +2025,6 @@ i_t1_glyph_name(handle, text_sv, utf8 = 0)
         char const *text;
         STRLEN work_len;
         int len;
-        int outsize;
         char name[255];
       PPCODE:
 #ifdef SvUTF8
@@ -1878,7 +2047,7 @@ i_t1_glyph_name(handle, text_sv, utf8 = 0)
             --len;
           }
           EXTEND(SP, 1);
-          if (outsize = i_t1_glyph_name(handle, ch, name, sizeof(name))) {
+          if (i_t1_glyph_name(handle, ch, name, sizeof(name))) {
             PUSHs(sv_2mortal(newSVpv(name, 0)));
           }
           else {
@@ -1917,7 +2086,6 @@ i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1)
      Imager::Color     cl
              float     points
              SV *     str_sv
-              int     len_ignored
               int     smooth
                int     utf8
                int     align
@@ -1945,7 +2113,6 @@ i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1)
               int     channel
              float     points
              SV *     str_sv
-              int     len_ignored
               int     smooth
                int     utf8
                int     align
@@ -1969,7 +2136,6 @@ i_tt_bbox(handle,point,str_sv,len_ignored, utf8)
   Imager::Font::TT     handle
             float     point
               SV*    str_sv
-              int     len_ignored
                int     utf8
             PREINIT:
               int     cords[BOUNDING_BOX_COUNT],rc;
@@ -2069,7 +2235,7 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0)
             --len;
           }
           EXTEND(SP, 1);
-          if (outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) {
+          if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
             PUSHs(sv_2mortal(newSVpv(name, 0)));
           }
           else {
@@ -2119,7 +2285,7 @@ i_exif_enabled()
 #endif
 
 
-char *
+const char *
 i_test_format_probe(ig, length)
         Imager::IO     ig
               int     length
@@ -2129,9 +2295,9 @@ i_test_format_probe(ig, length)
 #ifdef HAVE_LIBTIFF
 
 Imager::ImgRaw
-i_readtiff_wiol(ig, length, page=0)
+i_readtiff_wiol(ig, allow_incomplete, page=0)
         Imager::IO     ig
-              int     length
+              int     allow_incomplete
                int     page
 
 void
@@ -2249,6 +2415,12 @@ i_writetiff_multi_wiol_faxable(ig, fine, ...)
       OUTPUT:
         RETVAL
 
+const char *
+i_tiff_libversion()
+
+bool
+i_tiff_has_compression(name)
+       const char *name
 
 #endif /* HAVE_LIBTIFF */
 
@@ -2339,6 +2511,8 @@ i_writegif_gen(fd, ...)
        hv = (HV *)SvRV(ST(1));
        memset(&quant, 0, sizeof(quant));
        quant.mc_size = 256;
+       quant.transp = tr_threshold;
+       quant.tr_threshold = 127;
        handle_quant_opts(&quant, hv);
        img_count = items - 2;
        RETVAL = 1;
@@ -2394,6 +2568,8 @@ i_writegif_callback(cb, maxbuffer,...)
        hv = (HV *)SvRV(ST(2));
        memset(&quant, 0, sizeof(quant));
        quant.mc_size = 256;
+       quant.transp = tr_threshold;
+       quant.tr_threshold = 127;
        handle_quant_opts(&quant, hv);
        img_count = items - 3;
        RETVAL = 1;
@@ -2444,6 +2620,8 @@ i_writegif_wiol(ig, opts,...)
        hv = (HV *)SvRV(ST(1));
        memset(&quant, 0, sizeof(quant));
        quant.mc_size = 256;
+       quant.transp = tr_threshold;
+       quant.tr_threshold = 127;
        handle_quant_opts(&quant, hv);
        img_count = items - 2;
        RETVAL = 1;
@@ -2760,9 +2938,9 @@ i_readgif_multi_wiol(ig)
 
 
 Imager::ImgRaw
-i_readpnm_wiol(ig, length)
+i_readpnm_wiol(ig, allow_incomplete)
         Imager::IO     ig
-              int     length
+              int     allow_incomplete
 
 
 undef_int
@@ -2791,8 +2969,9 @@ i_writebmp_wiol(im,ig)
         Imager::IO     ig
 
 Imager::ImgRaw
-i_readbmp_wiol(ig)
+i_readbmp_wiol(ig, allow_incomplete=0)
         Imager::IO     ig
+        int            allow_incomplete
 
 
 undef_int
@@ -2817,27 +2996,6 @@ i_readtga_wiol(ig, length)
                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
@@ -2852,6 +3010,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
@@ -2861,6 +3025,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)
@@ -3142,9 +3323,9 @@ Imager::ImgRaw
 i_diff_image(im, im2, mindist=0)
     Imager::ImgRaw     im
     Imager::ImgRaw     im2
-               int     mindist
+            double     mindist
 
-void
+undef_int
 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
     Imager::ImgRaw     im
             double     xa
@@ -3166,9 +3347,11 @@ i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_para
         
        asegs = (AV *)SvRV(ST(10));
         segs = load_fount_segs(asegs, &count);
-        i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, 
-                   ssample_param, count, segs);
+        RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, 
+                            super_sample, ssample_param, count, segs);
         myfree(segs);
+      OUTPUT:
+        RETVAL
 
 Imager::FillHandle
 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
@@ -3222,6 +3405,14 @@ i_errors()
        }
 
 void
+i_clear_error()
+
+void
+i_push_error(code, msg)
+       int code
+       const char *msg
+
+undef_int
 i_nearest_color(im, ...)
     Imager::ImgRaw     im
       PREINIT:
@@ -3266,26 +3457,13 @@ i_nearest_color(im, ...)
          }
          ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
        }
-        i_nearest_color(im, num, xo, yo, ival, dmeasure);
-
-
-
+        RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
+      OUTPUT:
+        RETVAL
 
 void
 malloc_state()
 
-void
-hashinfo(hv)
-            PREINIT:
-              HV* hv;
-              int stuff;
-            PPCODE:
-              if (!SvROK(ST(0))) croak("Imager: Parameter 0 must be a reference to a hash\n");        
-              hv=(HV*)SvRV(ST(0));
-              if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 0 must be a reference to a hash\n");
-              if (getint(hv,"stuff",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
-              if (getint(hv,"stuff2",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n");
-              
 void
 DSO_open(filename)
              char*       filename
@@ -3316,17 +3494,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
@@ -3339,8 +3518,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
@@ -3447,6 +3624,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);
         }
@@ -3456,6 +3634,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
@@ -3624,6 +3824,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)
@@ -3720,6 +4022,7 @@ i_gsampf(im, l, r, y, ...)
             chans[i] = SvIV(ST(i+4));
           data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count);
           count = i_gsampf(im, l, r, y, data, chans, chan_count);
+          myfree(chans);
           if (GIMME_V == G_ARRAY) {
             EXTEND(SP, count);
             for (i = 0; i < count; ++i)
@@ -3729,6 +4032,7 @@ i_gsampf(im, l, r, y, ...)
             EXTEND(SP, 1);
             PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
           }
+          myfree(data);
         }
         else {
           if (GIMME_V != G_ARRAY) {
@@ -3814,6 +4118,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);
@@ -3842,9 +4147,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);
@@ -3870,6 +4180,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
@@ -4039,51 +4353,77 @@ i_tags_count(im)
 #ifdef HAVE_WIN32
 
 void
-i_wf_bbox(face, size, text)
+i_wf_bbox(face, size, text_sv, utf8=0)
        char *face
        int size
-       char *text
+       SV *text_sv
+       int utf8
       PREINIT:
        int cords[BOUNDING_BOX_COUNT];
         int rc, i;
+       char const *text;
+         STRLEN text_len;
       PPCODE:
-        if (rc = i_wf_bbox(face, size, text, strlen(text), cords)) {
+        text = SvPV(text_sv, text_len);
+#ifdef SvUTF8
+        if (SvUTF8(text_sv))
+          utf8 = 1;
+#endif
+        if (rc = i_wf_bbox(face, size, text, text_len, cords, utf8)) {
           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)
+i_wf_text(face, im, tx, ty, cl, size, text_sv, align, aa, utf8 = 0)
        char *face
        Imager::ImgRaw im
        int tx
        int ty
        Imager::Color cl
        int size
-       char *text
+       SV *text_sv
        int align
        int aa
+       int utf8
+      PREINIT:
+       char const *text;
+       STRLEN text_len;
       CODE:
-       RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text), 
-                          align, aa);
+        text = SvPV(text_sv, text_len);
+#ifdef SvUTF8
+        if (SvUTF8(text_sv))
+          utf8 = 1;
+#endif
+       RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, text_len, 
+                          align, aa, utf8);
       OUTPUT:
        RETVAL
 
 undef_int
-i_wf_cp(face, im, tx, ty, channel, size, text, align, aa)
+i_wf_cp(face, im, tx, ty, channel, size, text_sv, align, aa, utf8 = 0)
        char *face
        Imager::ImgRaw im
        int tx
        int ty
        int channel
        int size
-       char *text
+       SV *text_sv
        int align
        int aa
+       int utf8
+      PREINIT:
+       char const *text;
+       STRLEN text_len;
       CODE:
-       RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text), 
-                        align, aa);
+        text = SvPV(text_sv, text_len);
+#ifdef SvUTF8
+        if (SvUTF8(text_sv))
+          utf8 = 1;
+#endif
+       RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, text_len, 
+                        align, aa, utf8);
       OUTPUT:
        RETVAL
 
@@ -4091,6 +4431,10 @@ undef_int
 i_wf_addfont(font)
         char *font
 
+undef_int
+i_wf_delfont(font)
+        char *font
+
 #endif
 
 #ifdef HAVE_FT2
@@ -4237,7 +4581,7 @@ i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8
         RETVAL
 
 undef_int
-i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8)
+i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text_sv, align, aa, vlayout, utf8)
         Imager::Font::FT2 font
         Imager::ImgRaw im
         int tx
@@ -4245,18 +4589,22 @@ i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, u
         int channel
         double cheight
         double cwidth
-        char *text
+        SV *text_sv
         int align
         int aa
         int vlayout
         int utf8
+      PREINIT:
+       char const *text;
+       STRLEN len;
       CODE:
 #ifdef SvUTF8
         if (SvUTF8(ST(7)))
           utf8 = 1;
 #endif
+       text = SvPV(text_sv, len);
         RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
-                          strlen(text), align, aa, vlayout, 1);
+                          len, align, aa, vlayout, 1);
       OUTPUT:
         RETVAL
 
@@ -4335,7 +4683,6 @@ i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
         char const *text;
         STRLEN work_len;
         int len;
-        int outsize;
         char name[255];
       PPCODE:
 #ifdef SvUTF8
@@ -4358,7 +4705,7 @@ i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
             --len;
           }
           EXTEND(SP, 1);
-          if (outsize = i_ft2_glyph_name(handle, ch, name, sizeof(name), 
+          if (i_ft2_glyph_name(handle, ch, name, sizeof(name), 
                                          reliable_only)) {
             PUSHs(sv_2mortal(newSVpv(name, 0)));
           }
@@ -4560,3 +4907,6 @@ i_int_hlines_dump(hlines)
        Imager::Internal::Hlines hlines
 
 #endif
+
+BOOT:
+        PERL_SET_GLOBAL_CALLBACKS;