diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index bf99c584ed55733eae87b5afa37968a886bd0bcc..8c85c5112b09aa38ebd619b13c7c7b07a147e92f 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -109,12 +109,6 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
 			if (mipmap->colormap)
 				texel = mipmap->colormap[texel];
 
-			// If the mipmap is chromakeyed, check if the texel's color
-			// is equivalent to the chroma key's color index.
-			alpha = 0xff;
-			if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
-				alpha = 0x00;
-
 			// hope compiler will get this switch out of the loops (dreams...)
 			// gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
 			// Alam: SRB2 uses Mingw, HUGS
@@ -512,11 +506,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
 
 #ifndef NO_PNG_LUMPS
 		if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength))
-		{
-			// Dummy variables.
-			INT32 pngwidth, pngheight;
-			realpatch = (patch_t *)Picture_PNGConvert(pdata, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0);
-		}
+			realpatch = (patch_t *)Picture_PNGConvert(pdata, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
 		else
 #endif
 #ifdef WALLFLATS
@@ -558,12 +548,7 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm
 	// lump is a png so convert it
 	size_t len = W_LumpLengthPwad(grPatch->wadnum, grPatch->lumpnum);
 	if ((patch != NULL) && Picture_IsLumpPNG((const UINT8 *)patch, len))
-	{
-		// Dummy variables.
-		INT32 pngwidth, pngheight;
-		INT16 topoffset, leftoffset;
-		patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, &topoffset, &leftoffset, len, NULL, 0);
-	}
+		patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, NULL, NULL, NULL, NULL, len, NULL, 0);
 #endif
 
 	// don't do it twice (like a cache)
@@ -885,7 +870,7 @@ void HWR_GetLevelFlat(levelflat_t *levelflat)
 #ifndef NO_PNG_LUMPS
 	else if (levelflat->type == LEVELFLAT_PNG)
 	{
-		INT32 pngwidth, pngheight;
+		INT32 pngwidth = 0, pngheight = 0;
 		GLMipmap_t *mipmap = levelflat->mipmap;
 		UINT8 *flat;
 		size_t size;
diff --git a/src/r_picformats.c b/src/r_picformats.c
index d48bbaaf2f1ff6eba4c0f172cb3fcf3ce0e68e3d..f77d7dc487b2339f933af8aa6063fc56c82135b7 100644
--- a/src/r_picformats.c
+++ b/src/r_picformats.c
@@ -798,6 +798,8 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext)
 	CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext);
 }
 
