]> git.imager.perl.org - imager.git/blobdiff - Imager.xs
- use scanline oriented operations to flip images instead of pixel
[imager.git] / Imager.xs
index 531dd626035369fd3618ab6d49e57747934e5cb5..f6733ed68dbbd8541def9bf5d7dfca64de901ec8 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -4,6 +4,8 @@ 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
 }
@@ -17,8 +19,6 @@ extern "C" {
 #include "regmach.h"
 #include "imextdef.h"
 
-typedef io_glue* Imager__IO;
-
 #if i_int_hlines_testing()
 #include "imageri.h"
 #endif
@@ -272,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, 
@@ -325,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) {
@@ -377,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;
       }
@@ -392,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;
   }
@@ -406,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;
@@ -430,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, 
@@ -445,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*/
@@ -454,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;
   }
 
@@ -482,6 +494,8 @@ static void io_closer(void *p) {
     FREETMPS;
     LEAVE;
   }
+
+  return 0;
 }
 
 static void io_destroyer(void *p) {
@@ -521,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[] =
@@ -703,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;
@@ -718,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);
   }
 }
 
@@ -800,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
@@ -879,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
@@ -1101,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()
@@ -1160,9 +1283,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)
@@ -1216,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)
@@ -1433,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)
@@ -1474,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)
@@ -1555,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)
@@ -1566,45 +1756,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;
@@ -1631,7 +1816,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
@@ -1683,7 +1868,10 @@ 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)
@@ -2099,7 +2287,7 @@ i_exif_enabled()
 #endif
 
 
-char *
+const char *
 i_test_format_probe(ig, length)
         Imager::IO     ig
               int     length
@@ -2109,9 +2297,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
@@ -2229,6 +2417,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 */
 
@@ -2319,6 +2513,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;
@@ -2374,6 +2570,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;
@@ -2424,6 +2622,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;
@@ -2740,9 +2940,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
@@ -2771,8 +2971,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
@@ -2797,27 +2998,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
@@ -2832,6 +3012,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
@@ -2841,6 +3027,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)
@@ -3122,7 +3325,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)
@@ -3179,6 +3382,11 @@ i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_pa
       OUTPUT:
         RETVAL
 
+Imager::FillHandle
+i_new_fill_opacity(other_fill, alpha_mult)
+    Imager::FillHandle other_fill
+    double alpha_mult
+
 void
 i_errors()
       PREINIT:
@@ -3203,6 +3411,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
@@ -3285,17 +3501,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
@@ -3308,8 +3525,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
@@ -3416,6 +3631,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);
         }
@@ -3425,6 +3641,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
@@ -3593,6 +3831,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)
@@ -3785,6 +4125,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);
@@ -3813,9 +4154,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);
@@ -3841,6 +4187,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
@@ -4010,51 +4360,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
 
@@ -4062,6 +4438,10 @@ undef_int
 i_wf_addfont(font)
         char *font
 
+undef_int
+i_wf_delfont(font)
+        char *font
+
 #endif
 
 #ifdef HAVE_FT2
@@ -4208,7 +4588,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
@@ -4216,18 +4596,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