]> git.imager.perl.org - imager.git/blobdiff - Imager.xs
Changes updates
[imager.git] / Imager.xs
index a4ab76157b79db2eea901c875cccfafec1884973..c20b418f55f888f8a8356b924c1f016a5d7f8122 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -30,6 +30,8 @@ extern "C" {
 
 #include "imperl.h"
 
+#define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array))
+
 /*
 
 Context object management
@@ -50,22 +52,11 @@ typedef struct {
 
 START_MY_CXT
 
-im_context_t fallback_context;
-
 static void
 start_context(pTHX) {
   dMY_CXT;
   MY_CXT.ctx = im_context_new();
   sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
-
-  /* Ideally we'd free this reference, but the error message memory
-     was never released on exit, so the associated memory here is reasonable
-     to keep.
-     With logging enabled we always need at least one context, since
-     objects may be released fairly late and attempt to get the log file.
-  */
-  im_context_refinc(MY_CXT.ctx, "start_context");
-  fallback_context = MY_CXT.ctx;
 }
 
 static im_context_t
@@ -73,7 +64,7 @@ perl_get_context(void) {
   dTHX;
   dMY_CXT;
   
-  return MY_CXT.ctx ? MY_CXT.ctx : fallback_context;
+  return MY_CXT.ctx;
 }
 
 #else
@@ -83,7 +74,9 @@ static im_context_t perl_context;
 static void
 start_context(pTHX) {
   perl_context = im_context_new();
-  im_context_refinc(perl_context, "start_context");
+
+  /* just so it gets destroyed */
+  sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", perl_context);
 }
 
 static im_context_t
@@ -109,6 +102,11 @@ typedef struct {
   const i_fsample_t *samples;
 } i_fsample_list;
 
+typedef struct {
+  size_t count;
+  const i_polygon_t *polygons;
+} i_polygon_list;
+
 /*
 
 Allocate memory that will be discarded when mortals are discarded.
@@ -117,15 +115,18 @@ Allocate memory that will be discarded when mortals are discarded.
 
 static void *
 malloc_temp(pTHX_ size_t size) {
-  SV *sv = sv_2mortal(newSV(size));
+  void *result;
+  Newx(result, size, char);
+  SAVEFREEPV(result);
 
-  return SvPVX(sv);
+  return result;
 }
 
 static void *
 calloc_temp(pTHX_ size_t size) {
-  void *result = malloc_temp(aTHX_ size);
-  memset(result, 0, size);
+  void *result;
+  Newxz(result, size, char);
+  SAVEFREEPV(result);
 
   return result;
 }
@@ -140,14 +141,14 @@ calloc_temp(pTHX_ size_t size) {
 #define i_img_dimPtr(size) ((i_img_dim *)calloc_temp(aTHX_ sizeof(i_img_dim) * (size)))
 #define SvI_img_dim(sv, pname) (SvIV(sv))
 
-#define i_colorPtr(size) ((i_color *)calloc_temp(aTHX_ sizeof(i_color *) * (size)))
+#define i_colorPtr(size) ((i_color *)calloc_temp(aTHX_ sizeof(i_color) * (size)))
 
 #define SvI_color(sv, pname) S_sv_to_i_color(aTHX_ sv, pname)
 
 static i_color
 S_sv_to_i_color(pTHX_ SV *sv, const char *pname) {
   if (!sv_derived_from(sv, "Imager::Color")) {
-    croak("%s: not a color object");
+    croak("%s: not a color object", pname);
   }
   return *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
 }
@@ -234,9 +235,9 @@ static int getobj(void *hv_t,char *key,char *type,void **store) {
 
 UTIL_table_t i_UTIL_table={getstr,getint,getdouble,getvoid,getobj};
 
-void my_SvREFCNT_dec(void *p) {
-  dTHX;
-  SvREFCNT_dec((SV*)p);
+static void
+free_buffer(void *p) {
+  myfree(p);
 }
 
 
@@ -411,7 +412,6 @@ static int io_closer(void *p) {
   if (SvOK(cbd->closecb)) {
     dSP;
     I32 count;
-    SV *sv;
 
     ENTER;
     SAVETMPS;
@@ -422,8 +422,12 @@ static int io_closer(void *p) {
 
     SPAGAIN;
     
-    sv = POPs;
-    success = SvTRUE(sv);
+    if (count) {
+      SV *sv = POPs;
+      success = SvTRUE(sv);
+    }
+    else
+      success = 0;
 
     PUTBACK;
     FREETMPS;
@@ -444,14 +448,26 @@ static void io_destroyer(void *p) {
   myfree(cbd);
 }
 
-static i_io_glue_t *
-do_io_new_buffer(pTHX_ SV *data_sv) {
-  const char *data;
-  STRLEN length;
+static bool
+im_SvREFSCALAR(SV *sv) {
+  svtype type = SvTYPE(sv);
+
+  switch (type) {
+  case SVt_PV:
+  case SVt_PVIV:
+  case SVt_PVNV:
+  case SVt_PVMG:
+  case SVt_IV:
+  case SVt_NV:
+  case SVt_PVLV:
+#if PERL_VERSION > 10
+  case SVt_REGEXP:
+#endif
+    return 1;
 
-  data = SvPVbyte(data_sv, length);
-  SvREFCNT_inc(data_sv);
-  return io_new_buffer(data, length, my_SvREFCNT_dec, data_sv);
+  default:
+    return 0;
+  }
 }
 
 static const char *
@@ -475,6 +491,35 @@ describe_sv(SV *sv) {
   }
 }
 
+static i_io_glue_t *
+do_io_new_buffer(pTHX_ SV *data_sv) {
+  const char *data;
+  char *data_copy;
+  STRLEN length;
+  SV *sv;
+
+  SvGETMAGIC(data_sv);
+  if (SvROK(data_sv)) {
+    if (im_SvREFSCALAR(SvRV(data_sv))) {
+      sv = SvRV(data_sv);
+    }
+    else {
+      i_push_errorf(0, "data is not a scalar or a reference to scalar");
+      return NULL;
+    }
+  }
+  else {
+    sv = data_sv;
+  }
+
+  /* previously this would keep the SV around, but this is unsafe in
+     many ways, so always copy the bytes */
+  data = SvPVbyte(sv, length);
+  data_copy = mymalloc(length);
+  memcpy(data_copy, data, length);
+  return io_new_buffer(data_copy, length, free_buffer, data_copy);
+}
+
 static i_io_glue_t *
 do_io_new_cb(pTHX_ SV *writecb, SV *readcb, SV *seekcb, SV *closecb) {
   struct cbdata *cbd;
@@ -492,18 +537,29 @@ do_io_new_cb(pTHX_ SV *writecb, SV *readcb, SV *seekcb, SV *closecb) {
 }
 
 struct value_name {
-  char *name;
+  const char *name;
   int value;
 };
-static int lookup_name(struct value_name *names, int count, char *name, int def_value)
+static int
+lookup_name(const struct value_name *names, int count, char *name, int def_value, int push_errors, const char *id, int *failed)
 {
   int i;
+
+  if (push_errors)
+    *failed = 0;
+
   for (i = 0; i < count; ++i)
     if (strEQ(names[i].name, name))
       return names[i].value;
 
+  if (push_errors) {
+    i_push_errorf(0, "unknown value '%s' for %s", name, id);
+    *failed = 1;
+  }
+
   return def_value;
 }
+
 static struct value_name transp_names[] =
 {
   { "none", tr_none },
@@ -557,14 +613,14 @@ static struct value_name orddith_names[] =
 };
 
 /* look through the hash for quantization options */
-static void
-ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
+static int
+ip_handle_quant_opts_low(pTHX_ i_quantize *quant, HV *hv, int push_errors)
 {
-  /*** POSSIBLY BROKEN: do I need to unref the SV from hv_fetch ***/
   SV **sv;
   int i;
   STRLEN len;
   char *str;
+  int failed = 0;
 
   quant->mc_colors = mymalloc(quant->mc_size * sizeof(i_color));
 
@@ -572,7 +628,9 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
   if (sv && *sv && (str = SvPV(*sv, len))) {
     quant->transp = 
       lookup_name(transp_names, sizeof(transp_names)/sizeof(*transp_names), 
-                 str, tr_none);
+                 str, tr_none, push_errors, "transp", &failed);
+    if (failed)
+       return 0;
     if (quant->transp != tr_none) {
       quant->tr_threshold = 127;
       sv = hv_fetch(hv, "tr_threshold", 12, 0);
@@ -582,13 +640,18 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
     if (quant->transp == tr_errdiff) {
       sv = hv_fetch(hv, "tr_errdiff", 10, 0);
       if (sv && *sv && (str = SvPV(*sv, len)))
-       quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
+       quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd, push_errors, "tr_errdiff", &failed);
+       if (failed)
+         return 0;
     }
     if (quant->transp == tr_ordered) {
       quant->tr_orddith = od_tiny;
       sv = hv_fetch(hv, "tr_orddith", 10, 0);
-      if (sv && *sv && (str = SvPV(*sv, len)))
-       quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random);
+      if (sv && *sv && (str = SvPV(*sv, len))) {
+       quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random, push_errors, "tr_orddith", &failed);
+       if (failed)
+          return 0;
+      }
 
       if (quant->tr_orddith == od_custom) {
        sv = hv_fetch(hv, "tr_map", 6, 0);
@@ -613,7 +676,9 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
   sv = hv_fetch(hv, "make_colors", 11, 0);
   if (sv && *sv && (str = SvPV(*sv, len))) {
     quant->make_colors = 
-      lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut);
+      lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut, push_errors, "make_colors", &failed);
+    if (failed)
+      return 0;
   }
   sv = hv_fetch(hv, "colors", 6, 0);
   if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) {
@@ -630,6 +695,10 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
        i_color *col = INT2PTR(i_color *, SvIV((SV*)SvRV(*sv1)));
        quant->mc_colors[i] = *col;
       }