+static png_byte grAb_chunk[5] = {'g', 'r', 'A', 'b', (png_byte)'\0'};
+
 static png_bytep *PNG_Read(
 	const UINT8 *png,
 	INT32 *w, INT32 *h, INT16 *topoffset, INT16 *leftoffset,
@@ -824,8 +826,6 @@ static png_bytep *PNG_Read(
 
 	png_io_t png_io;
 	png_bytep *row_pointers;
-
-	png_byte grAb_chunk[5] = {'g', 'r', 'A', 'b', (png_byte)'\0'};
 	png_voidp *user_chunk_ptr;
 
 	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn);
@@ -852,7 +852,6 @@ static png_bytep *PNG_Read(
 	png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf);
 #endif
 
-	// set our own read function
 	png_io.buffer = png;
 	png_io.size = size;
 	png_io.position = 0;
@@ -896,7 +895,7 @@ static png_bytep *PNG_Read(
 		// color is present on the image, the palette flag is disabled.
 		png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values);
 
-		if (trans_num == 256)
+		if (trans && trans_num == 256)
 		{
 			int i;
 			for (i = 0; i < trans_num; i++)
@@ -950,7 +949,6 @@ static png_bytep *PNG_Read(
 			*topoffset = (INT16)BIGENDIAN_LONG(*offsets);
 	}
 
-	// bye
 	png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
 	if (chunk.data)
 		Z_Free(chunk.data);
@@ -987,12 +985,28 @@ void *Picture_PNGConvert(
 	png_uint_32 x, y;
 	png_bytep row;
 	boolean palette = false;
-	png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, &palette, insize);
-	png_uint_32 width = *w, height = *h;
+	png_bytep *row_pointers = NULL;
+	png_uint_32 width, height;
+
+	INT32 pngwidth, pngheight;
+	INT16 loffs = 0, toffs = 0;
 
 	if (png == NULL)
 		I_Error("Picture_PNGConvert: picture was NULL!");
 
+	if (w == NULL)
+		w = &pngwidth;
+	if (h == NULL)
+		h = &pngheight;
+	if (topoffset == NULL)
+		topoffset = &toffs;
+	if (leftoffset == NULL)
+		leftoffset = &loffs;
+
+	row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, &palette, insize);
+	width = *w;
+	height = *h;
+
 	if (row_pointers == NULL)
 		I_Error("Picture_PNGConvert: row_pointers was NULL!");
 
@@ -1158,7 +1172,6 @@ void *Picture_PNGConvert(
 	{
 		void *converted;
 		pictureformat_t informat = PICFMT_NONE;
-		INT16 patleftoffset = 0, pattopoffset = 0;
 
 		// Figure out the format of the flat, from the bit depth of the output format
 		switch (outbpp)
@@ -1174,14 +1187,8 @@ void *Picture_PNGConvert(
 				break;
 		}
 
-		// Also find out if leftoffset and topoffset aren't pointing to NULL.
-		if (leftoffset)
-			patleftoffset = *leftoffset;
-		if (topoffset)
-			pattopoffset = *topoffset;
-
 		// Now, convert it!
-		converted = Picture_PatchConvert(informat, flat, outformat, insize, outsize, (INT16)width, (INT16)height, patleftoffset, pattopoffset, flags);
+		converted = Picture_PatchConvert(informat, flat, outformat, insize, outsize, (INT16)width, (INT16)height, loffs, toffs, flags);
 		Z_Free(flat);
 		return converted;
 	}
@@ -1195,10 +1202,12 @@ void *Picture_PNGConvert(
   * \param png The PNG image.
   * \param width A pointer to the input picture's width.
   * \param height A pointer to the input picture's height.
+  * \param topoffset A pointer to the input picture's vertical offset.
+  * \param leftoffset A pointer to the input picture's horizontal offset.
   * \param size The input picture's size.
   * \return True if reading the file succeeded, false if it failed.
   */
-boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size)
+boolean Picture_PNGDimensions(UINT8 *png, INT32 *width, INT32 *height, INT16 *topoffset, INT16 *leftoffset, size_t size)
 {
 	png_structp png_ptr;
 	png_infop png_info_ptr;
@@ -1211,9 +1220,9 @@ boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t si
 #endif
 
 	png_io_t png_io;
+	png_voidp *user_chunk_ptr;
 
-	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
-		PNG_error, PNG_warn);
+	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn);
 	if (!png_ptr)
 		I_Error("Picture_PNGDimensions: Couldn't initialize libpng!");
 
@@ -1237,23 +1246,41 @@ boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t si
 	png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf);
 #endif
 
-	// set our own read function
 	png_io.buffer = png;
 	png_io.size = size;
 	png_io.position = 0;
 	png_set_read_fn(png_ptr, &png_io, PNG_IOReader);
 
+	memset(&chunk, 0x00, sizeof(png_chunk_t));
+	chunkname = grAb_chunk; // I want to read a grAb chunk
+
+	user_chunk_ptr = png_get_user_chunk_ptr(png_ptr);
+	png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, PNG_ChunkReader);
+	png_set_keep_unknown_chunks(png_ptr, 2, chunkname, 1);
+
 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
 	png_set_user_limits(png_ptr, 2048, 2048);
 #endif
 
 	png_read_info(png_ptr, png_info_ptr);
