diff --git a/src/modules/Image/encodings/png.c b/src/modules/Image/encodings/png.c
index 351e4d48fa52b4adf427dc12eac44831a394bc29..51ecebc7f5798873f669a233962af1554ffa1c2c 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.14 1998/04/20 18:53:35 grubba Exp $");
+RCSID("$Id: png.c,v 1.15 1998/05/02 01:24:26 mirar Exp $");
 
 #include "config.h"
 
@@ -281,6 +281,7 @@ static void image_png___decode(INT32 args)
 
 /*
 **! method array _decode(string|array data)
+**! method array _decode(string|array data,mapping options)
 **! 	Decode a PNG image file.
 **!
 **!     Result is a mapping,
@@ -294,8 +295,8 @@ static void image_png___decode(INT32 args)
 **!
 **!	<tt>image</tt> is the stored image.
 **!
-**!	Valid entries in <tt>options</tt> is the same
-**!	as given to <ref>encode</ref>:
+**!	Valid entries in <tt>options</tt> is a superset
+**!	of the one given to <ref>encode</ref>:
 **!
 **!	<pre>
 **!     basic options:
@@ -354,6 +355,15 @@ static void image_png___decode(INT32 args)
 **!	    "compression": int method         - compression method (0)
 **!
 **!      </pre>
+**!	
+**!	This method can also take options, 
+**! 	as a mapping:
+**!	<pre>
+**!     advanced options:
+**!	    "palette": colortable object
+**!		- replace the decoded palette with this when
+**!		  unpacking the image data, if applicable
+**!	</pre>
 **!
 **! note
 **!	Please read about the PNG file format.
@@ -674,6 +684,12 @@ static int _png_write_rgb(rgb_group *w1,
 	    error("Image.PNG->decode: Internal error (created palette isn't flat)\n");
 	 }
 	 mz=ct->u.flat.numentries;
+	 if (mz==0)
+	 {
+	    free(w1);
+	    free(wa1);
+	    error("Image.PNG->decode: palette is zero entries long; need at least one color.\n");
+	 }
 
 #define CUTPLTE(X,Z) (((X)>=(Z))?0:(X))
 	 switch (bpp)
@@ -958,9 +974,51 @@ static void image_png__decode(INT32 args)
    } ihdr={-1,-1,-1,0,-1,-1,-1};
 
    if (args<1) 
-      error("Image.PNG.__decode: too few arguments\n");
+      error("Image.PNG._decode: too few arguments\n");
+
+   m=allocate_mapping(10);
+   push_mapping(m);
+
+   if (args>=2)
+   {
+      if (sp[1-args-1].type!=T_MAPPING)
+	 error("Image.PNG._decode: illegal argument 2\n");
+
+      push_svalue(sp+1-args-1);
+      ref_push_string(param_palette);
+      f_index(2);
+      switch (sp[-1].type)
+      {
+	 case T_OBJECT:
+	    push_string(make_shared_string("cast"));
+	    if (sp[-1].type==T_INT)
+	       error("Image.PNG._decode: illegal value of option \"palette\"\n");
+	    f_index(2);
+	    push_string(make_shared_string("array"));
+	    f_call_function(2);
+	 case T_ARRAY:
+	 case T_STRING:
+	    push_object(clone_object(image_colortable_program,1));
 
+	    ct=(struct neo_colortable*)get_storage(sp[-1].u.object,
+						   image_colortable_program);
+	    if (!ct)
+	       error("Image.PNG._decode: internal error: cloned colortable isn't colortable\n");
+	    ref_push_string(param_palette);
+	    mapping_insert(m,sp-1,sp-2);
+	    pop_n_elems(2);
+	    break;
+	 case T_INT:
+	    pop_n_elems(1);
+	 default:
+	    error("Image.PNG._decode: illegal value of option \"palette\"\n");
+      }
+   }
+
+   sp--;
    pop_n_elems(args-1);
+   push_mapping(m);
+   stack_swap();
 
    if (sp[-1].type==T_STRING)
    {
@@ -970,14 +1028,9 @@ static void image_png__decode(INT32 args)
 	 error("Image.PNG._decode: Not PNG data\n");
    }
    else if (sp[-1].type!=T_ARRAY)
-      error("Image.PNG._decode: Illegal argument\n");
+      error("Image.PNG._decode: Illegal argument 1\n");
 
-   add_ref(a=sp[-1].u.array);
-
-   pop_n_elems(1);
-
-   m=allocate_mapping(10);
-   push_mapping(m);
+   a=sp[-1].u.array;
 
    for (i=0; i<a->size; i++)
    {
@@ -1020,6 +1073,8 @@ static void image_png__decode(INT32 args)
          case 0x504c5445: /* PLTE */
 	    /* palette info, 3×n bytes */
 
+	    if (ct) break; /* we have a palette already */
+
 	    ref_push_string(b->item[1].u.string);
 	    push_object(clone_object(image_colortable_program,1));
 
@@ -1137,7 +1192,10 @@ static void image_png__decode(INT32 args)
    /* on stack: mapping   n×string */
 
    /* IDAT stuff on stack, now */
-   f_add(n);
+   if (!n) 
+      push_string(make_shared_binary_string("",0));
+   else
+      f_add(n);
 
    if (ihdr.type==-1)
    {
@@ -1321,6 +1379,8 @@ static void image_png__decode(INT32 args)
    push_int(-2);
    map_delete(m,sp-1);
    pop_stack();
+
+   pop_stack(); /* remove 'a' from stack */
 }
 
 
@@ -1659,11 +1719,11 @@ struct object *init_image_png(void)
       if (gz_deflate)
       {
 	 add_function("_decode",image_png__decode,
-		      "function(array|string,void|mapping(string:int):object)",0);
+		      "function(array|string,void|mapping(string:mixed):object)",0);
 	 add_function("decode",image_png_decode,
-		      "function(string,void|mapping(string:int):object)",0);
+		      "function(string,void|mapping(string:mixed):object)",0);
 	 add_function("decode_alpha",image_png_decode_alpha,
-		      "function(string,void|mapping(string:int):object)",0);
+		      "function(string,void|mapping(string:mixed):object)",0);
       }
       add_function("encode",image_png_encode,
 		   "function(object,void|mapping(string:mixed):string)",