+      else if (push_errors) {
+        i_push_errorf(0, "colors[%d] isn't an Imager::Color object", i);
+       return 0;
+      }
     }
   }
   sv = hv_fetch(hv, "max_colors", 10, 0);
@@ -642,11 +711,15 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
   quant->translate = pt_closest;
   sv = hv_fetch(hv, "translate", 9, 0);
   if (sv && *sv && (str = SvPV(*sv, len))) {
-    quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest);
+    quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest, push_errors, "translate", &failed);
+    if (failed)
+      return 0;
   }
   sv = hv_fetch(hv, "errdiff", 7, 0);
   if (sv && *sv && (str = SvPV(*sv, len))) {
-    quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
+    quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd, push_errors, "errdiff", &failed);
+    if (failed)
+      return 0;
   }
   if (quant->translate == pt_errdiff && quant->errdiff == ed_custom) {
     /* get the error diffusion map */
@@ -671,7 +744,12 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
        for (i = 0; i < len; ++i) {
          SV **sv2 = av_fetch(av, i, 0);
          if (sv2 && *sv2) {
-           quant->ed_map[i] = SvIV(*sv2);
+           IV iv = SvIV(*sv2);
+           if (push_errors && iv < 0) {
+             i_push_errorf(0, "errdiff_map values must be non-negative, errdiff[%d] is negative", i);
+             return 0;
+           }
+           quant->ed_map[i] = iv;
            sum += quant->ed_map[i];
          }
        }
@@ -681,12 +759,18 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
        myfree(quant->ed_map);
        quant->ed_map = 0;
        quant->errdiff = ed_floyd;
+       if (push_errors) {
+         i_push_error(0, "error diffusion map must contain some non-zero values");
+         return 0;
+       }
       }
     }
   }
   sv = hv_fetch(hv, "perturb", 7, 0);
   if (sv && *sv)
     quant->perturb = SvIV(*sv);
