]> git.imager.perl.org - imager.git/blobdiff - image.c
allow Imager::IO->new_buffer() to accept a reference
[imager.git] / image.c
diff --git a/image.c b/image.c
index 55c0864b7432976c84083cbaf8498af1e570cfcb..03dc6e2c678e7f459deef8cacd517e044807ffa9 100644 (file)
--- a/image.c
+++ b/image.c
@@ -1,3 +1,5 @@
+#define IMAGER_NO_CONTEXT
+
 #include "imager.h"
 #include "imageri.h"
 
 #include "imager.h"
 #include "imageri.h"
 
@@ -12,7 +14,7 @@ image.c - implements most of the basic functions of Imager and much of the rest
   i_color *c;
   c = i_color_new(red, green, blue, alpha);
   ICL_DESTROY(c);
   i_color *c;
   c = i_color_new(red, green, blue, alpha);
   ICL_DESTROY(c);
-  i = i_img_new();
+  i = i_img_8_new();
   i_img_destroy(i);
   // and much more
 
   i_img_destroy(i);
   // and much more
 
@@ -30,6 +32,8 @@ Some of these functions are internal.
 =cut
 */
 
 =cut
 */
 
+im_context_t (*im_get_context)(void) = NULL;
+
 #define XAXIS 0
 #define YAXIS 1
 #define XYAXIS 2
 #define XAXIS 0
 #define YAXIS 1
 #define XYAXIS 2
@@ -37,22 +41,14 @@ Some of these functions are internal.
 #define minmax(a,b,i) ( ((a>=i)?a: ( (b<=i)?b:i   )) )
 
 /* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */
 #define minmax(a,b,i) ( ((a>=i)?a: ( (b<=i)?b:i   )) )
 
 /* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */
-static void fake(void) { ceil(1); }
-
-static int i_ppix_d(i_img *im, int x, int y, const i_color *val);
-static int i_gpix_d(i_img *im, int x, int y, i_color *val);
-static int i_glin_d(i_img *im, int l, int r, int y, i_color *vals);
-static int i_plin_d(i_img *im, int l, int r, int y, const i_color *vals);
-static int i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val);
-static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val);
-static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
-static int i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals);
-static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, const int *chans, int chan_count);
-static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, const int *chans, int chan_count);
+void i_linker_bug_fake(void) { ceil(1); }
 
 /*
 
 /*
-=item i_img_alloc()
+=item im_img_alloc(aIMCTX)
+X<im_img_alloc API>X<i_img_alloc API>
 =category Image Implementation
 =category Image Implementation
+=synopsis i_img *im = im_img_alloc(aIMCTX);
+=synopsis i_img *im = i_img_alloc();
 
 Allocates a new i_img structure.
 
 
 Allocates a new i_img structure.
 
@@ -81,25 +77,29 @@ object.
 */
 
 i_img *
 */
 
 i_img *
