Solid Fluid System Solutions  
Home Software About Hardware Firmware
Document Icon LibPNG
Document Icon Modifications
Document Icon ToPNG
Current Document Icon FromPNG

The FromPNG function

#include "ImgPNG.h"
#include "ImgAlloc.h"
#include ".\PNG\png.h"
#include ".\PNG\pngbuffersrc.h"
#include ".\PNG\pngbufferdst.h"

void png_FromPNG(void*& pBuf,unsigned long& BufSz,ImgPNGInfo& Info)
{
	png_structp png_ptr;
	png_infop info_ptr;

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
	if(png_ptr == NULL)
	{
		img_free(pBuf);
		BufSz = 0;
		return;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if(info_ptr == NULL)
	{
		img_free(pBuf);
		BufSz = 0;

		png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);

		return;
	}

	Info.Trns = PNG_TRNS_NONE;

	buffered_read_info aBRI;
	aBRI.Size = BufSz;
	aBRI.pBuf = (char*) pBuf;
	aBRI.Ptr = 0;

	png_set_read_fn(png_ptr,(void*)&aBRI,png_buffered_read_data);

	png_read_info(png_ptr, info_ptr);

	int bit_depth,color_type;
	png_get_IHDR(png_ptr,info_ptr,&Info.XDim,&Info.YDim,&bit_depth,&color_type,int_p_NULL,int_p_NULL,int_p_NULL);

	bool DoRead = false;
	bool CreatePalette = false;
	bool UsePalette = false;
	char PixelMultiplier = 0;
	bool Divide;
	unsigned long PaletteSize;
	unsigned long SrcPaletteMask;
	if(color_type == PNG_COLOR_TYPE_GRAY)
	{
		switch(bit_depth)
		{
			case 16:
			{
				png_set_strip_16(png_ptr); // reduce to 8bits per colour

				Info.BitCount = 8;
				Info.PNGColorType = PNG_TYPE_GREY;
				PixelMultiplier = 1;
				Divide = false;
				CreatePalette = true;
				PaletteSize = 256;
				DoRead = true;
			}
			break;

			case 8:
			{
				Info.BitCount = 8;
				Info.PNGColorType = PNG_TYPE_GREY;
				PixelMultiplier = 1;
				Divide = false;
				CreatePalette = true;
				PaletteSize = 256;
				DoRead = true;
			}
			break;

			case 4:
			{
				Info.BitCount = 4;
				Info.PNGColorType = PNG_TYPE_GREY;
				PixelMultiplier = 2;
				Divide = true;
				CreatePalette = true;
				PaletteSize = 16;
				DoRead = true;
			}
			break;

			case 2:
			{
				png_set_packing(png_ptr); // increase to 8bits per colour

				Info.BitCount = 8;
				Info.PNGColorType = PNG_TYPE_GREY;
				PixelMultiplier = 1;
				Divide = false;
				CreatePalette = true;
				PaletteSize = 256;
				DoRead = true;
			}
			break;

			case 1:
			{
				Info.BitCount = 1;
				Info.PNGColorType = PNG_TYPE_GREY;
				PixelMultiplier = 8;
				Divide = true;
				CreatePalette = true;
				PaletteSize = 2;
				DoRead = true;
			}
			break;

			default:
			break;
		}

		if((info_ptr->valid & PNG_INFO_tRNS) != 0)
		{
			png_color_16p trans_values = NULL;

			png_get_tRNS(png_ptr,info_ptr,NULL,NULL,&trans_values);

			if(trans_values != NULL)
			{
				Info.Trns = PNG_TRNS_INDEX;

				if(bit_depth < 16)
				 Info.TrnsIndex = (unsigned char) trans_values->gray;
				else
				 Info.TrnsIndex = (unsigned char) (trans_values->gray >> 8);
			}
		}
	}
	else
	if(color_type == PNG_COLOR_TYPE_PALETTE)
	{
		switch(bit_depth)
		{
			case 1:
			{
				Info.BitCount = 1;
				Info.PNGColorType = PNG_TYPE_PALETTE;
				PixelMultiplier = 8;
				Divide = true;
				UsePalette = true;
				PaletteSize = 2;
				SrcPaletteMask = 0x00000001;
				DoRead = true;
			}
			break;

			case 2:
			{
				// Convert to 256 colour palette
				// otherwise we'd have to repack 2 bit data to 4 bit data
				// and we have no way to test that it works, and there's 
				// no functional precedent
				png_set_packing(png_ptr);

				Info.BitCount = 8;
				Info.PNGColorType = PNG_TYPE_PALETTE;
				PixelMultiplier = 1;
				Divide = false;
				UsePalette = true;
				PaletteSize = 256;
				SrcPaletteMask = 0x00000003;
				DoRead = true;
			}
			break;

			case 4:
			{
				Info.BitCount = 4;
				Info.PNGColorType = PNG_TYPE_PALETTE;
				PixelMultiplier = 2;
				Divide = true;
				UsePalette = true;
				PaletteSize = 16;
				SrcPaletteMask = 0x0000000F;
				DoRead = true;
			}
			break;

			case 8:
			{
				Info.BitCount = 8;
				Info.PNGColorType = PNG_TYPE_PALETTE;
				PixelMultiplier = 1;
				Divide = false;
				UsePalette = true;
				PaletteSize = 256;
				SrcPaletteMask = 0x000000FF;
				DoRead = true;
			}
			break;

			default:
			break;
		}

		if((info_ptr->valid & PNG_INFO_tRNS) != 0)
		{
			png_bytep trans = NULL;
			int num_trans = 0;

			png_get_tRNS(png_ptr,info_ptr,&trans,&num_trans,NULL);

			if((trans != NULL) && (num_trans > 0))
			{
				bool Variable;
				int i,Count;

				Count = 0;
				Variable = false;
				for(i=0;i<num_trans;i++)
				{
					if(trans[i] == 0x00)
					{
						Info.TrnsIndex = (unsigned char) i;
						Count++;
					}
					else
					if(trans[i] != 0xFF)
					 Variable = true;
				}

				if((Count == 1) && (!Variable))
				 Info.Trns = PNG_TRNS_INDEX;
			}
		}
	}
	else
	if(color_type == PNG_COLOR_TYPE_RGB)
	{
		if(bit_depth > 8)
		 png_set_strip_16(png_ptr); // reduce to 8bits per colour

		png_set_bgr(png_ptr);

		// 24 bits per pixel, no palette
		Info.BitCount = 24;
		Info.PNGColorType = PNG_TYPE_RGB;
		PixelMultiplier = 3;
		Divide = false;
		DoRead = true;

		if((info_ptr->valid & PNG_INFO_tRNS) != 0)
		{
			png_color_16p trans_values = NULL;

			png_get_tRNS(png_ptr,info_ptr,NULL,NULL,&trans_values);

			if(trans_values != NULL)
			{
				Info.Trns = PNG_TRNS_COLOR;

				if(bit_depth < 16)
				{
					Info.TrnsColor = 0xFF000000;
					Info.TrnsColor |= ((unsigned char) trans_values->red) << 16;
					Info.TrnsColor |= ((unsigned char) trans_values->green) << 8;
					Info.TrnsColor |= ((unsigned char) trans_values->blue);
				}
				else
				{
					Info.TrnsColor = 0xFF000000;
					Info.TrnsColor |= ((unsigned char) (trans_values->red >> 8)) << 16;
					Info.TrnsColor |= ((unsigned char) (trans_values->green >> 8)) << 8;
					Info.TrnsColor |= ((unsigned char) (trans_values->blue >> 8));
				}
			}
		}
	}
	else
	if(color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	{
		if(bit_depth > 8)
		 png_set_strip_16(png_ptr); // reduce to 8bits per colour

		png_set_bgr(png_ptr);

		// 32 bits per pixel ARGB, no palette
		Info.BitCount = 32;
		Info.PNGColorType = PNG_TYPE_ALPHA;
		PixelMultiplier = 4;
		Divide = false;
		DoRead = true;
	}
	else
	if(color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
	{
		if(bit_depth > 8)
		 png_set_strip_16(png_ptr); // reduce to 8bits per colour

		png_set_strip_alpha(png_ptr);

		// 8 bits per pixel, no palette
		Info.BitCount = 8;
		Info.PNGColorType = PNG_TYPE_GREY;
		PixelMultiplier = 1;
		Divide = false;
		CreatePalette = true;
		PaletteSize = 256;
		DoRead = true;
	}

	unsigned long OutSize;
	void* pOutBuf;
	if(DoRead)
	{
		void* pPalette = NULL;
		void* pPixel = NULL;

		if(Divide)
		{
			Info.LineSize = (Info.XDim / PixelMultiplier);
			if((Info.XDim % PixelMultiplier) != 0)
			 Info.LineSize++;
		}
		else
		 Info.LineSize = (Info.XDim * PixelMultiplier);

		char Rem = (char) (Info.LineSize % 4);
		if(Rem != 0)
		 Info.LineSize += (4 - Rem);

		OutSize = Info.LineSize * Info.YDim;

		if(CreatePalette || UsePalette)
		 OutSize += (PaletteSize * 4);

		pOutBuf = img_malloc(OutSize);

		if(CreatePalette || UsePalette)
		{
			pPalette = pOutBuf;
			pPixel = &(((char*)pOutBuf)[PaletteSize * 4]);
		}
		else
		 pPixel = pOutBuf;

		unsigned long row;
		png_bytep* ppRowPtrs = (png_bytep*) img_malloc(sizeof(png_bytep) * Info.YDim);
		for(row=0;row<Info.YDim;row++)
		 ppRowPtrs[(Info.YDim - 1) - row] = &(((unsigned char*)pPixel)[row * Info.LineSize]);

		png_read_image(png_ptr,ppRowPtrs);

		img_free(ppRowPtrs);

		if(CreatePalette)
		{
			unsigned long Index;
			for(Index=0;Index<PaletteSize;Index++)
			{
				unsigned char PalVal = (unsigned char) ((((unsigned long)255) / (PaletteSize - 1)) * Index);

				((unsigned char*)pPalette)[(Index * 4) + 0] = (unsigned char) PalVal;
				((unsigned char*)pPalette)[(Index * 4) + 1] = (unsigned char) PalVal;
				((unsigned char*)pPalette)[(Index * 4) + 2] = (unsigned char) PalVal;
				((unsigned char*)pPalette)[(Index * 4) + 3] = 0xFF;
			}
		}
		else
		if(UsePalette)
		{
			void* pPNGPalette = info_ptr->palette;

			unsigned long Index;
			for(Index=0;Index<PaletteSize;Index++)
			{
				unsigned long Ptr = (Index & SrcPaletteMask);
				((unsigned char*)pPalette)[(Index * 4) + 0] = ((unsigned char*)pPNGPalette)[(Ptr * 3) + 2];
				((unsigned char*)pPalette)[(Index * 4) + 1] = ((unsigned char*)pPNGPalette)[(Ptr * 3) + 1];
				((unsigned char*)pPalette)[(Index * 4) + 2] = ((unsigned char*)pPNGPalette)[(Ptr * 3) + 0];
				((unsigned char*)pPalette)[(Index * 4) + 3] = 0xFF;
			}
		}
	}

	png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);

	if(!DoRead)
	{
		img_free(pBuf);
		BufSz = 0;
	}
	else
	{
		img_free(pBuf);
		pBuf = pOutBuf;
		BufSz = OutSize;
	}
}
Copyright © Solid Fluid 2007-2015
Last modified: SolFlu  Sun, 14 Jun 2009 09:23:37 GMT