+
+  return 1;
 }
 
 static void
@@ -696,6 +780,20 @@ ip_cleanup_quant_opts(pTHX_ i_quantize *quant) {
     myfree(quant->ed_map);
 }
 
+static int
+ip_handle_quant_opts2(pTHX_ i_quantize *quant, HV *hv) {
+  int result = ip_handle_quant_opts_low(aTHX_ quant, hv, 1);
+  if (!result) {
+     ip_cleanup_quant_opts(aTHX_ quant);
+  }
+  return result;
+}
+
+static void
+ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) {
+  (void)ip_handle_quant_opts_low(aTHX_ quant, hv, 0);
+}
+
 /* copies the color map from the hv into the colors member of the HV */
 static void
 ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) {
@@ -723,6 +821,95 @@ ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) {
   }
 }
 
+static struct value_name
+poly_fill_mode_names[] =
+{
+  { "evenodd", i_pfm_evenodd },
+  { "nonzero", i_pfm_nonzero }
+};
+
+static i_poly_fill_mode_t
+S_get_poly_fill_mode(pTHX_ SV *sv) {   
+  if (looks_like_number(sv)) {
+    IV work = SvIV(sv);
+    if (work < (IV)i_pfm_evenodd || work > (IV)i_pfm_nonzero)
+      work = (IV)i_pfm_evenodd;
+    return (i_poly_fill_mode_t)work;
+  }
+  else {
+    return (i_poly_fill_mode_t)lookup_name
+    (poly_fill_mode_names, ARRAY_COUNT(poly_fill_mode_names),
+     SvPV_nolen(sv), i_pfm_evenodd, 0, NULL, NULL);
+  }
+}
+
+static void
+S_get_polygon_list(pTHX_ i_polygon_list *polys, SV *sv) {
+  AV *av;
+  int i;
+  i_polygon_t *s;
+
+  SvGETMAGIC(sv);
+  if (!SvOK(sv) || !SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV) 
+    croak("polys must be an arrayref");
+
+  av = (AV*)SvRV(sv);
+  polys->count = av_len(av) + 1;
+  if (polys->count < 1)
+    croak("polypolygon: no polygons provided");
+  s = malloc_temp(aTHX_ sizeof(i_polygon_t) * polys->count);
+  for (i = 0; i < polys->count; ++i) {
+    SV **poly_sv = av_fetch(av, i, 0);
+    AV *poly_av;
+    SV **x_sv, **y_sv;
+    AV *x_av, *y_av;
+    double *x_data, *y_data;
+    ssize_t j;
+    ssize_t point_count;
+
+    if (!poly_sv)
+      croak("poly_polygon: nothing found for polygon %d", i);
+    /* needs to be another av */
+    SvGETMAGIC(*poly_sv);
+    if (!SvOK(*poly_sv) || !SvROK(*poly_sv) || SvTYPE(SvRV(*poly_sv)) != SVt_PVAV)
+      croak("poly_polygon: polygon %d isn't an arrayref", i);
+    poly_av = (AV*)SvRV(*poly_sv);
+    /* with two elements */
+    if (av_len(poly_av) != 1)
+      croak("poly_polygon: polygon %d should contain two arrays", i);
+    x_sv = av_fetch(poly_av, 0, 0);
+    y_sv = av_fetch(poly_av, 1, 0);
+    if (!x_sv)
+      croak("poly_polygon: polygon %d has no x elements", i);
+    if (!y_sv)
+      croak("poly_polygon: polygon %d has no y elements", i);
+    SvGETMAGIC(*x_sv);
+    SvGETMAGIC(*y_sv);
+    if (!SvOK(*x_sv) || !SvROK(*x_sv) || SvTYPE(SvRV(*x_sv)) != SVt_PVAV)
+      croak("poly_polygon: polygon %d x elements isn't an array", i);
+    if (!SvOK(*y_sv) || !SvROK(*y_sv) || SvTYPE(SvRV(*y_sv)) != SVt_PVAV)
+      croak("poly_polygon: polygon %d y elements isn't an array", i);
+    x_av = (AV*)SvRV(*x_sv);
+    y_av = (AV*)SvRV(*y_sv);
+    if (av_len(x_av) != av_len(y_av))
+      croak("poly_polygon: polygon %d x and y arrays different lengths", i+1);
+    point_count = av_len(x_av)+1;
+    x_data = malloc_temp(aTHX_ sizeof(double) * point_count * 2);
+    y_data = x_data + point_count;
+
+    for (j = 0; j < point_count; ++j) {
+      SV **x_item_sv = av_fetch(x_av, j, 0);
+      SV **y_item_sv = av_fetch(y_av, j, 0);
+      x_data[j] = x_item_sv ? SvNV(*x_item_sv) : 0;
+      y_data[j] = y_item_sv ? SvNV(*y_item_sv) : 0;
+    }
+    s[i].x = x_data;
+    s[i].y = y_data;
+    s[i].count = point_count;
+  }
+  polys->polygons = s;
+}
+
 /* loads the segments of a fountain fill into an array */
 static i_fountain_seg *
 load_fount_segs(pTHX_ AV *asegs, int *count) {
@@ -922,7 +1109,8 @@ static im_pl_ext_funcs im_perl_funcs =
   IMAGER_PL_API_LEVEL,
   ip_handle_quant_opts,
   ip_cleanup_quant_opts,
-  ip_copy_colors_back
+  ip_copy_colors_back,
+  ip_handle_quant_opts2
 };
 
 #define PERL_PL_SET_GLOBAL_CALLBACKS \
@@ -971,7 +1159,10 @@ ICL_set_internal(cl,r,g,b,a)
                unsigned char     b
                unsigned char     a
           PPCODE:
-              ICL_set_internal(cl, r, g, b, a);
+              cl->rgba.r = r;
+              cl->rgba.g = g;
+              cl->rgba.b = b;
+              cl->rgba.a = a;
               EXTEND(SP, 1);
               PUSHs(ST(0));
 