-i_img_alloc(void) {
+im_img_alloc(pIMCTX) {
   return mymalloc(sizeof(i_img));
 }
 
 /*
   return mymalloc(sizeof(i_img));
 }
 
 /*
-=item i_img_init(img)
+=item im_img_init(aIMCTX, image)
+X<im_img_init API>X<i_img_init API>
 =category Image Implementation
 =category Image Implementation
+=synopsis im_img_init(aIMCTX, im);
+=synopsis i_img_init(im);
 
 
-Imager interal initialization of images.
+Imager internal initialization of images.
 
 
-Currently this does very little, in the future it may be used to
-support threads, or color profiles.
+See L</im_img_alloc(aIMCTX)> for more information.
 
 =cut
 */
 
 void
 
 =cut
 */
 
 void
-i_img_init(i_img *img) {
+im_img_init(pIMCTX, i_img *img) {
   img->im_data = NULL;
   img->im_data = NULL;
+  img->context = aIMCTX;
+  im_context_refinc(aIMCTX, "img_init");
 }
 
 /* 
 }
 
 /* 
@@ -118,15 +118,16 @@ Return a new color object with values passed to it.
 i_color *
 ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
   i_color *cl = NULL;
 i_color *
 ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
   i_color *cl = NULL;
+  dIMCTX;
 
 
-  mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
+  im_log((aIMCTX,1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
 
 
-  if ( (cl=mymalloc(sizeof(i_color))) == NULL) i_fatal(2,"malloc() error\n");
+  if ( (cl=mymalloc(sizeof(i_color))) == NULL) im_fatal(aIMCTX, 2,"malloc() error\n");
   cl->rgba.r = r;
   cl->rgba.g = g;
   cl->rgba.b = b;
   cl->rgba.a = a;
   cl->rgba.r = r;
   cl->rgba.g = g;
   cl->rgba.b = b;
   cl->rgba.a = a;
-  mm_log((1,"(%p) <- ICL_new_internal\n",cl));
+  im_log((aIMCTX,1,"(%p) <- ICL_new_internal\n",cl));
   return cl;
 }
 
   return cl;
 }
 
@@ -147,15 +148,16 @@ ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a
 
 i_color *
 ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
 
 i_color *
 ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
-  mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
+  dIMCTX;
+  im_log((aIMCTX,1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
   if (cl == NULL)
     if ( (cl=mymalloc(sizeof(i_color))) == NULL)
   if (cl == NULL)
     if ( (cl=mymalloc(sizeof(i_color))) == NULL)
-      i_fatal(2,"malloc() error\n");
+      im_fatal(aIMCTX, 2,"malloc() error\n");
   cl->rgba.r=r;
   cl->rgba.g=g;
   cl->rgba.b=b;
   cl->rgba.a=a;
   cl->rgba.r=r;
   cl->rgba.g=g;
   cl->rgba.b=b;
   cl->rgba.a=a;
-  mm_log((1,"(%p) <- ICL_set_internal\n",cl));
+  im_log((aIMCTX,1,"(%p) <- ICL_set_internal\n",cl));
   return cl;
 }
 
   return cl;
 }
 
@@ -193,8 +195,9 @@ Dump color information to log - strictly for debugging.
 
 void
 ICL_info(i_color const *cl) {
 
 void
 ICL_info(i_color const *cl) {
-  mm_log((1,"i_color_info(cl* %p)\n",cl));
-  mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
+  dIMCTX;
+  im_log((aIMCTX, 1,"i_color_info(cl* %p)\n",cl));
+  im_log((aIMCTX, 1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
 }
 
 /* 
 }
 
 /* 
@@ -209,7 +212,8 @@ Destroy ancillary data for Color object.
 
 void
 ICL_DESTROY(i_color *cl) {
 
 void
 ICL_DESTROY(i_color *cl) {
-  mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
+  dIMCTX;
+  im_log((aIMCTX, 1,"ICL_DESTROY(cl* %p)\n",cl));
   myfree(cl);
 }
 
   myfree(cl);
 }
 
@@ -220,15 +224,16 @@ ICL_DESTROY(i_color *cl) {
 */
 i_fcolor *i_fcolor_new(double r, double g, double b, double a) {
   i_fcolor *cl = NULL;
 */
 i_fcolor *i_fcolor_new(double r, double g, double b, double a) {
   i_fcolor *cl = NULL;
+  dIMCTX;
 
 
-  mm_log((1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
+  im_log((aIMCTX, 1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
 
 
-  if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) i_fatal(2,"malloc() error\n");
+  if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) im_fatal(aIMCTX, 2,"malloc() error\n");
   cl->rgba.r = r;
   cl->rgba.g = g;
   cl->rgba.b = b;
   cl->rgba.a = a;
   cl->rgba.r = r;
   cl->rgba.g = g;
   cl->rgba.b = b;
   cl->rgba.a = a;
-  mm_log((1,"(%p) <- i_fcolor_new\n",cl));
+  im_log((aIMCTX, 1,"(%p) <- i_fcolor_new\n",cl));
 
   return cl;
 }
 
   return cl;
 }
@@ -242,213 +247,6 @@ void i_fcolor_destroy(i_fcolor *cl) {
   myfree(cl);
 }
 
   myfree(cl);
 }
 
-/*
-=item IIM_base_8bit_direct (static)
-
-A static i_img object used to initialize direct 8-bit per sample images.
-
-=cut
-*/
-static i_img IIM_base_8bit_direct =
-{
-  0, /* channels set */
-  0, 0, 0, /* xsize, ysize, bytes */
-  ~0U, /* ch_mask */
-  i_8_bits, /* bits */
-  i_direct_type, /* type */
-  0, /* virtual */
-  NULL, /* idata */
-  { 0, 0, NULL }, /* tags */
-  NULL, /* ext_data */
-
-  i_ppix_d, /* i_f_ppix */
-  i_ppixf_d, /* i_f_ppixf */
-  i_plin_d, /* i_f_plin */
-  i_plinf_d, /* i_f_plinf */
-  i_gpix_d, /* i_f_gpix */
-  i_gpixf_d, /* i_f_gpixf */
-  i_glin_d, /* i_f_glin */
-  i_glinf_d, /* i_f_glinf */
-  i_gsamp_d, /* i_f_gsamp */
-  i_gsampf_d, /* i_f_gsampf */
-
-  NULL, /* i_f_gpal */
-  NULL, /* i_f_ppal */
-  NULL, /* i_f_addcolors */
-  NULL, /* i_f_getcolors */
-  NULL, /* i_f_colorcount */
-  NULL, /* i_f_maxcolors */
-  NULL, /* i_f_findcolor */
-  NULL, /* i_f_setcolors */
-
-  NULL, /* i_f_destroy */
-
-  i_gsamp_bits_fb,
-  NULL, /* i_f_psamp_bits */
-};
-
-/*static void set_8bit_direct(i_img *im) {
-  im->i_f_ppix = i_ppix_d;
-  im->i_f_ppixf = i_ppixf_d;
-  im->i_f_plin = i_plin_d;
-  im->i_f_plinf = i_plinf_d;
-  im->i_f_gpix = i_gpix_d;
-  im->i_f_gpixf = i_gpixf_d;
-  im->i_f_glin = i_glin_d;
-  im->i_f_glinf = i_glinf_d;
-  im->i_f_gpal = NULL;
-  im->i_f_ppal = NULL;
-  im->i_f_addcolor = NULL;
-  im->i_f_getcolor = NULL;
-  im->i_f_colorcount = NULL;
-  im->i_f_findcolor = NULL;
-  }*/
-
-/*
-=item IIM_new(x, y, ch)
-
-=item i_img_8_new(x, y, ch)
-
-=category Image creation/destruction
-
-=synopsis i_img *img = i_img_8_new(width, height, channels);
-
-Creates a new image object I<x> pixels wide, and I<y> pixels high with
-I<ch> channels.
-
-=cut
-*/
-
-
-i_img *
-IIM_new(int x,int y,int ch) {
-  i_img *im;
-  mm_log((1,"IIM_new(x %d,y %d,ch %d)\n",x,y,ch));
-
-  im=i_img_empty_ch(NULL,x,y,ch);
-  
-  mm_log((1,"(%p) <- IIM_new\n",im));
-  return im;
-}
-
-
-void
-IIM_DESTROY(i_img *im) {
-  mm_log((1,"IIM_DESTROY(im* %p)\n",im));
-  i_img_destroy(im);
-  /*   myfree(cl); */
-}
-
-/* 
-=item i_img_new()
-
-Create new image reference - notice that this isn't an object yet and
-this should be fixed asap.
-
-=cut
-*/
-
-
-i_img *
-i_img_new() {
-  i_img *im;
-  
-  mm_log((1,"i_img_struct()\n"));
-
-  im = i_img_alloc();
-  
-  *im = IIM_base_8bit_direct;
-  im->xsize=0;
-  im->ysize=0;
-  im->channels=3;
-  im->ch_mask=MAXINT;
-  im->bytes=0;
-  im->idata=NULL;
-
-  i_img_init(im);
-  
-  mm_log((1,"(%p) <- i_img_struct\n",im));
-  return im;
-}
-
-/* 
-=item i_img_empty(im, x, y)
-
-Re-new image reference (assumes 3 channels)
-
-   im - Image pointer
-   x - xsize of destination image
-   y - ysize of destination image
-
-**FIXME** what happens if a live image is passed in here?
-
-Should this just call i_img_empty_ch()?
-
-=cut
-*/
-
-i_img *
-i_img_empty(i_img *im,int x,int y) {
-  mm_log((1,"i_img_empty(*im %p, x %d, y %d)\n",im, x, y));
-  return i_img_empty_ch(im, x, y, 3);
-}
-
-/* 
-=item i_img_empty_ch(im, x, y, ch)
-
-Re-new image reference 
-
-   im - Image pointer
-   x  - xsize of destination image
-   y  - ysize of destination image
-   ch - number of channels
-
-=cut
-*/
-
-i_img *
-i_img_empty_ch(i_img *im,int x,int y,int ch) {
-  int bytes;
-
-  mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
-
-  if (x < 1 || y < 1) {
-    i_push_error(0, "Image sizes must be positive");
-    return NULL;
-  }
-  if (ch < 1 || ch > MAXCHANNELS) {
-    i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
-    return NULL;
-  }
-  /* check this multiplication doesn't overflow */
-  bytes = x*y*ch;
-  if (bytes / y / ch != x) {
-    i_push_errorf(0, "integer overflow calculating image allocation");
-    return NULL;
-  }
-
-  if (im == NULL)
-    im = i_img_alloc();
-
-  memcpy(im, &IIM_base_8bit_direct, sizeof(i_img));
-  i_tags_new(&im->tags);
-  im->xsize    = x;
-  im->ysize    = y;
-  im->channels = ch;
-  im->ch_mask  = MAXINT;
-  im->bytes=bytes;
-  if ( (im->idata=mymalloc(im->bytes)) == NULL) 
-    i_fatal(2,"malloc() error\n"); 
-  memset(im->idata,0,(size_t)im->bytes);
-  
-  im->ext_data = NULL;
-
-  i_img_init(im);
-  
-  mm_log((1,"(%p) <- i_img_empty_ch\n",im));
-  return im;
-}
-
 /* 
 =item i_img_exorcise(im)
 
 /* 
 =item i_img_exorcise(im)
 
@@ -461,7 +259,8 @@ Free image data.
 
 void
 i_img_exorcise(i_img *im) {
 
 void
 i_img_exorcise(i_img *im) {
-  mm_log((1,"i_img_exorcise(im* 0x%x)\n",im));
+  dIMCTXim(im);
+  im_log((aIMCTX,1,"i_img_exorcise(im* %p)\n",im));
   i_tags_destroy(&im->tags);
   if (im->i_f_destroy)
     (im->i_f_destroy)(im);
   i_tags_destroy(&im->tags);
   if (im->i_f_destroy)
     (im->i_f_destroy)(im);
@@ -471,15 +270,11 @@ i_img_exorcise(i_img *im) {
   im->ysize    = 0;
   im->channels = 0;
 
   im->ysize    = 0;
   im->channels = 0;
 
-  im->i_f_ppix=i_ppix_d;
-  im->i_f_gpix=i_gpix_d;
-  im->i_f_plin=i_plin_d;
-  im->i_f_glin=i_glin_d;
   im->ext_data=NULL;
 }
 
 /* 
   im->ext_data=NULL;
 }
 
 /* 
-=item i_img_destroy(img)
+=item i_img_destroy(C<img>)
 =order 90
 =category Image creation/destruction
 =synopsis i_img_destroy(img)
 =order 90
 =category Image creation/destruction
 =synopsis i_img_destroy(img)
@@ -491,9 +286,11 @@ Destroy an image object
 
 void
 i_img_destroy(i_img *im) {
 
 void
 i_img_destroy(i_img *im) {
-  mm_log((1,"i_img_destroy(im %p)\n",im));
+  dIMCTXim(im);
+  im_log((aIMCTX, 1,"i_img_destroy(im %p)\n",im));
   i_img_exorcise(im);
   if (im) { myfree(im); }
   i_img_exorcise(im);
   if (im) { myfree(im); }
+  im_context_refdec(aIMCTX, "img_destroy");
 }
 
 /* 
 }
 
 /* 
@@ -518,11 +315,14 @@ info is an array of 4 integers with the following values:
 
 
 void
 
 
 void
-i_img_info(i_img *im,int *info) {
-  mm_log((1,"i_img_info(im 0x%x)\n",im));
+i_img_info(i_img *im, i_img_dim *info) {
+  dIMCTXim(im);
+  im_log((aIMCTX,1,"i_img_info(im %p)\n",im));
   if (im != NULL) {
   if (im != NULL) {
-    mm_log((1,"i_img_info: xsize=%d ysize=%d channels=%d mask=%ud\n",im->xsize,im->ysize,im->channels,im->ch_mask));
-    mm_log((1,"i_img_info: idata=0x%d\n",im->idata));
+    im_log((aIMCTX,1,"i_img_info: xsize=%" i_DF " ysize=%" i_DF " channels=%d "
+           "mask=%ud\n",
+           i_DFc(im->xsize), i_DFc(im->ysize), im->channels,im->ch_mask));
+    im_log((aIMCTX,1,"i_img_info: idata=%p\n",im->idata));
     info[0] = im->xsize;
     info[1] = im->ysize;
     info[2] = im->channels;
     info[0] = im->xsize;
     info[1] = im->ysize;
     info[2] = im->channels;
@@ -536,12 +336,12 @@ i_img_info(i_img *im,int *info) {
 }
 
 /*
 }
 
 /*
-=item i_img_setmask(im, ch_mask)
+=item i_img_setmask(C<im>, C<ch_mask>)
 =category Image Information
 =category Image Information
-=synopsis // only channel 0 writeable 
+=synopsis // only channel 0 writable 
 =synopsis i_img_setmask(img, 0x01);
 
 =synopsis i_img_setmask(img, 0x01);
 
-Set the image channel mask for I<im> to I<ch_mask>.
+Set the image channel mask for C<im> to C<ch_mask>.
 
 The image channel mask gives some control over which channels can be
 written to in the image.
 
 The image channel mask gives some control over which channels can be
 written to in the image.
@@ -553,11 +353,11 @@ i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
 
 
 /*
 
 
 /*
-=item i_img_getmask(im)
+=item i_img_getmask(C<im>)
 =category Image Information
 =synopsis int mask = i_img_getmask(img);
 
 =category Image Information
 =synopsis int mask = i_img_getmask(img);
 
-Get the image channel mask for I<im>.
+Get the image channel mask for C<im>.
 
 =cut
 */
 
 =cut
 */
@@ -565,11 +365,11 @@ int
 i_img_getmask(i_img *im) { return im->ch_mask; }
 
 /*
 i_img_getmask(i_img *im) { return im->ch_mask; }
 
 /*
-=item i_img_getchannels(im)
+=item i_img_getchannels(C<im>)
 =category Image Information
 =synopsis int channels = i_img_getchannels(img);
 
 =category Image Information
 =synopsis int channels = i_img_getchannels(img);
 
-Get the number of channels in I<im>.
+Get the number of channels in C<im>.
 
 =cut
 */
 
 =cut
 */
@@ -577,7 +377,7 @@ int
 i_img_getchannels(i_img *im) { return im->channels; }
 
 /*
 i_img_getchannels(i_img *im) { return im->channels; }
 
 /*
-=item i_img_get_width(im)
+=item i_img_get_width(C<im>)
 =category Image Information
 =synopsis i_img_dim width = i_img_get_width(im);
 
 =category Image Information
 =synopsis i_img_dim width = i_img_get_width(im);
 
@@ -591,7 +391,7 @@ i_img_get_width(i_img *im) {
 }
 
 /*
 }
 
 /*
-=item i_img_get_height(im)
+=item i_img_get_height(C<im>)
 =category Image Information
 =synopsis i_img_dim height = i_img_get_height(im);
 
 =category Image Information
 =synopsis i_img_dim height = i_img_get_height(im);
 
@@ -605,24 +405,27 @@ i_img_get_height(i_img *im) {
 }
 
 /*
 }
 
 /*
-=item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
+=item i_copyto_trans(C<im>, C<src>, C<x1>, C<y1>, C<x2>, C<y2>, C<tx>, C<ty>, C<trans>)
 
 =category Image
 
 
 =category Image
 
-(x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
-(tx,ty) specifies the upper left corner for the target image.
-pass NULL in trans for non transparent i_colors.
+(C<x1>,C<y1>) (C<x2>,C<y2>) specifies the region to copy (in the
+source coordinates) (C<tx>,C<ty>) specifies the upper left corner for
+the target image.  pass NULL in C<trans> for non transparent i_colors.
 
 =cut
 */
 
 void
 
 =cut
 */
 
 void
-i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,const i_color *trans) {
+i_copyto_trans(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty,const i_color *trans) {
   i_color pv;
   i_color pv;
-  int x,y,t,ttx,tty,tt,ch;
+  i_img_dim x,y,t,ttx,tty,tt;
+  int ch;
+  dIMCTXim(im);
 
 
-  mm_log((1,"i_copyto_trans(im* %p,src 0x%x, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d, trans* 0x%x)\n",
-         im, src, x1, y1, x2, y2, tx, ty, trans));
+  im_log((aIMCTX, 1,"i_copyto_trans(im* %p,src %p, p1(" i_DFp "), p2(" i_DFp "), "
+         "to(" i_DFp "), trans* %p)\n",
+         im, src, i_DFcp(x1, y1), i_DFcp(x2, y2), i_DFcp(tx, ty), trans));
   
   if (x2<x1) { t=x1; x1=x2; x2=t; }
   if (y2<y1) { t=y1; y1=y2; y2=t; }
   
   if (x2<x1) { t=x1; x1=x2; x2=t; }
   if (y2<y1) { t=y1; y1=y2; y2=t; }
@@ -647,11 +450,11 @@ i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,co
 }
 
 /*
 }
 
 /*
-=item i_copy(src)
+=item i_copy(source)
 
 =category Image
 
 
 =category Image
 
-Creates a new image that is a copy of src.
+Creates a new image that is a copy of the image C<source>.
 
 Tags are not copied, only the image data.
 
 
 Tags are not copied, only the image data.
 
@@ -662,10 +465,11 @@ Returns: i_img *
 
 i_img *
 i_copy(i_img *src) {
 
 i_img *
 i_copy(i_img *src) {
-  int y, y1, x1;
+  i_img_dim y, y1, x1;
+  dIMCTXim(src);
   i_img *im = i_sametype(src, src->xsize, src->ysize);
 
   i_img *im = i_sametype(src, src->xsize, src->ysize);
 
-  mm_log((1,"i_copy(src %p)\n", src));
+  im_log((aIMCTX,1,"i_copy(src %p)\n", src));
 
   if (!im)
     return NULL;
 
   if (!im)
     return NULL;
@@ -708,10 +512,11 @@ i_copy(i_img *src) {
   return im;
 }
 
   return im;
 }
 
+/*
 
 
+http://en.wikipedia.org/wiki/Lanczos_resampling
 
 
-
-
+*/
 
 static
 float
 
 static
 float
@@ -737,23 +542,26 @@ wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
 */
 
 i_img*
 */
 
 i_img*
-i_scaleaxis(i_img *im, float Value, int Axis) {
-  int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
-  int LanczosWidthFactor;
-  float *l0, *l1, OldLocation;
-  int T; 
-  float t;
+i_scaleaxis(i_img *im, double Value, int Axis) {
+  i_img_dim hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
+  i_img_dim LanczosWidthFactor;
+  float *l0, *l1;
+  double OldLocation;
+  i_img_dim T; 
+  double t;
   float F, PictureValue[MAXCHANNELS];
   short psave;
   i_color val,val1,val2;
   i_img *new_img;
   float F, PictureValue[MAXCHANNELS];
   short psave;
   i_color val,val1,val2;
   i_img *new_img;
+  int has_alpha = i_img_has_alpha(im);
+  int color_chans = i_img_color_channels(im);
+  dIMCTXim(im);
 
   i_clear_error();
 
   i_clear_error();
-  mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
-
+  im_log((aIMCTX, 1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
 
   if (Axis == XAXIS) {
 
   if (Axis == XAXIS) {
-    hsize = (int)(0.5 + im->xsize * Value);
+    hsize = (i_img_dim)(0.5 + im->xsize * Value);
     if (hsize < 1) {
       hsize = 1;
       Value = 1.0 / im->xsize;
     if (hsize < 1) {
       hsize = 1;
       Value = 1.0 / im->xsize;
@@ -764,7 +572,7 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
     iEnd = vsize;
   } else {
     hsize = im->xsize;
     iEnd = vsize;
   } else {
     hsize = im->xsize;
-    vsize = (int)(0.5 + im->ysize * Value);
+    vsize = (i_img_dim)(0.5 + im->ysize * Value);
 
     if (vsize < 1) {
       vsize = 1;
 
     if (vsize < 1) {
       vsize = 1;
@@ -775,23 +583,23 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
     iEnd = hsize;
   }
   
     iEnd = hsize;
   }
   
-  new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
+  new_img = i_img_8_new(hsize, vsize, im->channels);
   if (!new_img) {
     i_push_error(0, "cannot create output image");
     return NULL;
   }
   
   /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
   if (!new_img) {
     i_push_error(0, "cannot create output image");
     return NULL;
   }
   
   /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
-  LanczosWidthFactor = (Value >= 1) ? 1 : (int) (1.4/Value); 
+  LanczosWidthFactor = (Value >= 1) ? 1 : (i_img_dim) (1.4/Value); 
   lMax = LanczosWidthFactor << 1;
   
   l0 = mymalloc(lMax * sizeof(float));
   l1 = mymalloc(lMax * sizeof(float));
   
   for (j=0; j<jEnd; j++) {
   lMax = LanczosWidthFactor << 1;
   
   l0 = mymalloc(lMax * sizeof(float));
   l1 = mymalloc(lMax * sizeof(float));
   
   for (j=0; j<jEnd; j++) {
-    OldLocation = ((float) j) / Value;
-    T = (int) (OldLocation);
-    F = OldLocation - (float) T;
+    OldLocation = ((double) j) / Value;
+    T = (i_img_dim) (OldLocation);
+    F = OldLocation - T;
     
     for (l = 0; l<lMax; l++) {
       l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
     
     for (l = 0; l<lMax; l++) {
       l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
@@ -804,7 +612,7 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
       t+=l0[l];
       t+=l1[l];
     }
       t+=l0[l];
       t+=l1[l];
     }
-    t /= (float)LanczosWidthFactor;
+    t /= (double)LanczosWidthFactor;
     
     for(l=0; l<lMax; l++) {
       l0[l] /= t;
     
     for(l=0; l<lMax; l++) {
       l0[l] /= t;
@@ -816,22 +624,53 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
       for (i=0; i<iEnd; i++) {
        for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
        for (l=0; l<lMax; l++) {
       for (i=0; i<iEnd; i++) {
        for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
        for (l=0; l<lMax; l++) {
-         int mx = T-lMax+l+1;
-         int Mx = T+l+1;
+         i_img_dim mx = T-lMax+l+1;
+         i_img_dim Mx = T+l+1;
          mx = (mx < 0) ? 0 : mx;
          Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
          
          i_gpix(im, Mx, i, &val1);
          i_gpix(im, mx, i, &val2);
          mx = (mx < 0) ? 0 : mx;
          Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
          
          i_gpix(im, Mx, i, &val1);
          i_gpix(im, mx, i, &val2);
-         
-         for (k=0; k<im->channels; k++) {
-           PictureValue[k] += l1[l]        * val1.channel[k];
-           PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
+
+         if (has_alpha) {
+           i_sample_t alpha1 = val1.channel[color_chans];
+           i_sample_t alpha2 = val2.channel[color_chans];
+           for (k=0; k < color_chans; k++) {
+             PictureValue[k] += l1[l]        * val1.channel[k] * alpha1 / 255;
+             PictureValue[k] += l0[lMax-l-1] * val2.channel[k] * alpha2 / 255;
+           }
+           PictureValue[color_chans] += l1[l] * val1.channel[color_chans];
+           PictureValue[color_chans] += l0[lMax-l-1] * val2.channel[color_chans];
+         }
+         else {
+           for (k=0; k<im->channels; k++) {
+             PictureValue[k] += l1[l]        * val1.channel[k];
+             PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
+           }
          }
        }
          }
        }
-       for(k=0;k<im->channels;k++) {
-         psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
-         val.channel[k]=minmax(0,255,psave);
+
+       if (has_alpha) {
+         float fa = PictureValue[color_chans] / LanczosWidthFactor;
+         int alpha = minmax(0, 255, fa+0.5);
+         if (alpha) {
+           for (k = 0; k < color_chans; ++k) {
+             psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor * 255 / fa));
+             val.channel[k]=minmax(0,255,psave);
+           }
+           val.channel[color_chans] = alpha;
+         }
+         else {
+           /* zero alpha, so the pixel has no color */
+           for (k = 0; k < im->channels; ++k)
+             val.channel[k] = 0;
+         }
+       }
+       else {
+         for(k=0;k<im->channels;k++) {
+           psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
+           val.channel[k]=minmax(0,255,psave);
+         }
        }
        i_ppix(new_img, j, i, &val);
       }
        }
        i_ppix(new_img, j, i, &val);
       }
@@ -841,21 +680,50 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
       for (i=0; i<iEnd; i++) {
        for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
        for (l=0; l < lMax; l++) {
       for (i=0; i<iEnd; i++) {
        for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
        for (l=0; l < lMax; l++) {
-         int mx = T-lMax+l+1;
-         int Mx = T+l+1;
+         i_img_dim mx = T-lMax+l+1;
+         i_img_dim Mx = T+l+1;
          mx = (mx < 0) ? 0 : mx;
          Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
 
          i_gpix(im, i, Mx, &val1);
          i_gpix(im, i, mx, &val2);
          mx = (mx < 0) ? 0 : mx;
          Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
 
          i_gpix(im, i, Mx, &val1);
          i_gpix(im, i, mx, &val2);
-         for (k=0; k<im->channels; k++) {
-           PictureValue[k] += l1[l]        * val1.channel[k];
-           PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; 
+         if (has_alpha) {
+           i_sample_t alpha1 = val1.channel[color_chans];
+           i_sample_t alpha2 = val2.channel[color_chans];
+           for (k=0; k < color_chans; k++) {
+             PictureValue[k] += l1[l]        * val1.channel[k] * alpha1 / 255;
+             PictureValue[k] += l0[lMax-l-1] * val2.channel[k] * alpha2 / 255;
+           }
+           PictureValue[color_chans] += l1[l] * val1.channel[color_chans];
+           PictureValue[color_chans] += l0[lMax-l-1] * val2.channel[color_chans];
+         }
+         else {
+           for (k=0; k<im->channels; k++) {
+             PictureValue[k] += l1[l]        * val1.channel[k];
+             PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
+           }
          }
        }
          }
        }
-       for (k=0; k<im->channels; k++) {
-         psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
-         val.channel[k] = minmax(0, 255, psave);
+       if (has_alpha) {
+         float fa = PictureValue[color_chans] / LanczosWidthFactor;
+         int alpha = minmax(0, 255, fa+0.5);
+         if (alpha) {
+           for (k = 0; k < color_chans; ++k) {
+             psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor * 255 / fa));
+             val.channel[k]=minmax(0,255,psave);
+           }
+           val.channel[color_chans] = alpha;
+         }
+         else {
+           for (k = 0; k < im->channels; ++k)
+             val.channel[k] = 0;
+         }
+       }
+       else {
+         for(k=0;k<im->channels;k++) {
+           psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
+           val.channel[k]=minmax(0,255,psave);
+         }
        }
        i_ppix(new_img, i, j, &val);
       }
        }
        i_ppix(new_img, i, j, &val);
       }
@@ -865,7 +733,7 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
   myfree(l0);
   myfree(l1);
 
   myfree(l0);
   myfree(l1);
 
-  mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
+  im_log((aIMCTX, 1,"(%p) <- i_scaleaxis\n", new_img));
 
   return new_img;
 }
 
   return new_img;
 }
@@ -883,20 +751,21 @@ nothing is gained by doing it in two steps
 
 
 i_img*
 
 
 i_img*
-i_scale_nn(i_img *im, float scx, float scy) {
+i_scale_nn(i_img *im, double scx, double scy) {
 
 
-  int nxsize,nysize,nx,ny;
+  i_img_dim nxsize,nysize,nx,ny;
   i_img *new_img;
   i_color val;
   i_img *new_img;
   i_color val;
+  dIMCTXim(im);
 
 
-  mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
+  im_log((aIMCTX, 1,"i_scale_nn(im %p,scx %.2f,scy %.2f)\n",im,scx,scy));
 
 
-  nxsize = (int) ((float) im->xsize * scx);
+  nxsize = (i_img_dim) ((double) im->xsize * scx);
   if (nxsize < 1) {
     nxsize = 1;
     scx = 1.0 / im->xsize;
   }
   if (nxsize < 1) {
     nxsize = 1;
     scx = 1.0 / im->xsize;
   }
-  nysize = (int) ((float) im->ysize * scy);
+  nysize = (i_img_dim) ((double) im->ysize * scy);
   if (nysize < 1) {
     nysize = 1;
     scy = 1.0 / im->ysize;
   if (nysize < 1) {
     nysize = 1;
     scy = 1.0 / im->ysize;
@@ -906,17 +775,17 @@ i_scale_nn(i_img *im, float scx, float scy) {
   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
   
   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
   
   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
-    i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
+    i_gpix(im,((double)nx)/scx,((double)ny)/scy,&val);
     i_ppix(new_img,nx,ny,&val);
   }
 
     i_ppix(new_img,nx,ny,&val);
   }
 
-  mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
+  im_log((aIMCTX, 1,"(%p) <- i_scale_nn\n",new_img));
 
   return new_img;
 }
 
 /*
 
   return new_img;
 }
 
 /*
-=item i_sametype(i_img *im, int xsize, int ysize)
+=item i_sametype(C<im>, C<xsize>, C<ysize>)
 
 =category Image creation/destruction
 =synopsis i_img *img = i_sametype(src, width, height);
 
 =category Image creation/destruction
 =synopsis i_img *img = i_sametype(src, width, height);
@@ -928,7 +797,10 @@ For paletted images the palette is copied from the source.
 =cut
 */
 
 =cut
 */
 
-i_img *i_sametype(i_img *src, int xsize, int ysize) {
+i_img *
+i_sametype(i_img *src, i_img_dim xsize, i_img_dim ysize) {
+  dIMCTXim(src);
+
   if (src->type == i_direct_type) {
     if (src->bits == 8) {
       return i_img_empty_ch(NULL, xsize, ysize, src->channels);
   if (src->type == i_direct_type) {
     if (src->bits == 8) {
       return i_img_empty_ch(NULL, xsize, ysize, src->channels);
@@ -959,7 +831,7 @@ i_img *i_sametype(i_img *src, int xsize, int ysize) {
 }
 
 /*
 }
 
 /*
-=item i_sametype_chans(i_img *im, int xsize, int ysize, int channels)
+=item i_sametype_chans(C<im>, C<xsize>, C<ysize>, C<channels>)
 
 =category Image creation/destruction
 =synopsis i_img *img = i_sametype_chans(src, width, height, channels);
 
 =category Image creation/destruction
 =synopsis i_img *img = i_sametype_chans(src, width, height, channels);
@@ -971,7 +843,10 @@ For paletted images the equivalent direct type is returned.
 =cut
 */
 
 =cut
 */
 
-i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) {
+i_img *
+i_sametype_chans(i_img *src, i_img_dim xsize, i_img_dim ysize, int channels) {
+  dIMCTXim(src);
+
   if (src->bits == 8) {
     return i_img_empty_ch(NULL, xsize, ysize, channels);
   }
   if (src->bits == 8) {
     return i_img_empty_ch(NULL, xsize, ysize, channels);
   }
@@ -1009,11 +884,12 @@ The operators for this function are defined in L<stackmach.c>.
 i_img*
 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
   double rx,ry;
 i_img*
 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
   double rx,ry;
-  int nxsize,nysize,nx,ny;
+  i_img_dim nxsize,nysize,nx,ny;
   i_img *new_img;
   i_color val;
   i_img *new_img;
   i_color val;
+  dIMCTXim(im);
   
   
-  mm_log((1,"i_transform(im 0x%x, opx 0x%x, opxl %d, opy 0x%x, opyl %d, parm 0x%x, parmlen %d)\n",im,opx,opxl,opy,opyl,parm,parmlen));
+  im_log((aIMCTX, 1,"i_transform(im %p, opx %p, opxl %d, opy %p, opyl %d, parm %p, parmlen %d)\n",im,opx,opxl,opy,opyl,parm,parmlen));
 
   nxsize = im->xsize;
   nysize = im->ysize ;
 
   nxsize = im->xsize;
   nysize = im->ysize ;
@@ -1035,7 +911,7 @@ i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int par
     i_ppix(new_img,nx,ny,&val);
   }
 
     i_ppix(new_img,nx,ny,&val);
   }
 
-  mm_log((1,"(0x%x) <- i_transform\n",new_img));
+  im_log((aIMCTX, 1,"(%p) <- i_transform\n",new_img));
   return new_img;
 }
 
   return new_img;
 }
 
@@ -1054,17 +930,20 @@ can return zero.
 
 float
 i_img_diff(i_img *im1,i_img *im2) {
 
 float
 i_img_diff(i_img *im1,i_img *im2) {
-  int x,y,ch,xb,yb,chb;
+  i_img_dim x, y, xb, yb;
+  int ch, chb;
   float tdiff;
   i_color val1,val2;
   float tdiff;
   i_color val1,val2;
+  dIMCTXim(im1);
 
 
-  mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
+  im_log((aIMCTX, 1,"i_img_diff(im1 %p,im2 %p)\n",im1,im2));
 
   xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
   yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
   chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
 
 
   xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
   yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
   chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
 
-  mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
+  im_log((aIMCTX, 1,"i_img_diff: b=(" i_DFp ") chb=%d\n",
+         i_DFcp(xb,yb), chb));
 
   tdiff=0;
   for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
 
   tdiff=0;
   for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
@@ -1073,7 +952,7 @@ i_img_diff(i_img *im1,i_img *im2) {
 
     for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
   }
 
     for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
   }
-  mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
+  im_log((aIMCTX, 1,"i_img_diff <- (%.2f)\n",tdiff));
   return tdiff;
 }
 
   return tdiff;
 }
 
@@ -1094,17 +973,20 @@ This is like i_img_diff() but looks at floating point samples instead.
 
 double
 i_img_diffd(i_img *im1,i_img *im2) {
 
 double
 i_img_diffd(i_img *im1,i_img *im2) {
-  int x,y,ch,xb,yb,chb;
+  i_img_dim x, y, xb, yb;
+  int ch, chb;
   double tdiff;
   i_fcolor val1,val2;
   double tdiff;
   i_fcolor val1,val2;
+  dIMCTXim(im1);
 
 
-  mm_log((1,"i_img_diffd(im1 0x%x,im2 0x%x)\n",im1,im2));
+  im_log((aIMCTX, 1,"i_img_diffd(im1 %p,im2 %p)\n",im1,im2));
 
   xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
   yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
   chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
 
 
   xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
   yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
   chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
 
-  mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
+  im_log((aIMCTX, 1,"i_img_diffd: b(" i_DFp ") chb=%d\n",
+         i_DFcp(xb, yb), chb));
 
   tdiff=0;
   for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
 
   tdiff=0;
   for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
@@ -1116,21 +998,61 @@ i_img_diffd(i_img *im1,i_img *im2) {
       tdiff += sdiff * sdiff;
     }
   }
       tdiff += sdiff * sdiff;
     }
   }
-  mm_log((1,"i_img_diffd <- (%.2f)\n",tdiff));
+  im_log((aIMCTX, 1,"i_img_diffd <- (%.2f)\n",tdiff));
 
   return tdiff;
 }
 
 
   return tdiff;
 }
 
+int
+i_img_samef(i_img *im1,i_img *im2, double epsilon, char const *what) {
+  i_img_dim x,y,xb,yb;
+  int ch, chb;
+  i_fcolor val1,val2;
+  dIMCTXim(im1);
+
+  if (what == NULL)
+    what = "(null)";
+
+  im_log((aIMCTX,1,"i_img_samef(im1 %p,im2 %p, epsilon %g, what '%s')\n", im1, im2, epsilon, what));
+
+  xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
+  yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
+  chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
+
+  im_log((aIMCTX, 1,"i_img_samef: b(" i_DFp ") chb=%d\n",
+         i_DFcp(xb, yb), chb));
+
+  for(y = 0; y < yb; y++) {
+    for(x = 0; x < xb; x++) {
+      i_gpixf(im1, x, y, &val1);
+      i_gpixf(im2, x, y, &val2);
+      
+      for(ch = 0; ch < chb; ch++) {
+       double sdiff = val1.channel[ch] - val2.channel[ch];
+       if (fabs(sdiff) > epsilon) {
+         im_log((aIMCTX, 1,"i_img_samef <- different %g @(" i_DFp ")\n",
+                 sdiff, i_DFcp(x, y)));
+         return 0;
+       }
+      }
+    }
+  }
+  im_log((aIMCTX, 1,"i_img_samef <- same\n"));
+
+  return 1;
+}
+
 /* just a tiny demo of haar wavelets */
 
 i_img*
 i_haar(i_img *im) {
 /* just a tiny demo of haar wavelets */
 
 i_img*
 i_haar(i_img *im) {
-  int mx,my;
-  int fx,fy;
-  int x,y;
-  int ch,c;
+  i_img_dim mx,my;
+  i_img_dim fx,fy;
+  i_img_dim x,y;
+  int ch;
   i_img *new_img,*new_img2;
   i_color val1,val2,dval1,dval2;
   i_img *new_img,*new_img2;
   i_color val1,val2,dval1,dval2;
+  dIMCTXim(im);
   
   mx=im->xsize;
   my=im->ysize;
   
   mx=im->xsize;
   my=im->ysize;
@@ -1143,7 +1065,6 @@ i_haar(i_img *im) {
   new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
   new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
 
   new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
   new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
 
-  c=0; 
   for(y=0;y<my;y++) for(x=0;x<fx;x++) {
     i_gpix(im,x*2,y,&val1);
     i_gpix(im,x*2+1,y,&val2);
   for(y=0;y<my;y++) for(x=0;x<fx;x++) {
     i_gpix(im,x*2,y,&val1);
     i_gpix(im,x*2+1,y,&val2);
@@ -1183,13 +1104,13 @@ to indicate that it was more than max colors
 int
 i_count_colors(i_img *im,int maxc) {
   struct octt *ct;
 int
 i_count_colors(i_img *im,int maxc) {
   struct octt *ct;
-  int x,y;
+  i_img_dim x,y;
   int colorcnt;
   int channels[3];
   int *samp_chans;
   i_sample_t * samp;
   int colorcnt;
   int channels[3];
   int *samp_chans;
   i_sample_t * samp;
-  int xsize = im->xsize; 
-  int ysize = im->ysize;
+  i_img_dim xsize = im->xsize; 
+  i_img_dim ysize = im->ysize;
   int samp_cnt = 3 * xsize;
 
   if (im->channels >= 3) {
   int samp_cnt = 3 * xsize;
 
   if (im->channels >= 3) {
@@ -1272,15 +1193,15 @@ hpsort(unsigned int n, unsigned *ra) {
 int
 i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
   struct octt *ct;
 int
 i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
   struct octt *ct;
-  int x,y;
+  i_img_dim x,y;
   int colorcnt;
   unsigned int *col_usage_it;
   i_sample_t * samp;
   int channels[3];
   int *samp_chans;
   
   int colorcnt;
   unsigned int *col_usage_it;
   i_sample_t * samp;
   int channels[3];
   int *samp_chans;
   
-  int xsize = im->xsize; 
-  int ysize = im->ysize;
+  i_img_dim xsize = im->xsize; 
+  i_img_dim ysize = im->ysize;
   int samp_cnt = 3 * xsize;
   ct = octt_new();
   
   int samp_cnt = 3 * xsize;
   ct = octt_new();
   
@@ -1318,388 +1239,6 @@ i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
 /*
 =back
 
 /*
 =back
 
-=head2 8-bit per sample image internal functions
-
-These are the functions installed in an 8-bit per sample image.
-
-=over
-
-=item i_ppix_d(im, x, y, col)
-
-Internal function.
-
-This is the function kept in the i_f_ppix member of an i_img object.
-It does a normal store of a pixel into the image with range checking.
-
-Returns 0 if the pixel could be set, -1 otherwise.
-
-=cut
-*/
-static
-int
-i_ppix_d(i_img *im, int x, int y, const i_color *val) {
-  int ch;
-  
-  if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
-    for(ch=0;ch<im->channels;ch++)
-      if (im->ch_mask&(1<<ch)) 
-       im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
-    return 0;
-  }
-  return -1; /* error was clipped */
-}
-
-/*
-=item i_gpix_d(im, x, y, &col)
-
-Internal function.
-
-This is the function kept in the i_f_gpix member of an i_img object.
-It does normal retrieval of a pixel from the image with range checking.
-
-Returns 0 if the pixel could be set, -1 otherwise.
-
-=cut
-*/
-static
-int 
-i_gpix_d(i_img *im, int x, int y, i_color *val) {
-  int ch;
-  if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
-    for(ch=0;ch<im->channels;ch++) 
-      val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
-    return 0;
-  }
-  for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
-  return -1; /* error was cliped */
-}
-
-/*
-=item i_glin_d(im, l, r, y, vals)
-
-Reads a line of data from the image, storing the pixels at vals.
-
-The line runs from (l,y) inclusive to (r,y) non-inclusive
-
-vals should point at space for (r-l) pixels.
-
-l should never be less than zero (to avoid confusion about where to
-put the pixels in vals).
-
-Returns the number of pixels copied (eg. if r, l or y is out of range)
-
-=cut
-*/
-static
-int
-i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
-  int ch, count, i;
-  unsigned char *data;
-  if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
-    if (r > im->xsize)
-      r = im->xsize;
-    data = im->idata + (l+y*im->xsize) * im->channels;
-    count = r - l;
-    for (i = 0; i < count; ++i) {
-      for (ch = 0; ch < im->channels; ++ch)
-       vals[i].channel[ch] = *data++;
-    }
-    return count;
-  }
-  else {
-    return 0;
-  }
-}
-
-/*
-=item i_plin_d(im, l, r, y, vals)
-
-Writes a line of data into the image, using the pixels at vals.
-
-The line runs from (l,y) inclusive to (r,y) non-inclusive
-
-vals should point at (r-l) pixels.
-
-l should never be less than zero (to avoid confusion about where to
-get the pixels in vals).
-
-Returns the number of pixels copied (eg. if r, l or y is out of range)
-
-=cut
-*/
-static
-int
-i_plin_d(i_img *im, int l, int r, int y, const i_color *vals) {
-  int ch, count, i;
-  unsigned char *data;
-  if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
-    if (r > im->xsize)
-      r = im->xsize;
-    data = im->idata + (l+y*im->xsize) * im->channels;
-    count = r - l;
-    for (i = 0; i < count; ++i) {
-      for (ch = 0; ch < im->channels; ++ch) {
-       if (im->ch_mask & (1 << ch)) 
-         *data = vals[i].channel[ch];
-       ++data;
-      }
-    }
-    return count;
-  }
-  else {
-    return 0;
-  }
-}
-
-/*
-=item i_ppixf_d(im, x, y, val)
-
-=cut
-*/
-static
-int
-i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val) {
-  int ch;
-  
-  if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
-    for(ch=0;ch<im->channels;ch++)
-      if (im->ch_mask&(1<<ch)) {
-       im->idata[(x+y*im->xsize)*im->channels+ch] = 
-          SampleFTo8(val->channel[ch]);
-      }
-    return 0;
-  }
-  return -1; /* error was clipped */
-}
-
-/*
-=item i_gpixf_d(im, x, y, val)
-
-=cut
-*/
-static
-int
-i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
-  int ch;
-  if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
-    for(ch=0;ch<im->channels;ch++) {
-      val->channel[ch] = 
-        Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
-    }
-    return 0;
-  }
-  return -1; /* error was cliped */
-}
-
-/*
-=item i_glinf_d(im, l, r, y, vals)
-
-Reads a line of data from the image, storing the pixels at vals.
-
-The line runs from (l,y) inclusive to (r,y) non-inclusive
-
-vals should point at space for (r-l) pixels.
-
-l should never be less than zero (to avoid confusion about where to
-put the pixels in vals).
-
-Returns the number of pixels copied (eg. if r, l or y is out of range)
-
-=cut
-*/
-static
-int
-i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
-  int ch, count, i;
-  unsigned char *data;
-  if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
-    if (r > im->xsize)
-      r = im->xsize;
-    data = im->idata + (l+y*im->xsize) * im->channels;
-    count = r - l;
-    for (i = 0; i < count; ++i) {
-      for (ch = 0; ch < im->channels; ++ch)
-       vals[i].channel[ch] = Sample8ToF(*data++);
-    }
-    return count;
-  }
-  else {
-    return 0;
-  }
-}
-
-/*
-=item i_plinf_d(im, l, r, y, vals)
-
-Writes a line of data into the image, using the pixels at vals.
-
-The line runs from (l,y) inclusive to (r,y) non-inclusive
-
-vals should point at (r-l) pixels.
-
-l should never be less than zero (to avoid confusion about where to
-get the pixels in vals).
-
-Returns the number of pixels copied (eg. if r, l or y is out of range)
-
-=cut
-*/
-static
-int
-i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals) {
-  int ch, count, i;
-  unsigned char *data;
-  if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
-    if (r > im->xsize)
-      r = im->xsize;
-    data = im->idata + (l+y*im->xsize) * im->channels;
-    count = r - l;
-    for (i = 0; i < count; ++i) {
-      for (ch = 0; ch < im->channels; ++ch) {
-       if (im->ch_mask & (1 << ch)) 
-         *data = SampleFTo8(vals[i].channel[ch]);
-       ++data;
-      }
-    }
-    return count;
-  }
-  else {
-    return 0;
-  }
-}
-
-/*
-=item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
-
-Reads sample values from im for the horizontal line (l, y) to (r-1,y)
-for the channels specified by chans, an array of int with chan_count
-elements.
-
-Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
-
-=cut
-*/
-static
-int
-i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, 
-              const int *chans, int chan_count) {
-  int ch, count, i, w;
-  unsigned char *data;
-
-  if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
-    if (r > im->xsize)
-      r = im->xsize;
-    data = im->idata + (l+y*im->xsize) * im->channels;
-    w = r - l;
-    count = 0;
-
-    if (chans) {
-      /* make sure we have good channel numbers */
-      for (ch = 0; ch < chan_count; ++ch) {
-        if (chans[ch] < 0 || chans[ch] >= im->channels) {
-          i_push_errorf(0, "No channel %d in this image", chans[ch]);
-          return 0;
-        }
-      }
-      for (i = 0; i < w; ++i) {
-        for (ch = 0; ch < chan_count; ++ch) {
-          *samps++ = data[chans[ch]];
-          ++count;
-        }
-        data += im->channels;
-      }
-    }
-    else {
-      if (chan_count <= 0 || chan_count > im->channels) {
-       i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
-                     chan_count);
-       return 0;
-      }
-      for (i = 0; i < w; ++i) {
-        for (ch = 0; ch < chan_count; ++ch) {
-          *samps++ = data[ch];
-          ++count;
-        }
-        data += im->channels;
-      }
-    }
-
-    return count;
-  }
-  else {
-    return 0;
-  }
-}
-
-/*
-=item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
-
-Reads sample values from im for the horizontal line (l, y) to (r-1,y)
-for the channels specified by chan_mask, where bit 0 is the first
-channel.
-
-Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
-
-=cut
-*/
-static
-int
-i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, 
-           const int *chans, int chan_count) {
-  int ch, count, i, w;
-  unsigned char *data;
-  for (ch = 0; ch < chan_count; ++ch) {
-    if (chans[ch] < 0 || chans[ch] >= im->channels) {
-      i_push_errorf(0, "No channel %d in this image", chans[ch]);
-    }
-  }
-  if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
-    if (r > im->xsize)
-      r = im->xsize;
-    data = im->idata + (l+y*im->xsize) * im->channels;
-    w = r - l;
-    count = 0;
-
-    if (chans) {
-      /* make sure we have good channel numbers */
-      for (ch = 0; ch < chan_count; ++ch) {
-        if (chans[ch] < 0 || chans[ch] >= im->channels) {
-          i_push_errorf(0, "No channel %d in this image", chans[ch]);
-          return 0;
-        }
-      }
-      for (i = 0; i < w; ++i) {
-        for (ch = 0; ch < chan_count; ++ch) {
-          *samps++ = Sample8ToF(data[chans[ch]]);
-          ++count;
-        }
-        data += im->channels;
-      }
-    }
-    else {
-      if (chan_count <= 0 || chan_count > im->channels) {
-       i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
-                     chan_count);
-       return 0;
-      }
-      for (i = 0; i < w; ++i) {
-        for (ch = 0; ch < chan_count; ++ch) {
-          *samps++ = Sample8ToF(data[ch]);
-          ++count;
-        }
-        data += im->channels;
-      }
-    }
-    return count;
-  }
-  else {
-    return 0;
-  }
-}
-
-/*
-=back
-
 =head2 Image method wrappers
 
 These functions provide i_fsample_t functions in terms of their
 =head2 Image method wrappers
 
 These functions provide i_fsample_t functions in terms of their
@@ -1707,12 +1246,12 @@ i_sample_t versions.
 
 =over
 
 
 =over
 
-=item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
+=item i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix)
 
 =cut
 */
 
 
 =cut
 */
 
-int i_ppixf_fp(i_img *im, int x, int y, const i_fcolor *pix) {
+int i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix) {
   i_color temp;
   int ch;
 
   i_color temp;
   int ch;
 
@@ -1723,15 +1262,15 @@ int i_ppixf_fp(i_img *im, int x, int y, const i_fcolor *pix) {
 }
 
 /*
 }
 
 /*
-=item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
+=item i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix)
 
 =cut
 */
 
 =cut
 */
-int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
+int i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) {
   i_color temp;
   int ch;
 
   i_color temp;
   int ch;
 
-  if (i_gpix(im, x, y, &temp)) {
+  if (i_gpix(im, x, y, &temp) == 0) {
     for (ch = 0; ch < im->channels; ++ch)
       pix->channel[ch] = Sample8ToF(temp.channel[ch]);
     return 0;
     for (ch = 0; ch < im->channels; ++ch)
       pix->channel[ch] = Sample8ToF(temp.channel[ch]);
     return 0;
@@ -1741,19 +1280,21 @@ int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
 }
 
 /*
 }
 
 /*
-=item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
+=item i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix)
 
 =cut
 */
 
 =cut
 */
-int i_plinf_fp(i_img *im, int l, int r, int y, const i_fcolor *pix) {
+i_img_dim
+i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *pix) {
   i_color *work;
 
   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
     if (r > im->xsize)
       r = im->xsize;
     if (r > l) {
   i_color *work;
 
   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
     if (r > im->xsize)
       r = im->xsize;
     if (r > l) {
-      int ret;
-      int i, ch;
+      i_img_dim ret;
+      i_img_dim i;
+      int ch;
       work = mymalloc(sizeof(i_color) * (r-l));
       for (i = 0; i < r-l; ++i) {
         for (ch = 0; ch < im->channels; ++ch) 
       work = mymalloc(sizeof(i_color) * (r-l));
       for (i = 0; i < r-l; ++i) {
         for (ch = 0; ch < im->channels; ++ch) 
@@ -1774,19 +1315,21 @@ int i_plinf_fp(i_img *im, int l, int r, int y, const i_fcolor *pix) {
 }
 
 /*
 }
 
 /*
-=item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
+=item i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix)
 
 =cut
 */
 
 =cut
 */
-int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
+i_img_dim
+i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix) {
   i_color *work;
 
   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
     if (r > im->xsize)
       r = im->xsize;
     if (r > l) {
   i_color *work;
 
   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
     if (r > im->xsize)
       r = im->xsize;
     if (r > l) {
-      int ret;
-      int i, ch;
+      i_img_dim ret;
+      i_img_dim i;
+      int ch;
       work = mymalloc(sizeof(i_color) * (r-l));
       ret = i_plin(im, l, r, y, work);
       for (i = 0; i < r-l; ++i) {
       work = mymalloc(sizeof(i_color) * (r-l));
       ret = i_plin(im, l, r, y, work);
       for (i = 0; i < r-l; ++i) {
@@ -1807,11 +1350,13 @@ int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
 }
 
 /*
 }
 
 /*
-=item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
+=item i_gsampf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, int *chans, int chan_count)
 
 =cut
 */
 
 =cut
 */
-int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, 
+
+i_img_dim
+i_gsampf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, 
                 int const *chans, int chan_count) {
   i_sample_t *work;
 
                 int const *chans, int chan_count) {
   i_sample_t *work;
 
@@ -1819,8 +1364,8 @@ int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
     if (r > im->xsize)
       r = im->xsize;
     if (r > l) {
     if (r > im->xsize)
       r = im->xsize;
     if (r > l) {
-      int ret;
-      int i;
+      i_img_dim ret;
+      i_img_dim i;
       work = mymalloc(sizeof(i_sample_t) * (r-l));
       ret = i_gsamp(im, l, r, y, work, chans, chan_count);
       for (i = 0; i < ret; ++i) {
       work = mymalloc(sizeof(i_sample_t) * (r-l));
       ret = i_gsamp(im, l, r, y, work, chans, chan_count);
       for (i = 0; i < ret; ++i) {
@@ -1915,9 +1460,11 @@ int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
 =cut
 */
 
 =cut
 */
 
-int 
-i_gsamp_bits_fb(i_img *im, int l, int r, int y, unsigned *samps, 
+i_img_dim
+i_gsamp_bits_fb(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps, 
                const int *chans, int chan_count, int bits) {
                const int *chans, int chan_count, int bits) {
+  dIMCTXim(im);
+
   if (bits < 1 || bits > 32) {
     i_push_error(0, "Invalid bits, must be 1..32");
     return -1;
   if (bits < 1 || bits > 32) {
     i_push_error(0, "Invalid bits, must be 1..32");
     return -1;
@@ -1925,7 +1472,8 @@ i_gsamp_bits_fb(i_img *im, int l, int r, int y, unsigned *samps,
 
   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
     double scale;
 
   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
     double scale;
-    int ch, count, i, w;
+    int ch;
+    i_img_dim count, i, w;
     
     if (bits == 32)
       scale = 4294967295.0;
     
     if (bits == 32)
       scale = 4294967295.0;
@@ -1941,7 +1489,7 @@ i_gsamp_bits_fb(i_img *im, int l, int r, int y, unsigned *samps,
       /* make sure we have good channel numbers */
       for (ch = 0; ch < chan_count; ++ch) {
         if (chans[ch] < 0 || chans[ch] >= im->channels) {
       /* make sure we have good channel numbers */
       for (ch = 0; ch < chan_count; ++ch) {
         if (chans[ch] < 0 || chans[ch] >= im->channels) {
-          i_push_errorf(0, "No channel %d in this image", chans[ch]);
+          im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
           return -1;
         }
       }
           return -1;
         }
       }
@@ -1977,194 +1525,6 @@ i_gsamp_bits_fb(i_img *im, int l, int r, int y, unsigned *samps,
   }
 }
 
   }
 }
 
-/*
-=back
-
-=head2 Stream reading and writing wrapper functions
-
-=over
-
-=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
-
-Performs general read buffering for file readers that permit reading
-to be done through a callback.
-
-The final callback gets two parameters, a I<need> value, and a I<want>
-value, where I<need> is the amount of data that the file library needs
-to read, and I<want> is the amount of space available in the buffer
-maintained by these functions.
-
-This means if you need to read from a stream that you don't know the
-length of, you can return I<need> bytes, taking the performance hit of
-possibly expensive callbacks (eg. back to perl code), or if you are
-reading from a stream where it doesn't matter if some data is lost, or
-if the total length of the stream is known, you can return I<want>
-bytes.
-
-=cut 
-*/
-
-int
-i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
-  int total;
-
-  if (length < gci->length - gci->cpos) {
-    /* simplest case */
-    memcpy(buf, gci->buffer+gci->cpos, length);
-    gci->cpos += length;
-    return length;
-  }
-  
-  total = 0;
-  memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
-  total  += gci->length - gci->cpos;
-  length -= gci->length - gci->cpos;
-  buf    += gci->length - gci->cpos;
-  if (length < (int)sizeof(gci->buffer)) {
-    int did_read;
-    int copy_size;
-    while (length
-          && (did_read = (gci->cb)(gci->userdata, gci->buffer, length, 
-                                   sizeof(gci->buffer))) > 0) {
-      gci->cpos = 0;
-      gci->length = did_read;
-
-      copy_size = i_min(length, gci->length);
-      memcpy(buf, gci->buffer, copy_size);
-      gci->cpos += copy_size;
-      buf += copy_size;
-      total += copy_size;
-      length -= copy_size;
-    }
-  }
-  else {
-    /* just read the rest - too big for our buffer*/
-    int did_read;
-    while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
-      length -= did_read;
-      total += did_read;
-      buf += did_read;
-    }
-  }
-  return total;
-}
-
-/*
-=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
-
-For use by callback file readers to initialize the reader buffer.
-
-Allocates, initializes and returns the reader buffer.
-
-See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
-
-=cut
-*/
-i_gen_read_data *
-i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
-  i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
-  self->cb = cb;
-  self->userdata = userdata;
-  self->length = 0;
-  self->cpos = 0;
-
-  return self;
-}
-
-/*
-=item i_free_gen_read_data(i_gen_read_data *)
-
-Cleans up.
-
-=cut
-*/
-void i_free_gen_read_data(i_gen_read_data *self) {
-  myfree(self);
-}
-
-/*
-=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
-
-Performs write buffering for a callback based file writer.
-
-Failures are considered fatal, if a write fails then data will be
-dropped.
-
-=cut
-*/
-int 
-i_gen_writer(
-i_gen_write_data *self, 
-char const *data, 
-int size)
-{
-  if (self->filledto && self->filledto+size > self->maxlength) {
-    if (self->cb(self->userdata, self->buffer, self->filledto)) {
-      self->filledto = 0;
-    }
-    else {
-      self->filledto = 0;
-      return 0;
-    }
-  }
-  if (self->filledto+size <= self->maxlength) {
-    /* just save it */
-    memcpy(self->buffer+self->filledto, data, size);
-    self->filledto += size;
-    return 1;
-  }
-  /* doesn't fit - hand it off */
-  return self->cb(self->userdata, data, size);
-}
-
-/*
-=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
-
-Allocates and initializes the data structure used by i_gen_writer.
-
-This should be released with L<image.c/i_free_gen_write_data>
-
-=cut
-*/
-i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb, 
-                                      char *userdata, int max_length)
-{
-  i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
-  self->cb = cb;
-  self->userdata = userdata;
-  self->maxlength = i_min(max_length, sizeof(self->buffer));
-  if (self->maxlength < 0)
-    self->maxlength = sizeof(self->buffer);
-  self->filledto = 0;
-
-  return self;
-}
-
-/*
-=item i_free_gen_write_data(i_gen_write_data *info, int flush)
-
-Cleans up the write buffer.
-
-Will flush any left-over data if I<flush> is non-zero.
-
-Returns non-zero if flush is zero or if info->cb() returns non-zero.
-
-Return zero only if flush is non-zero and info->cb() returns zero.
-ie. if it fails.
-
-=cut
-*/
-
-int i_free_gen_write_data(i_gen_write_data *info, int flush)
-{
-  int result = !flush || 
-    info->filledto == 0 ||
-    info->cb(info->userdata, info->buffer, info->filledto);
-  myfree(info);
-
-  return result;
-}
-
 struct magic_entry {
   unsigned char *magic;
   size_t magic_size;
 struct magic_entry {
   unsigned char *magic;
   size_t magic_size;
@@ -2267,6 +1627,14 @@ i_test_format_probe(io_glue *data, int length) {
 
     /* bzip2 compressed */
     FORMAT_ENTRY("BZh", "bzip2"),
 
     /* bzip2 compressed */
     FORMAT_ENTRY("BZh", "bzip2"),
+
+    /* WEBP
+       http://code.google.com/speed/webp/docs/riff_container.html */
+    FORMAT_ENTRY2("RIFF    WEBP", "webp", "xxxx    xxxx"),
+
+    /* JPEG 2000 
+       This might match a little loosely */
+    FORMAT_ENTRY("\x00\x00\x00\x0CjP  \x0D\x0A\x87\x0A", "jp2"),
   };
   static const struct magic_entry more_formats[] = {
     /* these were originally both listed as ico, but cur files can
   };
   static const struct magic_entry more_formats[] = {
     /* these were originally both listed as ico, but cur files can
@@ -2281,10 +1649,17 @@ i_test_format_probe(io_glue *data, int length) {
   unsigned char head[18];
   ssize_t rc;
 
   unsigned char head[18];
   ssize_t rc;
 
-  io_glue_commit_types(data);
-  rc = data->readcb(data, head, 18);
+  rc = i_io_peekn(data, head, 18);
   if (rc == -1) return NULL;
   if (rc == -1) return NULL;
-  data->seekcb(data, -rc, SEEK_CUR);
+#if 0
+  {
+    int i;
+    fprintf(stderr, "%d bytes -", (int)rc);
+    for (i = 0; i < rc; ++i)
+      fprintf(stderr, " %02x", head[i]);
+    fprintf(stderr, "\n");
+  }
+#endif
 
   for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) { 
     struct magic_entry const *entry = formats + i;
 
   for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) { 
     struct magic_entry const *entry = formats + i;
@@ -2310,10 +1685,13 @@ i_test_format_probe(io_glue *data, int length) {
 /*
 =item i_img_is_monochrome(img, &zero_is_white)
 
 /*
 =item i_img_is_monochrome(img, &zero_is_white)
 
+=category Image Information
+
 Tests an image to check it meets our monochrome tests.
 
 The idea is that a file writer can use this to test where it should
 Tests an image to check it meets our monochrome tests.
 
 The idea is that a file writer can use this to test where it should
-write the image in whatever bi-level format it uses, eg. pbm for pnm.
+write the image in whatever bi-level format it uses, eg. C<pbm> for
+C<pnm>.
 
 For performance of encoders we require monochrome images:
 
 
 For performance of encoders we require monochrome images:
 
@@ -2325,12 +1703,12 @@ be paletted
 
 =item *
 
 
 =item *
 
-have a palette of two colors, containing only (0,0,0) and
-(255,255,255) in either order.
+have a palette of two colors, containing only C<(0,0,0)> and
+C<(255,255,255)> in either order.
 
 =back
 
 
 =back
 
-zero_is_white is set to non-zero iff the first palette entry is white.
+C<zero_is_white> is set to non-zero if the first palette entry is white.
 
 =cut
 */
 
 =cut
 */
@@ -2382,45 +1760,57 @@ i_img_is_monochrome(i_img *im, int *zero_is_white) {
 /*
 =item i_get_file_background(im, &bg)
 
 /*
 =item i_get_file_background(im, &bg)
 
+=category Files
+
 Retrieve the file write background color tag from the image.
 
 Retrieve the file write background color tag from the image.
 
-If not present, returns black.
+If not present, C<bg> is set to black.
+
+Returns 1 if the C<i_background> tag was found and valid.
 
 =cut
 */
 
 
 =cut
 */
 
-void
+int
 i_get_file_background(i_img *im, i_color *bg) {
 i_get_file_background(i_img *im, i_color *bg) {
-  if (!i_tags_get_color(&im->tags, "i_background", 0, bg)) {
+  int result = i_tags_get_color(&im->tags, "i_background", 0, bg);
+  if (!result) {
     /* black default */
     bg->channel[0] = bg->channel[1] = bg->channel[2] = 0;
   }
   /* always full alpha */
   bg->channel[3] = 255;
     /* black default */
     bg->channel[0] = bg->channel[1] = bg->channel[2] = 0;
   }
   /* always full alpha */
   bg->channel[3] = 255;
+
+  return result;
 }
 
 /*
 =item i_get_file_backgroundf(im, &bg)
 
 }
 
 /*
 =item i_get_file_backgroundf(im, &bg)
 
+=category Files
+
 Retrieve the file write background color tag from the image as a
 floating point color.
 
 Implemented in terms of i_get_file_background().
 
 Retrieve the file write background color tag from the image as a
 floating point color.
 
 Implemented in terms of i_get_file_background().
 
-If not present, returns black.
+If not present, C<bg> is set to black.
+
+Returns 1 if the C<i_background> tag was found and valid.
 
 =cut
 */
 
 
 =cut
 */
 
-void
+int
 i_get_file_backgroundf(i_img *im, i_fcolor *fbg) {
   i_color bg;
 i_get_file_backgroundf(i_img *im, i_fcolor *fbg) {
   i_color bg;
-
-  i_get_file_background(im, &bg);
+  int result = i_get_file_background(im, &bg);
   fbg->rgba.r = Sample8ToF(bg.rgba.r);
   fbg->rgba.g = Sample8ToF(bg.rgba.g);
   fbg->rgba.b = Sample8ToF(bg.rgba.b);
   fbg->rgba.a = 1.0;
   fbg->rgba.r = Sample8ToF(bg.rgba.r);
   fbg->rgba.g = Sample8ToF(bg.rgba.g);
   fbg->rgba.b = Sample8ToF(bg.rgba.b);
   fbg->rgba.a = 1.0;
+
+  return result;
 }
 
 /*
 }
 
 /*
@@ -2430,7 +1820,7 @@ i_get_file_backgroundf(i_img *im, i_fcolor *fbg) {
 
 Arnar M. Hrafnkelsson <addi@umich.edu>
 
 
 Arnar M. Hrafnkelsson <addi@umich.edu>
 
-Tony Cook <tony@develop-help.com>
+Tony Cook <tonyc@cpan.org>
 
 =head1 SEE ALSO
 
 
 =head1 SEE ALSO