+	png_get_IHDR(png_ptr, png_info_ptr, &w, &h, &bit_depth, &color_type, NULL, NULL, NULL);
 
-	png_get_IHDR(png_ptr, png_info_ptr, &w, &h, &bit_depth, &color_type,
-	 NULL, NULL, NULL);
+	// Read grAB chunk
+	if ((topoffset || leftoffset) && (chunk.data != NULL))
+	{
+		INT32 *offsets = (INT32 *)chunk.data;
+		// read left offset
+		if (leftoffset != NULL)
+			*leftoffset = (INT16)BIGENDIAN_LONG(*offsets);
+		offsets++;
+		// read top offset
+		if (topoffset != NULL)
+			*topoffset = (INT16)BIGENDIAN_LONG(*offsets);
+	}
 
-	// okay done. stop.
 	png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
+	if (chunk.data)
+		Z_Free(chunk.data);
 
 	*width = (INT32)w;
 	*height = (INT32)h;
@@ -1634,11 +1661,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
 		lumplength = W_LumpLength(lump);
 
 		if (Picture_IsLumpPNG((const UINT8 *)patch, lumplength))
-		{
-			INT32 pngwidth, pngheight;
-			INT16 toffs, loffs;
-			patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, &toffs, &loffs, lumplength, NULL, 0);
-		}
+			patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
 		else
 #endif
 		// Because there's something wrong with SPR_DFLM, I guess
diff --git a/src/r_picformats.h b/src/r_picformats.h
index 32754d64ea9048fa759f6fed309ba2d511b2e798..3ee76a92f1bf2c521ef92372429543e7de10cba8 100644
--- a/src/r_picformats.h
+++ b/src/r_picformats.h
@@ -110,7 +110,7 @@ void *Picture_PNGConvert(
 	INT16 *topoffset, INT16 *leftoffset,
 	size_t insize, size_t *outsize,
 	pictureflags_t flags);
-boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size);
+boolean Picture_PNGDimensions(UINT8 *png, INT32 *width, INT32 *height, INT16 *topoffset, INT16 *leftoffset, size_t size);
 #endif
 
 #define PICTURE_PNG_USELOOKUP
diff --git a/src/r_textures.c b/src/r_textures.c
index ef45863a2ff94239abe1226a0cea758fda2a5559..a34c29c728c79395d56ad93864b32c575032d5aa 100644
--- a/src/r_textures.c
+++ b/src/r_textures.c
@@ -397,11 +397,7 @@ UINT8 *R_GenerateTexture(size_t texnum)
 
 #ifndef NO_PNG_LUMPS
 		if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength))
-		{
-			// Dummy variables.
-			INT32 pngwidth, pngheight;
-			realpatch = (patch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0);
-		}
+			realpatch = (patch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
 		else
 #endif
 #ifdef WALLFLATS
@@ -800,10 +796,10 @@ Rloadflats (INT32 i, INT32 w)
 #ifndef NO_PNG_LUMPS
 			if (Picture_IsLumpPNG((UINT8 *)flatlump, lumplength))
 			{
-				INT16 width, height;
-				Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, lumplength);
-				texture->width = width;
-				texture->height = height;
+				INT32 width, height;
+				Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, NULL, NULL, lumplength);
+				texture->width = (INT16)width;
+				texture->height = (INT16)height;
 			}
 			else
 #endif
@@ -898,10 +894,10 @@ Rloadtextures (INT32 i, INT32 w)
 #ifndef NO_PNG_LUMPS
 			if (Picture_IsLumpPNG((UINT8 *)patchlump, lumplength))
 			{
-				INT16 width, height;
-				Picture_PNGDimensions((UINT8 *)patchlump, &width, &height, lumplength);
-				texture->width = width;
-				texture->height = height;
+				INT32 width, height;
+				Picture_PNGDimensions((UINT8 *)patchlump, &width, &height, NULL, NULL, lumplength);
+				texture->width = (INT16)width;
+				texture->height = (INT16)height;
 			}
 			else
 #endif