@@ -1016,10 +1207,10 @@ MODULE = Imager        PACKAGE = Imager::Color::Float  PREFIX=ICLF_
 
 Imager::Color::Float
 ICLF_new_internal(r, g, b, a)
-        double r
-        double g
-        double b
-        double a
+        im_double r
+        im_double g
+        im_double b
+        im_double a
 
 void
 ICLF_DESTROY(cl)
@@ -1040,10 +1231,10 @@ ICLF_rgba(cl)
 void
 ICLF_set_internal(cl,r,g,b,a)
         Imager::Color::Float    cl
-        double     r
-        double     g
-        double     b
-        double     a
+        im_double     r
+        im_double     g
+        im_double     b
+        im_double     a
       PPCODE:
         cl->rgba.r = r;
         cl->rgba.g = g;
@@ -1075,9 +1266,9 @@ i_rgb_to_hsv(c)
 MODULE = Imager                PACKAGE = Imager::ImgRaw        PREFIX = IIM_
 
 Imager::ImgRaw
-IIM_new(x,y,ch)
-               i_img_dim     x
-              i_img_dim     y
+IIM_new(xsize,ysize,ch)
+               i_img_dim     xsize
+              i_img_dim     ysize
               int     ch
 
 void
@@ -1103,7 +1294,10 @@ Imager::IO
 io_new_buffer(data_sv)
          SV   *data_sv
        CODE:
+         i_clear_error();
          RETVAL = do_io_new_buffer(aTHX_ data_sv);
+         if (!RETVAL)
+           XSRETURN(0);
         OUTPUT:
           RETVAL
 
@@ -1113,7 +1307,6 @@ io_new_cb(writecb, readcb, seekcb, closecb, maxwrite = CBDATA_BUFSIZE)
         SV *readcb;
         SV *seekcb;
         SV *closecb;
-        int maxwrite;
       CODE:
         RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb);
       OUTPUT:
@@ -1175,7 +1368,10 @@ Imager::IO
 io_new_buffer(class, data_sv)
        SV *data_sv
     CODE:
+        i_clear_error();
         RETVAL = do_io_new_buffer(aTHX_ data_sv);
+       if (!RETVAL)
+         XSRETURN(0);
     OUTPUT:
         RETVAL
 
@@ -1246,12 +1442,12 @@ i_io_raw_read(ig, buffer_sv, size)
         if (size <= 0)
          croak("size negative in call to i_io_raw_read()");
         /* prevent an undefined value warning if they supplied an 
-          undef buffer.
+          undef buffer.
            Orginally conditional on !SvOK(), but this will prevent the
-          downgrade from croaking */
-       sv_setpvn(buffer_sv, "", 0);
+          downgrade from croaking */
+       sv_setpvn(buffer_sv, "", 0);
 #ifdef SvUTF8
-       if (SvUTF8(buffer_sv))
+       if (SvUTF8(buffer_sv))
           sv_utf8_downgrade(buffer_sv, FALSE);
 #endif
        buffer = SvGROW(buffer_sv, size+1);
@@ -1318,6 +1514,10 @@ int
 i_io_getc(ig)
        Imager::IO ig
 
+void
+i_io_nextc(ig)
+       Imager::IO ig
+
 int
 i_io_putc(ig, c)
        Imager::IO ig
@@ -1377,12 +1577,12 @@ i_io_read(ig, buffer_sv, size)
         if (size <= 0)
          croak("size negative in call to i_io_read()");
         /* prevent an undefined value warning if they supplied an 
-          undef buffer.
+          undef buffer.
            Orginally conditional on !SvOK(), but this will prevent the
-          downgrade from croaking */
-       sv_setpvn(buffer_sv, "", 0);
+          downgrade from croaking */
+       sv_setpvn(buffer_sv, "", 0);
 #ifdef SvUTF8
-       if (SvUTF8(buffer_sv))
+       if (SvUTF8(buffer_sv))
           sv_utf8_downgrade(buffer_sv, FALSE);
 #endif
        buffer = SvGROW(buffer_sv, size+1);
@@ -1575,6 +1775,22 @@ IV
 i_img_get_height(im)
     Imager::ImgRaw     im
 
+int
+i_img_color_model(im)
+    Imager::ImgRaw     im
+
+int
+i_img_color_channels(im)
+    Imager::ImgRaw     im
+
+int
+i_img_alpha_channel(im)
+    Imager::ImgRaw     im
+  CODE:
+    if (!i_img_alpha_channel(im, &RETVAL))
+      XSRETURN(0);
+  OUTPUT:
+    RETVAL
 
 void
 i_img_is_monochrome(im)
@@ -1657,19 +1873,19 @@ i_arc(im,x,y,rad,d1,d2,val)
     Imager::ImgRaw     im
               i_img_dim     x
               i_img_dim     y
-             double     rad
-             double     d1
-             double     d2
+             im_double     rad
+             im_double     d1
+             im_double     d2
           Imager::Color    val
 
 void
 i_arc_aa(im,x,y,rad,d1,d2,val)
     Imager::ImgRaw     im
-           double     x
-           double     y
-            double     rad
-            double     d1
-            double     d2
+           im_double     x
+           im_double     y
+            im_double     rad
+            im_double     d1
+            im_double     d2
           Imager::Color    val
 
 void
@@ -1677,30 +1893,38 @@ i_arc_cfill(im,x,y,rad,d1,d2,fill)
     Imager::ImgRaw     im
               i_img_dim     x
               i_img_dim     y
-             double     rad
-             double     d1
-             double     d2
+             im_double     rad
+             im_double     d1
+             im_double     d2
           Imager::FillHandle    fill
 
 void
 i_arc_aa_cfill(im,x,y,rad,d1,d2,fill)
     Imager::ImgRaw     im
