]> git.imager.perl.org - imager.git/blobdiff - image.c
avoid dead code in i_t1_glyph_names().
[imager.git] / image.c
diff --git a/image.c b/image.c
index abf867682e46ec6156674f1e99b13c166b22f048..cdfa2ed4aaa1a5575b239be374c7d667d4d84dee 100644 (file)
--- a/image.c
+++ b/image.c
@@ -1,3 +1,5 @@
+#define IMAGER_NO_CONTEXT
+
 #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 = i_img_new();
+  i = i_img_8_new();
   i_img_destroy(i);
   // and much more
 
@@ -30,6 +32,8 @@ Some of these functions are internal.
 =cut
 */
 
+im_context_t (*im_get_context)(void) = NULL;
+
 #define XAXIS 0
 #define YAXIS 1
 #define XYAXIS 2
@@ -40,8 +44,11 @@ Some of these functions are internal.
 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
+=synopsis i_img *im = im_img_alloc(aIMCTX);
+=synopsis i_img *im = i_img_alloc();
 
 Allocates a new i_img structure.
 
@@ -70,25 +77,29 @@ object.
 */
 
 i_img *
-i_img_alloc(void) {
+im_img_alloc(pIMCTX) {
   return mymalloc(sizeof(i_img));
 }
 
 /*
-=item i_img_init(C<img>)
+=item im_img_init(aIMCTX, image)
+X<im_img_init API>X<i_img_init API>
 =category Image Implementation
+=synopsis im_img_init(aIMCTX, im);
+=synopsis i_img_init(im);
 
 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
-i_img_init(i_img *img) {
+im_img_init(pIMCTX, i_img *img) {
   img->im_data = NULL;
+  img->context = aIMCTX;
+  im_context_refinc(aIMCTX, "img_init");
 }
 
 /* 
@@ -107,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;
+  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;
-  mm_log((1,"(%p) <- ICL_new_internal\n",cl));
+  im_log((aIMCTX,1,"(%p) <- ICL_new_internal\n",cl));
   return cl;
 }
 
@@ -136,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) {
-  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)
-      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;
-  mm_log((1,"(%p) <- ICL_set_internal\n",cl));
+  im_log((aIMCTX,1,"(%p) <- ICL_set_internal\n",cl));
   return cl;
 }
 
@@ -182,8 +195,9 @@ Dump color information to log - strictly for debugging.
 
 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));
 }
 
 /* 
@@ -198,7 +212,8 @@ Destroy ancillary data for Color object.
 
 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);
 }
 
@@ -209,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;
+  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;
-  mm_log((1,"(%p) <- i_fcolor_new\n",cl));
+  im_log((aIMCTX, 1,"(%p) <- i_fcolor_new\n",cl));
 
   return cl;
 }
@@ -243,7 +259,8 @@ Free image data.
 
 void
 i_img_exorcise(i_img *im) {
-  mm_log((1,"i_img_exorcise(im* %p)\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);
@@ -269,9 +286,11 @@ Destroy an image object
 
 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); }
+  im_context_refdec(aIMCTX, "img_destroy");
 }
 
 /* 
@@ -297,12 +316,13 @@ info is an array of 4 integers with the following values:
 
 void
 i_img_info(i_img *im, i_img_dim *info) {
-  mm_log((1,"i_img_info(im %p)\n",im));
+  dIMCTXim(im);
+  im_log((aIMCTX,1,"i_img_info(im %p)\n",im));
   if (im != NULL) {
-    mm_log((1,"i_img_info: xsize=%" i_DF " ysize=%" i_DF " channels=%d "
+    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));
-    mm_log((1,"i_img_info: idata=%p\n",im->idata));
+    im_log((aIMCTX,1,"i_img_info: idata=%p\n",im->idata));
     info[0] = im->xsize;
     info[1] = im->ysize;
     info[2] = im->channels;
@@ -318,7 +338,7 @@ i_img_info(i_img *im, i_img_dim *info) {
 /*
 =item i_img_setmask(C<im>, C<ch_mask>)
 =category Image Information
-=synopsis // only channel 0 writeable 
+=synopsis // only channel 0 writable 
 =synopsis i_img_setmask(img, 0x01);
 
 Set the image channel mask for C<im> to C<ch_mask>.
@@ -384,6 +404,85 @@ i_img_get_height(i_img *im) {
   return im->ysize;
 }
 
+/*
+=item i_img_color_model(im)
+=category Image Information
+=synopsis i_color_model_t cm = i_img_color_model(im);
+
+Returns the color model for the image.
+
+A future version of Imager will allow for images with extra channels
+beyond gray/rgb and alpha.
+
+=cut
+*/
+i_color_model_t
+i_img_color_model(i_img *im) {
+  return (i_color_model_t)im->channels;
+}
+
+/*
+=item i_img_alpha_channel(im, &channel)
+=category Image Information
+=synopsis int alpha_channel;
+=synopsis int has_alpha = i_img_alpha_channel(im, &alpha_channel);
+
+Work out the alpha channel for an image.
+
+If the image has an alpha channel, sets C<*channel> to the alpha
+channel index and returns non-zero.
+
+If the image has no alpha channel, returns zero and C<*channel> is not
+modified.
+
+C<channel> may be C<NULL>.
+
+=cut
+*/
+
+int
+i_img_alpha_channel(i_img *im, int *channel) {
+  i_color_model_t model = i_img_color_model(im);
+  switch (model) {
+  case icm_gray_alpha:
+  case icm_rgb_alpha:
+    if (channel) *channel = (int)model - 1;
+    return 1;
+
+  default:
+    return 0;
+  }
+}
+
+/*
+=item i_img_color_channels(im)
+=category Image Information
+=synopsis int color_channels = i_img_color_channels(im);
+
+Returns the number of color channels in the image.  For now this is
+always 1 (for grayscale) or 3 (for RGB) but may be 0 in some special
+cases in a future release of Imager.
+
+=cut
+*/
+
+int
+i_img_color_channels(i_img *im) {
+  i_color_model_t model = i_img_color_model(im);
+  switch (model) {
+  case icm_gray_alpha:
+  case icm_rgb_alpha:
+    return (int)model - 1;
+
+  case icm_gray:
+  case icm_rgb:
+    return (int)model;
+
+  default:
+    return 0;
+  }
+}
+
 /*
 =item i_copyto_trans(C<im>, C<src>, C<x1>, C<y1>, C<x2>, C<y2>, C<tx>, C<ty>, C<trans>)
 
@@ -401,8 +500,9 @@ i_copyto_trans(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img
   i_color pv;
   i_img_dim x,y,t,ttx,tty,tt;
   int ch;
+  dIMCTXim(im);
 
-  mm_log((1,"i_copyto_trans(im* %p,src %p, p1(" i_DFp "), p2(" i_DFp "), "
+  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));
   
@@ -445,9 +545,10 @@ Returns: i_img *
 i_img *
 i_copy(i_img *src) {
   i_img_dim y, y1, x1;
+  dIMCTXim(src);
   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;
@@ -533,9 +634,10 @@ i_scaleaxis(i_img *im, double Value, int Axis) {
   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();
-  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) {
     hsize = (i_img_dim)(0.5 + im->xsize * Value);
@@ -560,7 +662,7 @@ i_scaleaxis(i_img *im, double Value, int Axis) {
     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;
@@ -710,7 +812,7 @@ i_scaleaxis(i_img *im, double Value, int Axis) {
   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;
 }
@@ -733,8 +835,9 @@ i_scale_nn(i_img *im, double scx, double scy) {
   i_img_dim nxsize,nysize,nx,ny;
   i_img *new_img;
   i_color val;
+  dIMCTXim(im);
 
-  mm_log((1,"i_scale_nn(im %p,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 = (i_img_dim) ((double) im->xsize * scx);
   if (nxsize < 1) {
@@ -755,7 +858,7 @@ i_scale_nn(i_img *im, double scx, double scy) {
     i_ppix(new_img,nx,ny,&val);
   }
 
-  mm_log((1,"(%p) <- i_scale_nn\n",new_img));
+  im_log((aIMCTX, 1,"(%p) <- i_scale_nn\n",new_img));
 
   return new_img;
 }
@@ -773,7 +876,10 @@ For paletted images the palette is copied from the source.
 =cut
 */
 
-i_img *i_sametype(i_img *src, i_img_dim xsize, i_img_dim 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);
@@ -816,7 +922,10 @@ For paletted images the equivalent direct type is returned.
 =cut
 */
 
-i_img *i_sametype_chans(i_img *src, i_img_dim xsize, i_img_dim 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);
   }