diff --git a/src/r_things.c b/src/r_things.c
index a3ce90991af9c627fbd26ac9276e578f19a2ca47..382eed5608b372d7a2d3c83191d20fa9f0626f66 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -259,6 +259,12 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 	{
 		if (memcmp(lumpinfo[l].name,sprname,4)==0)
 		{
+			INT32 width, height;
+			INT16 topoffset, leftoffset;
+#ifndef NO_PNG_LUMPS
+			boolean isPNG = false;
+#endif
+
 			frame = R_Char2Frame(lumpinfo[l].name[4]);
 			rotation = R_Char2Rotation(lumpinfo[l].name[5]);
 
@@ -274,28 +280,35 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 
 			// store sprite info in lookup tables
 			//FIXME : numspritelumps do not duplicate sprite replacements
-			W_ReadLumpHeaderPwad(wadnum, l, &patch, sizeof (patch_t), 0);
+
 #ifndef NO_PNG_LUMPS
 			{
 				patch_t *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC);
 				size_t len = W_LumpLengthPwad(wadnum, l);
-				// lump is a png so convert it
+
 				if (Picture_IsLumpPNG((UINT8 *)png, len))
 				{
-					// Dummy variables.
-					INT32 pngwidth, pngheight;
-					INT16 topoffset, leftoffset;
-					patch_t *converted = (patch_t *)Picture_PNGConvert((UINT8 *)png, PICFMT_PATCH, &pngwidth, &pngheight, &topoffset, &leftoffset, len, NULL, 0);
-					M_Memcpy(&patch, converted, sizeof(INT16)*4); // only copy the header because that's all we need
-					Z_Free(converted);
+					Picture_PNGDimensions((UINT8 *)png, &width, &height, &topoffset, &leftoffset, len);
+					isPNG = true;
 				}
+
 				Z_Free(png);
 			}
+
+			if (!isPNG)
 #endif
-			spritecachedinfo[numspritelumps].width = SHORT(patch.width)<<FRACBITS;
-			spritecachedinfo[numspritelumps].offset = SHORT(patch.leftoffset)<<FRACBITS;
-			spritecachedinfo[numspritelumps].topoffset = SHORT(patch.topoffset)<<FRACBITS;
-			spritecachedinfo[numspritelumps].height = SHORT(patch.height)<<FRACBITS;
+			{
+				W_ReadLumpHeaderPwad(wadnum, l, &patch, sizeof (patch_t), 0);
+				width = SHORT(patch.width);
+				height = SHORT(patch.height);
+				topoffset = SHORT(patch.topoffset);
+				leftoffset = SHORT(patch.leftoffset);
+			}
+
+			spritecachedinfo[numspritelumps].width = width<<FRACBITS;
+			spritecachedinfo[numspritelumps].offset = leftoffset<<FRACBITS;
+			spritecachedinfo[numspritelumps].topoffset = topoffset<<FRACBITS;
+			spritecachedinfo[numspritelumps].height = height<<FRACBITS;
 
 			//BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer
 			if (rendermode != render_none) // not for psprite
diff --git a/src/w_wad.c b/src/w_wad.c
index 1469b405f8aaadbc775e25dc008577b964f9c2de..11679b8f4f797564a815efb841f00b5c91115ea3 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -1685,10 +1685,8 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
 		// lump is a png so convert it
 		if (Picture_IsLumpPNG((UINT8 *)lumpdata, len))
 		{
-			// Dummy variables.
 			size_t newlen;
-			INT32 pngwidth, pngheight;
-			srcdata = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, len, &newlen, 0);
+			srcdata = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_PATCH, NULL, NULL, NULL, NULL, len, &newlen, 0);
 			ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]);
 			M_Memcpy(ptr, srcdata, newlen);
 			Z_Free(srcdata);