-           double     x
-           double     y
-            double     rad
-            double     d1
-            double     d2
+           im_double     x
+           im_double     y
+            im_double     rad
+            im_double     d1
+            im_double     d2
           Imager::FillHandle   fill
 
 
 void
 i_circle_aa(im,x,y,rad,val)
     Imager::ImgRaw     im
-            double     x
-            double     y
-             double     rad
+            im_double     x
+            im_double     y
+             im_double     rad
           Imager::Color    val
 
+void
+i_circle_aa_fill(im,x,y,rad,fill)
+    Imager::ImgRaw     im
+            im_double     x
+            im_double     y
+             im_double     rad
+          Imager::FillHandle    fill
+
 int
 i_circle_out(im,x,y,rad,val)
     Imager::ImgRaw     im
@@ -1723,8 +1947,8 @@ i_arc_out(im,x,y,rad,d1,d2,val)
             i_img_dim     x
             i_img_dim     y
              i_img_dim     rad
-            double d1
-            double d2
+            im_double d1
+            im_double d2
           Imager::Color    val
 
 int
@@ -1733,51 +1957,31 @@ i_arc_out_aa(im,x,y,rad,d1,d2,val)
             i_img_dim     x
             i_img_dim     y
              i_img_dim     rad
-            double d1
-            double d2
+            im_double d1
+            im_double d2
           Imager::Color    val
 
 
 void
-i_bezier_multi(im,xc,yc,val)
+i_bezier_multi(im,x,y,val)
     Imager::ImgRaw     im
-             Imager::Color  val
-            PREINIT:
-            double   *x,*y;
-            int       len;
-            AV       *av1;
-            AV       *av2;
-            SV       *sv1;
-            SV       *sv2;
-            int i;
-            PPCODE:
-            ICL_info(val);
-            if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
-            if (!SvROK(ST(2))) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
-            av1=(AV*)SvRV(ST(1));
-            av2=(AV*)SvRV(ST(2));
-            if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
-            len=av_len(av1)+1;
-            x=mymalloc( len*sizeof(double) );
-            y=mymalloc( len*sizeof(double) );
-            for(i=0;i<len;i++) {
-              sv1=(*(av_fetch(av1,i,0)));
-              sv2=(*(av_fetch(av2,i,0)));
-              x[i]=(double)SvNV(sv1);
-              y[i]=(double)SvNV(sv2);
-            }
-             i_bezier_multi(im,len,x,y,val);
-             myfree(x);
-             myfree(y);
-
+    double *x
+    double *y
+    Imager::Color  val
+  PREINIT:
+    STRLEN size_x;
+    STRLEN size_y;
+  PPCODE:
+    if (size_x != size_y)
+      croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
+    i_bezier_multi(im,size_x,x,y,val);
 
 int
-i_poly_aa(im,x,y,val)
+i_poly_aa_m(im,x,y,mode,val)
     Imager::ImgRaw     im
     double *x
     double *y
+    i_poly_fill_mode_t mode
     Imager::Color  val
   PREINIT:
     STRLEN   size_x;
@@ -1785,15 +1989,16 @@ i_poly_aa(im,x,y,val)
   CODE:
     if (size_x != size_y)
       croak("Imager: x and y arrays to i_poly_aa must be equal length\n");
-    RETVAL = i_poly_aa(im, size_x, x, y, val);
+    RETVAL = i_poly_aa_m(im, size_x, x, y, mode, val);
   OUTPUT:
     RETVAL
 
 int
-i_poly_aa_cfill(im, x, y, fill)
+i_poly_aa_cfill_m(im, x, y, mode, fill)
     Imager::ImgRaw     im
     double *x
     double *y
+    i_poly_fill_mode_t mode
     Imager::FillHandle     fill
   PREINIT:
     STRLEN size_x;
@@ -1801,10 +2006,32 @@ i_poly_aa_cfill(im, x, y, fill)
   CODE:
     if (size_x != size_y)
       croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n");
-    RETVAL = i_poly_aa_cfill(im, size_x, x, y, fill);
+    RETVAL = i_poly_aa_cfill_m(im, size_x, x, y, mode, fill);
   OUTPUT:
     RETVAL
 
+int
+i_poly_poly_aa(im, polys, mode, color)
+    Imager::ImgRaw     im
+         i_polygon_list polys
+        i_poly_fill_mode_t mode
+        Imager::Color color
+    CODE:
+        RETVAL = i_poly_poly_aa(im, polys.count, polys.polygons, mode, color);
+    OUTPUT:
+        RETVAL
+
+int
+i_poly_poly_aa_cfill(im, polys, mode, fill)
+    Imager::ImgRaw     im
+         i_polygon_list polys
+        i_poly_fill_mode_t mode
+        Imager::FillHandle fill
+    CODE:
+        RETVAL = i_poly_poly_aa_cfill(im, polys.count, polys.polygons, mode, fill);
+    OUTPUT:
+        RETVAL
+
 undef_int
 i_flood_fill(im,seedx,seedy,dcol)
     Imager::ImgRaw     im