@@ -857,8 +966,9 @@ i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int par
   i_img_dim nxsize,nysize,nx,ny;
   i_img *new_img;
   i_color val;
+  dIMCTXim(im);
   
-  mm_log((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));
+  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 ;
@@ -880,7 +990,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);
   }
 
-  mm_log((1,"(%p) <- i_transform\n",new_img));
+  im_log((aIMCTX, 1,"(%p) <- i_transform\n",new_img));
   return new_img;
 }
 
@@ -903,14 +1013,15 @@ i_img_diff(i_img *im1,i_img *im2) {
   int ch, chb;
   float tdiff;
   i_color val1,val2;
+  dIMCTXim(im1);
 
-  mm_log((1,"i_img_diff(im1 %p,im2 %p)\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;
 
-  mm_log((1,"i_img_diff: b=(" i_DFp ") chb=%d\n",
+  im_log((aIMCTX, 1,"i_img_diff: b=(" i_DFp ") chb=%d\n",
          i_DFcp(xb,yb), chb));
 
   tdiff=0;
@@ -920,7 +1031,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]);
   }
-  mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
+  im_log((aIMCTX, 1,"i_img_diff <- (%.2f)\n",tdiff));
   return tdiff;
 }
 
@@ -945,14 +1056,15 @@ i_img_diffd(i_img *im1,i_img *im2) {
   int ch, chb;
   double tdiff;
   i_fcolor val1,val2;
+  dIMCTXim(im1);
 
-  mm_log((1,"i_img_diffd(im1 %p,im2 %p)\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;
 
-  mm_log((1,"i_img_diffd: b(" i_DFp ") chb=%d\n",
+  im_log((aIMCTX, 1,"i_img_diffd: b(" i_DFp ") chb=%d\n",
          i_DFcp(xb, yb), chb));
 
   tdiff=0;
@@ -965,7 +1077,7 @@ i_img_diffd(i_img *im1,i_img *im2) {
       tdiff += sdiff * sdiff;
     }
   }
-  mm_log((1,"i_img_diffd <- (%.2f)\n",tdiff));
+  im_log((aIMCTX, 1,"i_img_diffd <- (%.2f)\n",tdiff));
 
   return tdiff;
 }
@@ -975,17 +1087,18 @@ 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)";
 
-  mm_log((1,"i_img_samef(im1 %p,im2 %p, epsilon %g, what '%s')\n", im1, im2, epsilon, what));
+  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;
 
-  mm_log((1,"i_img_samef: b(" i_DFp ") chb=%d\n",
+  im_log((aIMCTX, 1,"i_img_samef: b(" i_DFp ") chb=%d\n",
          i_DFcp(xb, yb), chb));
 
   for(y = 0; y < yb; y++) {
@@ -996,14 +1109,14 @@ i_img_samef(i_img *im1,i_img *im2, double epsilon, char const *what) {
       for(ch = 0; ch < chb; ch++) {
        double sdiff = val1.channel[ch] - val2.channel[ch];
        if (fabs(sdiff) > epsilon) {
-         mm_log((1,"i_img_samef <- different %g @(" i_DFp ")\n",
+         im_log((aIMCTX, 1,"i_img_samef <- different %g @(" i_DFp ")\n",
                  sdiff, i_DFcp(x, y)));
          return 0;
        }
       }
     }
   }
-  mm_log((1,"i_img_samef <- same\n"));
+  im_log((aIMCTX, 1,"i_img_samef <- same\n"));
 
   return 1;
 }
@@ -1015,9 +1128,10 @@ i_haar(i_img *im) {
   i_img_dim mx,my;
   i_img_dim fx,fy;
   i_img_dim x,y;
-  int ch,c;
+  int ch;
   i_img *new_img,*new_img2;
   i_color val1,val2,dval1,dval2;
+  dIMCTXim(im);
   
   mx=im->xsize;
   my=im->ysize;
@@ -1030,7 +1144,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);
 
-  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);
@@ -1097,7 +1210,8 @@ i_count_colors(i_img *im,int maxc) {
       for(x = 0; x < samp_cnt; ) {
           colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
           x += 3;
-          if (colorcnt > maxc) { 
+          if (colorcnt > maxc) {
+             myfree(samp);
               octt_delete(ct); 
               return -1; 
           }
@@ -1188,7 +1302,8 @@ i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
       colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
       x += 3;
       if (colorcnt > maxc) { 
-       octt_delete(ct); 
+       octt_delete(ct);
+       myfree(samp);
        return -1; 
       }
     }
@@ -1236,7 +1351,7 @@ int i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) {
   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;
@@ -1429,6 +1544,8 @@ int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
 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) {
+  dIMCTXim(im);
+
   if (bits < 1 || bits > 32) {
     i_push_error(0, "Invalid bits, must be 1..32");
     return -1;
@@ -1453,7 +1570,7 @@ i_gsamp_bits_fb(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samp
       /* 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;
         }
       }
@@ -1489,194 +1606,6 @@ i_gsamp_bits_fb(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samp
   }
 }
 
-/*
-=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;
@@ -1787,6 +1716,9 @@ i_test_format_probe(io_glue *data, int length) {
     /* JPEG 2000 
        This might match a little loosely */
     FORMAT_ENTRY("\x00\x00\x00\x0CjP  \x0D\x0A\x87\x0A", "jp2"),
+
+    /* FLIF - Free Lossless Image Format - https://flif.info/spec.html */
+    FORMAT_ENTRY("FLIF", "flif")
   };
   static const struct magic_entry more_formats[] = {
     /* these were originally both listed as ico, but cur files can
@@ -1801,10 +1733,17 @@ i_test_format_probe(io_glue *data, int length) {
   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;
-  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;
@@ -1863,7 +1802,8 @@ i_img_is_monochrome(i_img *im, int *zero_is_white) {
   if (im->type == i_palette_type
       && i_colorcount(im) == 2) {
     i_color colors[2];
-    i_getcolors(im, 0, colors, 2);
+    if (!i_getcolors(im, 0, colors, 2))
+      return 0;
     if (im->channels == 3) {
       if (colors[0].rgb.r == 255 && 
           colors[0].rgb.g == 255 &&
@@ -1909,19 +1849,24 @@ i_img_is_monochrome(i_img *im, int *zero_is_white) {
 
 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
 */
 
-void
+int
 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;
+
+  return result;
 }
 
 /*
@@ -1934,20 +1879,23 @@ 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
 */
 
-void
+int
 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;
+
+  return result;
 }
 
 /*