diff --git a/src/modules/Image/encodings/png.c b/src/modules/Image/encodings/png.c
index f9849164f160a2a2ddf57f1f7c3ad87143d68c68..2577a64e9d687d950c6461f9ac6b50dbd56298ad 100644
--- a/src/modules/Image/encodings/png.c
+++ b/src/modules/Image/encodings/png.c
@@ -1,5 +1,5 @@
 #include "global.h"
-RCSID("$Id: png.c,v 1.6 1998/04/03 03:49:50 mirar Exp $");
+RCSID("$Id: png.c,v 1.7 1998/04/05 21:10:43 mirar Exp $");
 
 #include "config.h"
 
@@ -343,9 +343,11 @@ static void image_png___decode(INT32 args)
 */
 
 static struct pike_string *_png_unfilter(unsigned char *data,
-					 INT32 len,int xsize,
+					 INT32 len,
+					 int xsize,int ysize,
 					 int filter,int type,
-					 int bpp,int interlace)
+					 int bpp,
+					 unsigned char **pos)
 {
    struct pike_string *ps;
    unsigned char *d;
@@ -372,9 +374,23 @@ static struct pike_string *_png_unfilter(unsigned char *data,
 
    for (;;)
    {
-      if (!len) return end_shared_string(ps);
+      if (!len || !ysize--) 
+      {
+	 if (pos) *pos=s;
+	 return end_shared_string(ps);
+      }
       x=xsize;
 
+      fprintf(stderr,
+	      "%05d 0x%08lx %02x %02x %02x > %02x < %02x %02x %02x "
+	      "len=%d xsize=%d sbb=%d next=0x%08lx d=0x%lx nd=0x%lx\n",
+	      ysize+1,(unsigned long)s,
+	      s[-3],s[-2],s[-1],s[0],s[1],s[2],s[3],
+	      len,xsize,sbb,
+	      (unsigned long)s+xsize+1,
+	      (unsigned long)d,
+	      (unsigned long)d+xsize);
+
       switch (*(s++))
       {
 	 case 0: /* no filter */
@@ -457,219 +473,37 @@ static struct pike_string *_png_unfilter(unsigned char *data,
    }
 }
 
-static void image_png__decode(INT32 args)
+static int _png_write_rgb(rgb_group *w1,
+			  rgb_group *wa1,
+			  int type,int bpp,
+			  unsigned char *s,
+			  unsigned long len,
+			  unsigned long width,
+			  int n,
+			  struct neo_colortable *ct)
 {
-   struct array *a;
-   struct mapping *m;
-   struct neo_colortable *ct=NULL;
-   rgb_group *d1,*da1,*w1,*wa1,*t1;
-   struct pike_string *fs;
-   unsigned char *s;
-   struct image *img;
+   /* returns 1 if interlace, 0 if not */
+   /* w1, wa1 will be freed upon error */
 
    static rgb_group white={255,255,255};
    static rgb_group grey4[4]={{0,0,0},{85,85,85},{170,170,170},{255,255,255}};
    static rgb_group black={0,0,0};
 
-   int n=0,i,mz,x,y;
-   struct ihdr
-   {
-      INT32 width,height;
-      int bpp;  /* bit depth, 1, 2, 4, 8 or 16  */
-      int type; /* 0, 2,3,4 or 6 */
-      int compression; /* 0 */
-      int filter; 
-      int interlace;
-   } ihdr={-1,-1,-1,0,-1,-1,-1};
-
-   if (args<1) 
-      error("Image.PNG.__decode: too few arguments\n");
-
-   pop_n_elems(args-1);
-
-   if (sp[-1].type==T_STRING)
-   {
-      push_int(1); /* no care crc */
-      image_png___decode(2);
-      if (sp[-1].type!=T_ARRAY)
-	 error("Image.PNG._decode: Not PNG data\n");
-   }
-   else if (sp[-1].type!=T_ARRAY)
-      error("Image.PNG._decode: Illegal argument\n");
-
-   (a=sp[-1].u.array)->refs++;
-
-   pop_n_elems(1);
-
-   m=allocate_mapping(10);
-   push_mapping(m);
-
-   for (i=0; i<a->size; i++)
-   {
-      struct array *b;
-      unsigned char *data;
-      unsigned long len;
-
-      if (a->item[i].type!=T_ARRAY ||
-	  (b=a->item[i].u.array)->size!=3 ||
-	  b->item[0].type!=T_STRING ||
-	  b->item[1].type!=T_STRING ||
-	  b->item[0].u.string->len!=4)
-	 error("Image.PNG._decode: Illegal stuff in array index %d\n",i);
-
-      data=(unsigned char*)b->item[1].u.string->str;
-      len=(unsigned long)b->item[1].u.string->len;
-
-      switch (int_from_32bit((unsigned char*)b->item[0].u.string->str))
-      {
-	 /* ------ major chunks ------------ */
-         case 0x49484452: /* IHDR */
-	    /* header info */
-	    if (b->item[1].u.string->len!=13)
-	       error("Image.PNG._decode: illegal header (IHDR chunk)\n");
-
-	    ihdr.width=int_from_32bit(data+0);
-	    ihdr.height=int_from_32bit(data+4);
-	    ihdr.bpp=data[8];
-	    ihdr.type=data[9];
-	    ihdr.compression=data[10];
-	    ihdr.filter=data[11];
-	    ihdr.interlace=data[12];
-	    break;
-
-         case 0x504c5445: /* PLTE */
-	    /* palette info, 3×n bytes */
-
-	    push_string(b->item[1].u.string);
-	    b->item[1].u.string->refs++;
-	    push_object(clone_object(image_colortable_program,1));
-
-	    if (ihdr.type==3)
-	    {
-	       ct=(struct neo_colortable*)
-		  get_storage(sp[-1].u.object,image_colortable_program);
-	       push_string(param_palette);
-	       param_palette->refs++;
-	       mapping_insert(m,sp-1,sp-2);
-	    }
-	    else
-	    {
-	       push_string(param_spalette);
-	       param_spalette->refs++;
-	       mapping_insert(m,sp-1,sp-2);
-	    }
-	    pop_n_elems(2);
-	    break;
-
-         case 0x49444154: /* IDAT */
-	    /* compressed image data. push, n++ */
-	    if (ihdr.compression!=0)
-	       free_mapping(m);
-
-	    push_string(b->item[1].u.string);
-	    b->item[1].u.string->refs++;
-	    n++;
-	    if (n>32) { f_add(n); n=1; }
-	    break;
-
-         case 0x49454e44: /* IEND */
-	    /* end of file */
-	    break;
-
-	 /* ------ minor chunks ------------ */
-
-         case 0x6348524d: /* cHRM */
-	    break;
-
-         case 0x67414d41: /* gAMA */
-	    break;
-
-         case 0x73424954: /* sBIT */
-	    break;
-
-         case 0x624b4744: /* bKGD */
-	    break;
-
-         case 0x68495354: /* hIST */
-	    break;
-
-         case 0x74524e53: /* tRNS */
-	    break;
-
-         case 0x70485973: /* pHYs */
-	    break;
-
-         case 0x74494d45: /* tIME */
-	    break;
-
-         case 0x7a455874: /* tEXt */
-	    break;
-
-         case 0x7a545874: /* zTXt */
-	    break;
-      }
-   }
-
-   /* on stack: mapping   n×string */
-
-   /* IDAT stuff on stack, now */
-   f_add(n);
-
-   if (ihdr.type==-1)
-   {
-      error("Image.PNG._decode: missing header (IHDR chunk)\n");
-   }
-   if (ihdr.type==3 && !ct)
-   {
-      error("Image.PNG._decode: missing palette (PLTE chunk)\n");
-   }
-   
-   if (ihdr.compression==0)
-   {
-      png_decompress(ihdr.compression);
-      if (sp[-1].type!=T_STRING)
-	 error("Image.PNG._decode: got wierd stuff from decompression\n");
-   }
-   else
-      error("Image.PNG._decode: illegal compression type 0x%02x\n",
-	    ihdr.compression);
-
-   fs=sp[-1].u.string; 
-   push_int(-1);
-   mapping_insert(m,sp-2,sp-1);
+   rgb_group *d1=w1;
+   rgb_group *da1=wa1;
 
-   /* not thread-safe */
-   fs=_png_unfilter((unsigned char*)fs->str,fs->len,
-		    ihdr.width,ihdr.filter,ihdr.type,ihdr.bpp,
-		    ihdr.interlace);
-   push_string(fs);
-   push_int(-1);
-   mapping_insert(m,sp-2,sp-1);
-   pop_n_elems(4);
-
-   s=(unsigned char*)fs->str;
-
-   w1=d1=malloc(sizeof(rgb_group)*ihdr.width*ihdr.height);
-   if (!d1)
-      error("Image.PNG._decode: Out of memory\n");
-
-   wa1=da1=malloc(sizeof(rgb_group)*ihdr.width*ihdr.height);
-   if (!da1)
-   {
-      free(d1);
-      error("Image.PNG._decode: Out of memory\n");
-   }
+   unsigned long x,mz;
 
    /* write stuff to d1 */
-   n=ihdr.width*ihdr.height;
-   switch (ihdr.type)
+
+   switch (type)
    {
       case 0: /* 1,2,4,8 or 16 bit greyscale */
-	 switch (ihdr.bpp)
+	 switch (bpp)
 	 {
 	    case 1:
-	       if (n>fs->len*8) n=fs->len*8;
-	       x=ihdr.width;
+	       if (n>len*8) n=len*8;
+	       x=width;
 	       while (n)
 	       {
 		  if (x) x--,*(d1++)=((*s)&128)?white:black;
@@ -683,12 +517,12 @@ static void image_png__decode(INT32 args)
 		  if (n<8) break;
 		  n-=8;
 		  s++;
-		  if (!x) x=ihdr.width;
+		  if (!x) x=width;
 	       }
 	       break;
 	    case 2:
-	       if (n>fs->len*4) n=fs->len*4;
-	       x=ihdr.width;
+	       if (n>len*4) n=len*4;
+	       x=width;
 	       while (n)
 	       {
 		  if (x) x--,*(d1++)=grey4[((*s)>>6)&3];
@@ -698,12 +532,12 @@ static void image_png__decode(INT32 args)
 		  if (n<4) break;
 		  n-=4;
 		  s++;
-		  if (!x) x=ihdr.width;
+		  if (!x) x=width;
 	       }
 	       break;
 	    case 4:
-	       if (n>fs->len*2) n=fs->len*2;
-	       x=ihdr.width;
+	       if (n>len*2) n=len*2;
+	       x=width;
 	       while (n)
 	       {
 		  int q;
@@ -720,11 +554,11 @@ static void image_png__decode(INT32 args)
 		  if (n<2) break;
 		  n-=2;
 		  s++;
-		  if (!x) x=ihdr.width;
+		  if (!x) x=width;
 	       }
 	       break;
 	    case 8:
-	       if (n>fs->len) n=fs->len;
+	       if (n>len) n=len;
 	       while (n)
 	       {
 		  d1->r=d1->g=d1->b=*(s++); d1++;
@@ -732,7 +566,7 @@ static void image_png__decode(INT32 args)
 	       }
 	       break;
 	    case 16:
-	       if (n>fs->len/2) n=fs->len/2;
+	       if (n>len/2) n=len/2;
 	       while (n)
 	       {
 		  d1->r=d1->g=d1->b=*(s++); d1++; s++;
@@ -742,17 +576,15 @@ static void image_png__decode(INT32 args)
 	    default:
 	       free(wa1); free(w1);
 	       error("Image.PNG->_decode: Unsupported color type/bit depth %d (grey)/%d bit.\n",
-		     ihdr.type,ihdr.bpp);
+		     type,bpp);
 	 }
-	 free(wa1); /* no alpha channel */
-	 wa1=NULL; 
-	 break;
+	 return 0; /* no alpha channel */
 
       case 2: /* 8 or 16 bit r,g,b */
-	 switch (ihdr.bpp)
+	 switch (bpp)
 	 {
 	    case 8:
-	       if (n>fs->len/3) n=fs->len/3;
+	       if (n>len/3) n=len/3;
 	       while (n)
 	       {
 		  d1->r=*(s++);
@@ -763,7 +595,7 @@ static void image_png__decode(INT32 args)
 	       }
 	       break;
 	    case 16:
-	       if (n>fs->len/6) n=fs->len/6;
+	       if (n>len/6) n=len/6;
 	       while (n)
 	       {
 		  d1->r=*(s++);
@@ -777,25 +609,31 @@ static void image_png__decode(INT32 args)
 	    default:
 	       free(wa1); free(w1);
 	       error("Image.PNG->_decode: Unsupported color type/bit depth %d (rgb)/%d bit.\n",
-		     ihdr.type,ihdr.bpp);
+		     type,bpp);
 	 }
-	 free(wa1); /* no alpha channel */
-	 wa1=NULL;
-	 break;
+	 return 0; /* no alpha channel */
 
       case 3: /* 1,2,4,8 bit palette index */
 	 if (!ct)
+	 {
+	    free(w1);
+	    free(wa1);
 	    error("Image.PNG->decode: No palette (PLTE entry), but color type (3) needs one\n");
+	 }
 	 if (ct->type!=NCT_FLAT)
+	 {
+	    free(w1);
+	    free(wa1);
 	    error("Image.PNG->decode: Internal error (created palette isn't flat)\n");
+	 }
 	 mz=ct->u.flat.numentries;
 
 #define CUTPLTE(X,Z) (((X)>=(Z))?0:(X))
-	 switch (ihdr.bpp)
+	 switch (bpp)
 	 {
 	    case 1:
-	       if (n>fs->len*8) n=fs->len*8;
-	       x=ihdr.width;
+	       if (n>len*8) n=len*8;
+	       x=width;
 	       while (n)
 	       {
 		  if (x) x--,*(d1++)=ct->u.flat.entries[CUTPLTE(((*s)>>7)&1,mz)].color;
@@ -809,12 +647,12 @@ static void image_png__decode(INT32 args)
 		  s++;
 		  if (n<8) break;
 		  n-=8;
-		  if (!x) x=ihdr.width;
+		  if (!x) x=width;
 	       }
 	       break;
 	    case 2:
-	       if (n>fs->len*4) n=fs->len*4;
-	       x=ihdr.width;
+	       if (n>len*4) n=len*4;
+	       x=width;
 	       while (n)
 	       {
 		  if (x) x--,*(d1++)=ct->u.flat.entries[CUTPLTE(((*s)>>6)&3,mz)].color;
@@ -824,12 +662,12 @@ static void image_png__decode(INT32 args)
 		  s++;
 		  if (n<4) break;
 		  n-=4;
-		  if (!x) x=ihdr.width;
+		  if (!x) x=width;
 	       }
 	       break;
 	    case 4:
-	       if (n>fs->len*2) n=fs->len*2;
-	       x=ihdr.width;
+	       if (n>len*2) n=len*2;
+	       x=width;
 	       while (n)
 	       {
 		  if (x) x--,*(d1++)=ct->u.flat.entries[CUTPLTE(((*s)>>4)&15,mz)].color;
@@ -837,11 +675,11 @@ static void image_png__decode(INT32 args)
 		  s++;
 		  if (n<2) break;
 		  n--;
-		  if (!x) x=ihdr.width;
+		  if (!x) x=width;
 	       }
 	       break;
 	    case 8:
-	       if (n>fs->len) n=fs->len;
+	       if (n>len) n=len;
 	       while (n)
 	       {
 		  *(d1++)=ct->u.flat.entries[CUTPLTE(*s,mz)].color;
@@ -852,17 +690,15 @@ static void image_png__decode(INT32 args)
 	       
 	    default:
 	       error("Image.PNG->_decode: Unsupported color type/bit depth %d (palette)/%d bit.\n",
-		     ihdr.type,ihdr.bpp);
+		     type,bpp);
 	 }
-	 free(wa1); /* no alpha channel */
-	 wa1=NULL; 
-	 break;
+	 return 0; /* no alpha channel */
 
       case 4: /* 8 or 16 bit grey,a */
-	 switch (ihdr.bpp)
+	 switch (bpp)
 	 {
 	    case 8:
-	       if (n>fs->len/3) n=fs->len/3;
+	       if (n>len/3) n=len/3;
 	       while (n)
 	       {
 		  d1->r=d1->g=d1->b=*(s++);
@@ -873,7 +709,7 @@ static void image_png__decode(INT32 args)
 	       }
 	       break;
 	    case 16:
-	       if (n>fs->len/6) n=fs->len/6;
+	       if (n>len/6) n=len/6;
 	       while (n)
 	       {
 		  d1->r=d1->g=d1->b=*(s++);
@@ -888,15 +724,15 @@ static void image_png__decode(INT32 args)
 	    default:
 	       free(wa1); free(w1);
 	       error("Image.PNG->_decode: Unsupported color type/bit depth %d (grey+a)/%d bit.\n",
-		     ihdr.type,ihdr.bpp);
+		     type,bpp);
 	 }
-	 break;
+	 return 1; /* alpha channel */
 
       case 6: /* 8 or 16 bit r,g,b,a */
-	 switch (ihdr.bpp)
+	 switch (bpp)
 	 {
 	    case 8:
-	       if (n>fs->len/3) n=fs->len/3;
+	       if (n>len/3) n=len/3;
 	       while (n)
 	       {
 		  d1->r=*(s++);
@@ -909,7 +745,7 @@ static void image_png__decode(INT32 args)
 	       }
 	       break;
 	    case 16:
-	       if (n>fs->len/6) n=fs->len/6;
+	       if (n>len/6) n=len/6;
 	       while (n)
 	       {
 		  d1->r=*(s++);
@@ -926,13 +762,220 @@ static void image_png__decode(INT32 args)
 	    default:
 	       free(wa1); free(w1);
 	       error("Image.PNG->_decode: Unsupported color type/bit depth %d(rgba)/%d bit.\n",
-		     ihdr.type,ihdr.bpp);
+		     type,bpp);
 	 }
-	 break;
+	 return 1; /* alpha channel */
       default:
 	 free(wa1); free(w1);
 	 error("Image.PNG->_decode: Unknown color type %d (bit depth %d).\n",
-	       ihdr.type,ihdr.bpp);
+	       type,bpp);
+   }
+}
+
+struct png_interlace
+{
+   int y0,yd,x0,xd;
+};
+
+static struct png_interlace adam7[8]=
+{ {0,8,0,8},
+  {0,8,4,8},
+  {4,8,0,4},
+  {0,4,2,4},
+  {2,4,0,2},
+  {0,2,1,2},
+  {1,2,0,1} };
+
+static void image_png__decode(INT32 args)
+{
+   struct array *a;
+   struct mapping *m;
+   struct neo_colortable *ct=NULL;
+   rgb_group *d1,*da1,*w1,*wa1,*t1;
+   struct pike_string *fs;
+   unsigned char *s,*s0;
+   struct image *img;
+
+   int n=0,i,x,y;
+   struct ihdr
+   {
+      INT32 width,height;
+      int bpp;  /* bit depth, 1, 2, 4, 8 or 16  */
+      int type; /* 0, 2,3,4 or 6 */
+      int compression; /* 0 */
+      int filter; 
+      int interlace;
+   } ihdr={-1,-1,-1,0,-1,-1,-1};
+
+   if (args<1) 
+      error("Image.PNG.__decode: too few arguments\n");
+
+   pop_n_elems(args-1);
+
+   if (sp[-1].type==T_STRING)
+   {
+      push_int(1); /* no care crc */
+      image_png___decode(2);
+      if (sp[-1].type!=T_ARRAY)
+	 error("Image.PNG._decode: Not PNG data\n");
+   }
+   else if (sp[-1].type!=T_ARRAY)
+      error("Image.PNG._decode: Illegal argument\n");
+
+   (a=sp[-1].u.array)->refs++;
+
+   pop_n_elems(1);
+
+   m=allocate_mapping(10);
+   push_mapping(m);
+
+   for (i=0; i<a->size; i++)
+   {
+      struct array *b;
+      unsigned char *data;
+      unsigned long len;
+
+      if (a->item[i].type!=T_ARRAY ||
+	  (b=a->item[i].u.array)->size!=3 ||
+	  b->item[0].type!=T_STRING ||
+	  b->item[1].type!=T_STRING ||
+	  b->item[0].u.string->len!=4)
+	 error("Image.PNG._decode: Illegal stuff in array index %d\n",i);
+
+      data=(unsigned char*)b->item[1].u.string->str;
+      len=(unsigned long)b->item[1].u.string->len;
+
+      switch (int_from_32bit((unsigned char*)b->item[0].u.string->str))
+      {
+	 /* ------ major chunks ------------ */
+         case 0x49484452: /* IHDR */
+	    /* header info */
+	    if (b->item[1].u.string->len!=13)
+	       error("Image.PNG._decode: illegal header (IHDR chunk)\n");
+
+	    ihdr.width=int_from_32bit(data+0);
+	    ihdr.height=int_from_32bit(data+4);
+	    ihdr.bpp=data[8];
+	    ihdr.type=data[9];
+	    ihdr.compression=data[10];
+	    ihdr.filter=data[11];
+	    ihdr.interlace=data[12];
+	    break;
+
+         case 0x504c5445: /* PLTE */
+	    /* palette info, 3×n bytes */
+
+	    push_string(b->item[1].u.string);
+	    b->item[1].u.string->refs++;
+	    push_object(clone_object(image_colortable_program,1));
+
+	    if (ihdr.type==3)
+	    {
+	       ct=(struct neo_colortable*)
+		  get_storage(sp[-1].u.object,image_colortable_program);
+	       push_string(param_palette);
+	       param_palette->refs++;
+	       mapping_insert(m,sp-1,sp-2);
+	    }
+	    else
+	    {
+	       push_string(param_spalette);
+	       param_spalette->refs++;
+	       mapping_insert(m,sp-1,sp-2);
+	    }
+	    pop_n_elems(2);
+	    break;
+
+         case 0x49444154: /* IDAT */
+	    /* compressed image data. push, n++ */
+	    if (ihdr.compression!=0)
+	       free_mapping(m);
+
+	    push_string(b->item[1].u.string);
+	    b->item[1].u.string->refs++;
+	    n++;
+	    if (n>32) { f_add(n); n=1; }
+	    break;
+
+         case 0x49454e44: /* IEND */
+	    /* end of file */
+	    break;
+
+	 /* ------ minor chunks ------------ */
+
+         case 0x6348524d: /* cHRM */
+	    break;
+
+         case 0x67414d41: /* gAMA */
+	    break;
+
+         case 0x73424954: /* sBIT */
+	    break;
+
+         case 0x624b4744: /* bKGD */
+	    break;
+
+         case 0x68495354: /* hIST */
+	    break;
+
+         case 0x74524e53: /* tRNS */
+	    break;
+
+         case 0x70485973: /* pHYs */
+	    break;
+
+         case 0x74494d45: /* tIME */
+	    break;
+
+         case 0x7a455874: /* tEXt */
+	    break;
+
+         case 0x7a545874: /* zTXt */
+	    break;
+      }
+   }
+
+   /* on stack: mapping   n×string */
+
+   /* IDAT stuff on stack, now */
+   f_add(n);
+
+   if (ihdr.type==-1)
+   {
+      error("Image.PNG._decode: missing header (IHDR chunk)\n");
+   }
+   if (ihdr.type==3 && !ct)
+   {
+      error("Image.PNG._decode: missing palette (PLTE chunk)\n");
+   }
+   
+   if (ihdr.compression==0)
+   {
+      png_decompress(ihdr.compression);
+      if (sp[-1].type!=T_STRING)
+	 error("Image.PNG._decode: got wierd stuff from decompression\n");
+   }
+   else
+      error("Image.PNG._decode: illegal compression type 0x%02x\n",
+	    ihdr.compression);
+
+   fs=sp[-1].u.string; 
+   push_int(-1);
+   mapping_insert(m,sp-2,sp-1);
+
+   pop_n_elems(2);
+
+   s=(unsigned char*)fs->str;
+
+   w1=d1=malloc(sizeof(rgb_group)*ihdr.width*ihdr.height);
+   if (!d1)
+      error("Image.PNG._decode: Out of memory\n");
+
+   wa1=da1=malloc(sizeof(rgb_group)*ihdr.width*ihdr.height);
+   if (!da1)
+   {
+      free(d1);
+      error("Image.PNG._decode: Out of memory\n");
    }
 
    /* --- interlace decoding --- */
@@ -940,32 +983,73 @@ static void image_png__decode(INT32 args)
    switch (ihdr.interlace)
    {
       case 0: /* none */
+	 fs=_png_unfilter((unsigned char*)fs->str,fs->len,
+			  ihdr.width,ihdr.height,
+			  ihdr.filter,ihdr.type,ihdr.bpp,
+			  NULL);
+	 push_string(fs);
+	 if (!_png_write_rgb(w1,wa1,
+			     ihdr.type,ihdr.bpp,fs->str,
+			     fs->len,
+			     ihdr.width,
+			     ihdr.width*ihdr.height,
+			     ct))
+	 {
+	    free(wa1);
+	    wa1=NULL;
+	 }
+	 pop_stack();
 	 break;
 
       case 1: /* adam7 */
+
+	 /* need arena */
 	 t1=malloc(sizeof(rgb_group)*ihdr.width*ihdr.height);
 	 if (!t1)
 	 {
 	    if (wa1) free(wa1); free(w1); 
 	    error("Image.PNG->_decode: out of memory (close one)\n");
 	 }
-	 d1=w1;
-	 for (y=0;y<ihdr.height;y+=8) for (x=0;x<ihdr.width;x+=8)
-	       t1[x+y*ihdr.width]=*(d1++);
-	 for (y=0;y<ihdr.height;y+=8) for (x=4;x<ihdr.width;x+=8)
-	       t1[x+y*ihdr.width]=*(d1++);
-	 for (y=4;y<ihdr.height;y+=8) for (x=0;x<ihdr.width;x+=4)
-	       t1[x+y*ihdr.width]=*(d1++);
-	 for (y=0;y<ihdr.height;y+=8) for (x=2;x<ihdr.width;x+=4)
-	       t1[x+y*ihdr.width]=*(d1++);
-	 for (y=2;y<ihdr.height;y+=4) for (x=0;x<ihdr.width;x+=2)
-	       t1[x+y*ihdr.width]=*(d1++);
-	 for (y=0;y<ihdr.height;y+=2) for (x=1;x<ihdr.width;x+=2)
-	       t1[x+y*ihdr.width]=*(d1++);
-	 for (y=1;y<ihdr.height;y+=2) for (x=0;x<ihdr.width;x++)
-	       t1[x+y*ihdr.width]=*(d1++);
+
+	 /* loop over adam7 interlace's 
+	    and write them to the arena */
+
+	 s0=(unsigned char*)fs->str;
+	 for (i=0; i<7; i++)
+	 {
+	    struct pike_string *ds;
+
+	    ds=_png_unfilter(s0,fs->len-(s0-(unsigned char*)fs->str),
+			     (ihdr.width+adam7[i].xd-1-adam7[i].x0)/
+			     adam7[i].xd,			     
+			     (ihdr.height+adam7[i].yd-1-adam7[i].y0)/
+			     adam7[i].yd,
+			     ihdr.filter,ihdr.type,ihdr.bpp,
+			     &s0);
+
+	    push_string(ds);
+	    if (!_png_write_rgb(w1,wa1,ihdr.type,ihdr.bpp,ds->str,ds->len,
+				(ihdr.width+adam7[i].xd-1-adam7[i].x0)/
+				adam7[i].xd,
+				(ihdr.width+adam7[i].xd-1-adam7[i].x0)/
+				adam7[i].xd*
+				(ihdr.height+adam7[i].yd-1-adam7[i].y0)/
+				adam7[i].yd,
+				ct))
+	    {
+	       if (wa1) free(wa1);
+	       wa1=NULL;
+	    }
+	    d1=w1;
+	    for (y=adam7[i].y0;y<ihdr.height;y+=adam7[i].yd)
+	       for (x=adam7[i].x0;x<ihdr.width;x+=adam7[i].xd)
+		  t1[x+y*ihdr.width]=*(d1++);
+
+	    pop_stack();
+	 }
 	 
 	 free(w1);
+	 if (wa1) free(wa1);
 	 w1=t1;
 
 	 break;
@@ -973,6 +1057,8 @@ static void image_png__decode(INT32 args)
 	 free(w1); if (wa1) free(wa1);
 	 error("Image.PNG._decode: Unknown interlace type\n");
    }
+
+
    
    
    /* --- done, store in mapping --- */