@@ -1887,7 +2114,7 @@ i_compose(out, src, out_left, out_top, src_left, src_top, width, height, combine
        i_img_dim width
        i_img_dim height
        int combine
-       double opacity
+       im_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)
@@ -1903,7 +2130,7 @@ i_compose_mask(out, src, mask, out_left, out_top, src_left, src_top, mask_left,
        i_img_dim width
        i_img_dim height
        int combine
-       double opacity
+       im_double opacity
 
 Imager::ImgRaw
 i_combine(src_av, channels_av = NULL)
@@ -1959,7 +2186,7 @@ i_rotate90(im, degrees)
 Imager::ImgRaw
 i_rotate_exact(im, amount, ...)
     Imager::ImgRaw      im
-            double      amount
+            im_double      amount
       PREINIT:
        i_color *backp = NULL;
        i_fcolor *fbackp = NULL;
@@ -2026,13 +2253,13 @@ i_matrix_transform(im, xsize, ysize, matrix_av, ...)
 undef_int
 i_gaussian(im,stdev)
     Imager::ImgRaw     im
-           double     stdev
+           im_double     stdev
 
 void
 i_unsharp_mask(im,stdev,scale)
     Imager::ImgRaw     im
-            double    stdev
-             double    scale
+            im_double    stdev
+             im_double    scale
 
 int
 i_conv(im,coef)
@@ -2110,7 +2337,6 @@ i_map(im, pmaps_av)
     AV *pmaps_av
   PREINIT:
     unsigned int mask = 0;
-    AV *avmain;
     AV *avsub;
     SV **temp;
     int len;
@@ -2158,7 +2384,7 @@ int
 i_img_samef(im1, im2, epsilon = i_img_epsilonf(), what=NULL)
     Imager::ImgRaw    im1
     Imager::ImgRaw    im2
-    double epsilon
+    im_double epsilon
     const char *what
 
 double
@@ -2210,7 +2436,7 @@ i_tt_text(handle,im,xb,yb,cl,points,str_sv,smooth,utf8,align=1)
               i_img_dim     xb
               i_img_dim     yb
      Imager::Color     cl
-             double     points
+             im_double     points
              SV *     str_sv
               int     smooth
                int     utf8
@@ -2237,7 +2463,7 @@ i_tt_cp(handle,im,xb,yb,channel,points,str_sv,smooth,utf8,align=1)
               i_img_dim     xb
               i_img_dim     yb
               int     channel
-             double     points
+             im_double     points
              SV *     str_sv
               int     smooth
                int     utf8
@@ -2260,7 +2486,7 @@ i_tt_cp(handle,im,xb,yb,channel,points,str_sv,smooth,utf8,align=1)
 void
 i_tt_bbox(handle,point,str_sv,utf8)
   Imager::Font::TT     handle
-            double     point
+            im_double     point
               SV*    str_sv
                int     utf8
             PREINIT:
@@ -2303,10 +2529,12 @@ i_tt_has_chars(handle, text_sv, utf8)
         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(boolSV(work[i]));
-          }
+         if (count) {
+            EXTEND(SP, count);
+            for (i = 0; i < count; ++i) {
+              PUSHs(boolSV(work[i]));
+            }
+         }
         }
         else {
           EXTEND(SP, 1);
@@ -2342,7 +2570,6 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0)
         size_t len;
         size_t outsize;
         char name[255];
-       SSize_t count = 0;
       PPCODE:
         i_clear_error();
         text = SvPV(text_sv, work_len);
@@ -2364,16 +2591,14 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0)
             ch = *text++;
             --len;
           }
-          EXTEND(SP, count+1);
+          EXTEND(SP, 1);
           if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
-           ST(count) = sv_2mortal(newSVpv(name, 0));
+           PUSHs(sv_2mortal(newSVpv(name, 0)));
           }
           else {
-           ST(count) = &PL_sv_undef;
+           PUSHs(&PL_sv_undef);
           }
-          ++count;
         }
-       XSRETURN(count);
 
 #endif 
 
@@ -2382,6 +2607,40 @@ i_test_format_probe(ig, length)
         Imager::IO     ig
               int     length
 
+int
+i_add_file_magic(name, bits_sv, mask_sv)
+        const char *name
+        SV *bits_sv
+        SV *mask_sv
+      PREINIT:
+        const unsigned char *bits;
+        const unsigned char *mask;
+       size_t bits_size;
+       size_t mask_size;
+      CODE:
+       i_clear_error();
+       bits = SvPV(bits_sv, bits_size);
+        mask = SvPV(mask_sv, mask_size);
+        if (bits_size == 0) {
+           i_push_error(0, "bits must be non-empty");
+           XSRETURN_EMPTY;
+       }
+       if (mask_size == 0) {
+           i_push_error(0, "mask must be non-empty");
+           XSRETURN_EMPTY;
+       }
+       if (bits_size != mask_size) {
+           i_push_error(0, "bits and mask must be the same length");
+           XSRETURN_EMPTY;
+       }
+       if (!*name) {
+           i_push_error(0, "name must be non-empty");
+           XSRETURN_EMPTY;
+       }
+       RETVAL = i_add_file_magic(name, bits, mask, bits_size);
+      OUTPUT:
+       RETVAL
+
 Imager::ImgRaw
 i_readpnm_wiol(ig, allow_incomplete)
         Imager::IO     ig
@@ -2469,14 +2728,14 @@ i_readtga_wiol(ig, length)
 Imager::ImgRaw
 i_scaleaxis(im,Value,Axis)
     Imager::ImgRaw     im
-             double     Value
+             im_double     Value
               int     Axis
 
 Imager::ImgRaw
 i_scale_nn(im,scx,scy)
     Imager::ImgRaw     im
-             double    scx
-             double    scy
+             im_double    scx
+             im_double    scy
 
 Imager::ImgRaw
 i_scale_mixing(im, width, height)
@@ -2503,12 +2762,14 @@ i_get_anonymous_color_histo(im, maxc = 0x40000000)
         int col_cnt;
     PPCODE:
        col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc);
+        if (col_cnt <= 0) {
+           XSRETURN_EMPTY;
+       }
         EXTEND(SP, col_cnt);
         for (i = 0; i < col_cnt; i++)  {
             PUSHs(sv_2mortal(newSViv( col_usage[i])));
         }
         myfree(col_usage);
-        XSRETURN(col_cnt);
 
 
 void
@@ -2627,7 +2888,7 @@ i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
 void
 i_contrast(im,intensity)
     Imager::ImgRaw     im
-             float     intensity
+             im_float     intensity
 
 void
 i_hardinvert(im)
@@ -2640,7 +2901,7 @@ i_hardinvertall(im)
 void
 i_noise(im,amount,type)
     Imager::ImgRaw     im
-             float     amount
+             im_float     amount
      unsigned char     type
 
 void
@@ -2660,12 +2921,12 @@ i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
                int     channel
                i_img_dim     tx
                i_img_dim     ty
