diff -rupN postgis-old/raster/rt_pg/rtpostgis.sql.in.c postgis-new/raster/rt_pg/rtpostgis.sql.in.c
--- postgis-old/raster/rt_pg/rtpostgis.sql.in.c	2011-04-22 16:30:47.000000000 -0700
+++ postgis-new/raster/rt_pg/rtpostgis.sql.in.c	2011-04-22 16:30:16.000000000 -0700
@@ -664,6 +664,93 @@ CREATE OR REPLACE FUNCTION st_asjpeg(ras
 	LANGUAGE 'SQL' IMMUTABLE STRICT;
 
 -----------------------------------------------------------------------
+-- ST_AsPNG
+-----------------------------------------------------------------------
+-- Cannot be strict as "options" can be NULL
+CREATE OR REPLACE FUNCTION st_aspng(rast raster, options text[])
+	RETURNS bytea
+	AS $$
+	DECLARE
+		num_bands int;
+		i int;
+		pt text;
+	BEGIN
+		num_bands := st_numbands($1);
+
+		-- PNG only allows 1 or 3 bands
+		IF num_bands > 3 THEN
+			RAISE WARNING 'The PNG format only permits one or three bands.  The first three bands will be used.';
+			rast := st_band(rast, ARRAY[1, 2, 3]);
+			num_bands := st_numbands(rast);
+		ELSEIF num_bands > 1 THEN
+			RAISE WARNING 'The PNG format only permits one or three bands.  The first band will be used.';
+			rast := st_band(rast, ARRAY[1]);
+			num_bands := st_numbands(rast);
+		END IF;
+
+		-- PNG only supports 8BUI and 16BUI pixeltype
+		FOR i IN 1..num_bands LOOP
+			pt = st_bandpixeltype(rast, i);
+			IF pt != '8BUI' AND pt != '16BUI' THEN
+				RAISE EXCEPTION 'The pixel type of band % in the raster is not 8BUI or 16BUI.  The PNG format can only be used with 8BUI and 16BUI pixel types.', i;
+			END IF;
+		END LOOP;
+
+		RETURN st_asgdalraster($1, 'PNG', $2, NULL);
+	END;
+	$$ LANGUAGE 'plpgsql' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION st_aspng(rast raster)
+	RETURNS bytea
+	AS $$ SELECT st_aspng($1, NULL::text[]) $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION st_aspng(rast raster, nbands int[], options text[])
+	RETURNS bytea
+	AS $$ SELECT st_aspng(st_band($1, $2), $3) $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION st_aspng(rast raster, nbands int[])
+	RETURNS bytea
+	AS $$ SELECT st_aspng(st_band($1, $2), NULL::text[]) $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION st_aspng(rast raster, nband int)
+	RETURNS bytea
+	AS $$ SELECT st_aspng(st_band($1, $2)) $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION st_aspng(rast raster, nbands int[], compression int)
+	RETURNS bytea
+	AS $$
+	DECLARE
+		options text[];
+	BEGIN
+		IF compression IS NOT NULL THEN
+			IF compression > 9 THEN
+				compression := 9;
+			ELSEIF compression < 1 THEN
+				compression := 1;
+			END IF;
+
+			options := array_append(options, 'ZLEVEL=' || compression);
+		END IF;
+
+		RETURN st_aspng(st_band($1, $2), options);
+	END;
+	$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION st_aspng(rast raster, nband int, options text[])
+	RETURNS bytea
+	AS $$ SELECT st_aspng(st_band($1, $2), $3) $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION st_aspng(rast raster, nband int, compression int)
+	RETURNS bytea
+	AS $$ SELECT st_aspng($1, ARRAY[$2], $3) $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-----------------------------------------------------------------------
 -- MapAlgebra
 -----------------------------------------------------------------------
 -- This function can not be STRICT, because nodatavalueexpr can be NULL (could be just '' though)
diff -rupN postgis-old/raster/test/regress/Makefile.in postgis-new/raster/test/regress/Makefile.in
--- postgis-old/raster/test/regress/Makefile.in	2011-04-22 16:30:47.000000000 -0700
+++ postgis-new/raster/test/regress/Makefile.in	2011-04-22 16:28:28.000000000 -0700
@@ -46,6 +46,7 @@ TEST_FUNC = \
 	rt_asgdalraster.sql \
 	rt_astiff.sql \
 	rt_asjpeg.sql \
+	rt_aspng.sql \
 	$(NULL)
 
 TEST_PROPS = \
diff -rupN postgis-old/raster/test/regress/rt_aspng.sql postgis-new/raster/test/regress/rt_aspng.sql
--- postgis-old/raster/test/regress/rt_aspng.sql	1969-12-31 16:00:00.000000000 -0800
+++ postgis-new/raster/test/regress/rt_aspng.sql	2011-04-22 16:28:48.000000000 -0700
@@ -0,0 +1,94 @@
+SELECT md5(
+	ST_AsPNG(
+		ST_AddBand(ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1), 1, '8BSI', 123, NULL)
+	)
+);
+SELECT md5(
+	ST_AsPNG(
+		ST_AddBand(ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1), 1, '8BUI', 123, NULL)
+	)
+);
+SELECT md5(
+	ST_AsPNG(
+		ST_AddBand(ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1), 1, '8BSI', -123, NULL)
+	)
+);
+SELECT md5(
+	ST_AsPNG(
+		ST_AddBand(ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1), 1, '8BUI', 254, NULL)
+	)
+);
+SELECT md5(
+	ST_AsPNG(
+		ST_AddBand(
+			ST_AddBand(
+				ST_AddBand(
+					ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1)
+					, 1, '8BSI', 1, -1
+				)
+				, 2, '8BSI', 11, -1
+			)
+			, 3, '8BSI', 111, -1
+		),
+		ARRAY['ZLEVEL=1']
+	)
+);
+SELECT md5(
+	ST_AsPNG(
+		ST_AddBand(
+			ST_AddBand(
+				ST_AddBand(
+					ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1)
+					, 1, '8BSI', 1, -1
+				)
+				, 2, '8BSI', 11, -1
+			)
+			, 3, '8BSI', 111, -1
+		),
+		ARRAY['ZLEVEL=9']
+	)
+);
+SELECT md5(
+	ST_AsPNG(
+		ST_AddBand(
+			ST_AddBand(
+				ST_AddBand(
+					ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1)
+					, 1, '8BSI', 1, 1
+				)
+				, 2, '8BSI', 11, 1
+			)
+			, 3, '8BSI', 111, 1
+		),
+		ARRAY['ZLEVEL=9']
+	)
+);
+SELECT md5(
+	ST_AsPNG(
+		ST_AddBand(
+			ST_AddBand(
+				ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1)
+				, 1, '8BUI', 1, 1
+			)
+			, 2, '8BUI', 11, 1
+		),
+		ARRAY[1],
+		6
+	)
+);
+SELECT md5(
+	ST_AsPNG(
+		ST_AddBand(
+			ST_AddBand(
+				ST_AddBand(
+					ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1)
+					, 1, '8BUI', 1, 1
+				)
+				, 2, '8BUI', 11, 1
+			)
+			, 3, '8BUI', 111, 1
+		),
+		ARRAY[3,1],
+		6
+	)
+);
diff -rupN postgis-old/raster/test/regress/rt_aspng_expected postgis-new/raster/test/regress/rt_aspng_expected
--- postgis-old/raster/test/regress/rt_aspng_expected	1969-12-31 16:00:00.000000000 -0800
+++ postgis-new/raster/test/regress/rt_aspng_expected	2011-04-22 16:28:48.000000000 -0700
@@ -0,0 +1,13 @@
+ERROR:  The pixel type of band 1 in the raster is not 8BUI or 16BUI.  The PNG format can only be used with 8BUI and 16BUI pixel types.
+55279950e29968bcf36b2c11ce8bf88b
+ERROR:  The pixel type of band 1 in the raster is not 8BUI or 16BUI.  The PNG format can only be used with 8BUI and 16BUI pixel types.
+24188762b5745acda4aa7b92776e7280
+WARNING:  The PNG format only permits one or three bands.  The first band will be used.
+ERROR:  The pixel type of band 1 in the raster is not 8BUI or 16BUI.  The PNG format can only be used with 8BUI and 16BUI pixel types.
+WARNING:  The PNG format only permits one or three bands.  The first band will be used.
+ERROR:  The pixel type of band 1 in the raster is not 8BUI or 16BUI.  The PNG format can only be used with 8BUI and 16BUI pixel types.
+WARNING:  The PNG format only permits one or three bands.  The first band will be used.
+ERROR:  The pixel type of band 1 in the raster is not 8BUI or 16BUI.  The PNG format can only be used with 8BUI and 16BUI pixel types.
+3b859bf98d434fe1cbefb96844badfec
+WARNING:  The PNG format only permits one or three bands.  The first band will be used.
+58168aa11f7ccdf095e5ed02bde1e676