-             double     Lx
-             double     Ly
-             double     Lz
-             float     cd
-             float     cs
-             float     n
+             im_double     Lx
+             im_double     Ly
+             im_double     Lz
+             im_float     cd
+             im_float     cs
+             im_float     n
      Imager::Color     Ia
      Imager::Color     Il
      Imager::Color     Is
@@ -2694,24 +2955,30 @@ i_watermark(im,wmark,tx,ty,pixdiff)
 void
 i_autolevels(im,lsat,usat,skew)
     Imager::ImgRaw     im
-             float     lsat
-             float     usat
-             float     skew
+             im_float     lsat
+             im_float     usat
+             im_float     skew
+
+void
+i_autolevels_mono(im,lsat,usat)
+    Imager::ImgRaw     im
+             im_float     lsat
+             im_float     usat
 
 void
 i_radnoise(im,xo,yo,rscale,ascale)
     Imager::ImgRaw     im
-             float     xo
-             float     yo
-             float     rscale
-             float     ascale
+             im_float     xo
+             im_float     yo
+             im_float     rscale
+             im_float     ascale
 
 void
 i_turbnoise(im, xo, yo, scale)
     Imager::ImgRaw     im
-             float     xo
-             float     yo
-             float     scale
+             im_float     xo
+             im_float     yo
+             im_float     scale
 
 
 void
@@ -2736,20 +3003,20 @@ Imager::ImgRaw
 i_diff_image(im, im2, mindist=0)
     Imager::ImgRaw     im
     Imager::ImgRaw     im2
-            double     mindist
+            im_double     mindist
 
 undef_int
 i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
     Imager::ImgRaw     im
-            double     xa
-            double     ya
-            double     xb
-            double     yb
+            im_double     xa
+            im_double     ya
+            im_double     xb
+            im_double     yb
                int     type
                int     repeat
                int     combine
                int     super_sample
-            double     ssample_param
+            im_double     ssample_param
       PREINIT:
         AV *asegs;
         int count;
@@ -2768,15 +3035,15 @@ i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_para
 
 Imager::FillHandle
 i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
-            double     xa
-            double     ya
-            double     xb
-            double     yb
+            im_double     xa
+            im_double     ya
+            im_double     xb
+            im_double     yb
                int     type
                int     repeat
                int     combine
                int     super_sample
-            double     ssample_param
+            im_double     ssample_param
       PREINIT:
         AV *asegs;
         int count;
@@ -2796,7 +3063,7 @@ i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_pa
 Imager::FillHandle
 i_new_fill_opacity(other_fill, alpha_mult)
     Imager::FillHandle other_fill
-    double alpha_mult
+    im_double alpha_mult
 
 void
 i_errors()
@@ -2818,7 +3085,7 @@ i_errors()
          if (!av_store(av, 1, sv)) {
            SvREFCNT_dec(sv);
          }
-         PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
+         XPUSHs(sv_2mortal(newRV_noinc((SV*)av)));
          ++i;
        }
 
@@ -2862,9 +3129,9 @@ i_nearest_color(im, ...)
        num = num <= av_len(ac) ? num : av_len(ac);
        num++; 
        if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
-       xo = mymalloc( sizeof(i_img_dim) * num );
-       yo = mymalloc( sizeof(i_img_dim) * num );
-       ival = mymalloc( sizeof(i_color) * num );
+       xo = malloc_temp(aTHX_ sizeof(i_img_dim) * num );
+       yo = malloc_temp(aTHX_ sizeof(i_img_dim) * num );
+       ival = malloc_temp(aTHX_ sizeof(i_color) * num );
        for(i = 0; i<num; i++) {
          xo[i]   = (i_img_dim)SvIV(* av_fetch(axx, i, 0));
          yo[i]   = (i_img_dim)SvIV(* av_fetch(ayy, i, 0));
@@ -2939,6 +3206,7 @@ i_get_pixel(im, x, y)
        i_img_dim y;
       CODE:
        RETVAL = (i_color *)mymalloc(sizeof(i_color));
+       memset(RETVAL, 0, sizeof(*RETVAL));
        if (i_gpix(im, x, y, RETVAL) != 0) {
           myfree(RETVAL);
          XSRETURN_UNDEF;
@@ -2962,22 +3230,23 @@ i_img_pal_new(x, y, channels, maxpal)
        int     maxpal
 
 Imager::ImgRaw
-i_img_to_pal(src, quant)
+i_img_to_pal(src, quant_hv)
         Imager::ImgRaw src
+       HV *quant_hv
       PREINIT:
         HV *hv;
         i_quantize quant;
       CODE:
-        if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
-          croak("i_img_to_pal: second argument must be a hash ref");
-        hv = (HV *)SvRV(ST(1));
         memset(&quant, 0, sizeof(quant));
        quant.version = 1;
         quant.mc_size = 256;
-       ip_handle_quant_opts(aTHX_ &quant, hv);
+       i_clear_error();
+       if (!ip_handle_quant_opts2(aTHX_ &quant, quant_hv)) {
+          XSRETURN_EMPTY;
+       }
         RETVAL = i_img_to_pal(src, &quant);
         if (RETVAL) {
-          ip_copy_colors_back(aTHX_ hv, &quant);
+          ip_copy_colors_back(aTHX_ quant_hv, &quant);
         }
        ip_cleanup_quant_opts(aTHX_ &quant);
       OUTPUT:
@@ -3011,7 +3280,9 @@ i_img_make_palette(HV *quant_hv, ...)
         memset(&quant, 0, sizeof(quant));
        quant.version = 1;
        quant.mc_size = 256;
-        ip_handle_quant_opts(aTHX_ &quant, quant_hv);
+        if (!ip_handle_quant_opts2(aTHX_ &quant, quant_hv)) {
+         XSRETURN_EMPTY;
+       }
        i_quant_makemap(&quant, imgs, count);
        EXTEND(SP, quant.mc_count);
        for (i = 0; i < quant.mc_count; ++i) {
@@ -3019,6 +3290,7 @@ i_img_make_palette(HV *quant_hv, ...)
          PUSHs(sv_c);
        }
        ip_cleanup_quant_opts(aTHX_ &quant);
+        myfree(imgs);
        
 
 void
@@ -3120,6 +3392,7 @@ i_addcolors(im, ...)
           }
         }
         RETVAL = i_addcolors(im, colors, items-1);
+        myfree(colors);
       OUTPUT:
         RETVAL
 
@@ -3532,6 +3805,7 @@ i_gpixf(im, x, y)
        i_img_dim y;
       CODE:
        RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor));
+       memset(RETVAL, 0, sizeof(*RETVAL));
        if (i_gpixf(im, x, y, RETVAL) != 0) {
           myfree(RETVAL);
           XSRETURN_UNDEF;
@@ -3604,26 +3878,26 @@ i_glinf(im, l, r, y)
         }
 
 Imager::ImgRaw
-i_img_8_new(x, y, ch)
-        i_img_dim x
-        i_img_dim y
-        int ch
+i_img_8_new(xsize, ysize, channels)
+        i_img_dim xsize
+        i_img_dim ysize
+        int channels
 
 Imager::ImgRaw
-i_img_16_new(x, y, ch)
-        i_img_dim x
-        i_img_dim y
-        int ch
+i_img_16_new(xsize, ysize, channels)
+        i_img_dim xsize
+        i_img_dim ysize
+        int channels
 
 Imager::ImgRaw
 i_img_to_rgb16(im)
        Imager::ImgRaw im
 
 Imager::ImgRaw
-i_img_double_new(x, y, ch)
-        i_img_dim x
-        i_img_dim y
-        int ch
+i_img_double_new(xsize, ysize, channels)
+        i_img_dim xsize
+        i_img_dim ysize
+        int channels
 
 Imager::ImgRaw
 i_img_to_drgb(im)
@@ -3676,7 +3950,7 @@ i_tags_add(im, name_sv, code, data_sv, idata)
       OUTPUT:
         RETVAL
 
-SV *
+SysRet
 i_tags_find(im, name, start)
         Imager::ImgRaw  im
         char *name
@@ -3685,17 +3959,14 @@ i_tags_find(im, name, start)
         int entry;
       CODE:
         if (i_tags_find(&im->tags, name, start, &entry)) {
-          if (entry == 0)
-            RETVAL = newSVpv("0 but true", 0);
-          else
-            RETVAL = newSViv(entry);
+         RETVAL = entry;
         } else {
-          RETVAL = &PL_sv_undef;
+          XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
 
-SV *
+SysRet
 i_tags_findn(im, code, start)
         Imager::ImgRaw  im
         int             code
@@ -3704,13 +3975,10 @@ i_tags_findn(im, code, start)
         int entry;
       CODE:
         if (i_tags_findn(&im->tags, code, start, &entry)) {
-          if (entry == 0)
-            RETVAL = newSVpv("0 but true", 0);
-          else
-            RETVAL = newSViv(entry);
+          RETVAL = entry;
         }
         else {
-          RETVAL = &PL_sv_undef;
+          XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
@@ -3824,19 +4092,21 @@ i_new_fill_solidf(cl, combine)
         int combine
 
 Imager::FillHandle
-i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
+i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
         Imager::Color fg
         Imager::Color bg
         int combine
         int hatch
+       SV *cust_hatch_sv
         i_img_dim dx
         i_img_dim dy
       PREINIT:
         unsigned char *cust_hatch;
         STRLEN len;
       CODE:
-        if (SvOK(ST(4))) {
-          cust_hatch = (unsigned char *)SvPV(ST(4), len);
+        SvGETMAGIC(cust_hatch_sv);
+        if (SvOK(cust_hatch_sv)) {
+          cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len);
         }
         else
           cust_hatch = NULL;
@@ -3845,19 +4115,21 @@ i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
         RETVAL
 
 Imager::FillHandle
-i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
+i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
         Imager::Color::Float fg
         Imager::Color::Float bg
         int combine
         int hatch
+        SV *cust_hatch_sv
         i_img_dim dx
         i_img_dim dy
       PREINIT:
         unsigned char *cust_hatch;
         STRLEN len;
       CODE:
-        if (SvOK(ST(4))) {
-          cust_hatch = (unsigned char *)SvPV(ST(4), len);
+        SvGETMAGIC(cust_hatch_sv);
+        if (SvOK(cust_hatch_sv)) {
+          cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len);
         }
         else
           cust_hatch = NULL;
@@ -3866,8 +4138,9 @@ i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
         RETVAL
 
 Imager::FillHandle
-i_new_fill_image(src, matrix, xoff, yoff, combine)
+i_new_fill_image(src, matrix_sv, xoff, yoff, combine)
         Imager::ImgRaw src
+       SV *matrix_sv
         i_img_dim xoff
         i_img_dim yoff
         int combine
@@ -3879,13 +4152,14 @@ i_new_fill_image(src, matrix, xoff, yoff, combine)
         SV *sv1;
         int i;
       CODE:
-        if (!SvOK(ST(1))) {
+        SvGETMAGIC(matrix_sv);
+        if (!SvOK(matrix_sv)) {
           matrixp = NULL;
         }
         else {
-          if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
-            croak("i_new_fill_image: parameter must be an arrayref");
-         av=(AV*)SvRV(ST(1));
+          if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV)
+            croak("i_new_fill_image: matrix parameter must be an arrayref or undef");
+         av=(AV*)SvRV(matrix_sv);
          len=av_len(av)+1;
           if (len > 9)
             len = 9;
@@ -3957,6 +4231,9 @@ im_context_CLONE(...)
       /* the following sv_setref_pv() will free this inc */
       im_context_refinc(MY_CXT.ctx, "CLONE");
       MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE");
+      if (MY_CXT.ctx == NULL) {
+        croak("Failed to clone Imager context");
+      }
       sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
 
 #endif