Code Search for Developers
 
 
  

neoicpng.cpp from NeoEngineNG at Krugle


Show neoicpng.cpp syntax highlighted

/***************************************************************************
                         neoicpng.cpp  -  description
                             -------------------
    begin                : Fri Aug 23 2002
    copyright            : (C) 2002 by Mattias Jansson
    email                : mattias@realityrift.com
 ***************************************************************************

 The contents of this file are subject to the Mozilla Public License Version
 1.1 (the "License"); you may not use this file except in compliance with
 the License. You may obtain a copy of the License at 
 http://www.mozilla.org/MPL/

 Software distributed under the License is distributed on an "AS IS" basis,
 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 for the specific language governing rights and limitations under the
 License.

 The Original Code is the NeoEngine, NeoICPNG, neoicpng.cpp

 The Initial Developer of the Original Code is Mattias Jansson.
 Portions created by Mattias Jansson are Copyright (C) 2002
 Reality Rift Studios. All Rights Reserved.

 ***************************************************************************/

#include "neoicpng.h"
#include "link.h"
#include "png.h"

#include <neoengine/file.h>
#include <neoengine/logstream.h>

#include <string.h>

using namespace std;
using namespace NeoEngine;


namespace NeoPNG
{

#define PNGEXPORT
	ModuleStatic *g_pkStaticModule = 0;

	PNGEXPORT ImageCodec *LoadImageCodec()
	{
		vector<string> vstrExtensions;

		vstrExtensions.push_back( "png" );
		vstrExtensions.push_back( "PNG" );

		ImageCodec *pkCodec = new NeoPNG::ImageCodec( vstrExtensions );

		return pkCodec;
	}

	PNGEXPORT int Initialize()
	{
		return 0;
	}

	PNGEXPORT int Shutdown()
	{
		delete g_pkStaticModule;
		return 0;
	}

	PNGEXPORT void GetVersion( std::string *pstrName, int *piMajor, int *piMinor, int *piRevision )
	{
		*pstrName   = "NeoICPNG";
		*piMajor    = NEOENGINEVERSION_MAJOR;
		*piMinor    = NEOENGINEVERSION_MINOR;
		*piRevision = NEOENGINEVERSION_REVISION;
	}

	//Read data from file, callback to PNG lib
	void read_file_data( png_struct *pPng, png_bytep pucData, png_size_t iNum )
	{
		File *pkFile = (File*)png_get_io_ptr( pPng );

		pkFile->Read( pucData, iNum );
	}



	ImageCodec::ImageCodec( const vector<string> &rvstrExtensions ) :
		NeoEngine::ImageCodec( "PNG Image File", rvstrExtensions )
	{
		neolog << LogLevel( INFO ) << "Loading PNG image codec" << endl << "  Based on the libpng library, copyright (C) 2000-2002 Glenn Randers-Pehrson" << endl << "  For license details, see the README" << endl;
	}


	ImageCodec::~ImageCodec()
	{
	}


#define PNG_BYTES_TO_CHECK 4

	bool ImageCodec::IsType( File *pkFile )
	{
		//Set file mode and read ptr to start of file
		bool bBinary = pkFile->SetBinary( true );
		int  iOffset = pkFile->Tellg();

		if( iOffset != 0 )
			pkFile->Seekg( 0, ios_base::beg );

		char acBuf[ 8 ];

		//Read in signature bytes
		pkFile->Read( acBuf, 8 );

		//Restore file ptr and mode
		pkFile->Seekg( iOffset, ios_base::beg );
		pkFile->SetBinary( bBinary );

		if( png_sig_cmp( (png_byte*)acBuf, (png_size_t)0, 8 ) )
		{
			//neolog << LogLevel( ERROR ) << "*** Unable to read PNG image: Invalid signature" << endl;
			return false;
		}

		return true;
	}


	ImageData *ImageCodec::LoadImage( File *pkFile )
	{
		bool bBinary = pkFile->SetBinary( true );
		int  iOffset = pkFile->Tellg();

		if( iOffset != 0 )
			pkFile->Seekg( 0, ios_base::beg );

		png_structp png_ptr = 0;
		png_infop info_ptr  = 0;

		ImageData *pkImage = 0;
		int iWidth, iHeight;
		int iChannels, iColorType, iBitDepth;
		int i,j,iRow;

		png_bytep *ppucRowPointers = NULL;

		/* Create and initialize the png_struct with the desired error handler
		 * functions.  If you want to use the default stderr and longjump method,
		 * you can supply NULL for the last three parameters.  We also supply the
		 * the compiler header file version, so that we know if the application
		 * was compiled with a compatible version of the library.  REQUIRED
		 */
		if( !( png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ) ) )
		{
			neolog << LogLevel( ERROR ) << "*** Unable to read PNG image: Failed to create PNG struct" << endl;
			goto CLEANUP;
		}

		if( !( info_ptr = png_create_info_struct( png_ptr ) ) )
		{
			neolog << LogLevel( ERROR ) << "*** Unable to read PNG image: Failed to create info struct" << endl;
			goto CLEANUP;
		}



		/* Set error handling if you are using the setjmp/longjmp method (this is
		 * the normal method of doing things with libpng).  REQUIRED unless you
		 * set up your own error handlers in the png_create_read_struct() earlier.
		 */
		if( setjmp( png_jmpbuf( png_ptr) ) )
		{
			neolog << LogLevel( ERROR ) << "*** Unable to read PNG image: setjmp failed" << endl;
			goto CLEANUP;
		}

		/* If you are using replacement read functions, instead of calling
		 * png_init_io() here you would call:
		 * (where user_io_ptr is a structure you want available to the callbacks)
		 */
		png_set_read_fn( png_ptr, (void*)pkFile, read_file_data );

		/* The call to png_read_info() gives us all of the information from the
		 * PNG file before the first IDAT (image data chunk).  REQUIRED
		 */
		png_read_info( png_ptr, info_ptr );


		iWidth  = png_get_image_width( png_ptr, info_ptr );
		iHeight = png_get_image_height( png_ptr, info_ptr );

		iColorType = png_get_color_type( png_ptr, info_ptr );
		iChannels  = ( iColorType == PNG_COLOR_TYPE_RGB_ALPHA ) ? 4 : 3;
		iBitDepth  = png_get_bit_depth( png_ptr, info_ptr );

		if( iColorType == PNG_COLOR_TYPE_PALETTE )
		{
			iChannels  = 3;
			iColorType = PNG_COLOR_TYPE_RGB;

			png_set_palette_to_rgb( png_ptr );
		}

		if( ( iColorType == PNG_COLOR_TYPE_GRAY ) && ( iBitDepth < 8 ) )
			png_set_gray_1_2_4_to_8( png_ptr );

		/* We now read grayscale images as alpha */
		if( iColorType == PNG_COLOR_TYPE_GRAY )
		{
			iChannels  = 1;

			//iColorType = PNG_COLOR_TYPE_RGB;

			//png_set_gray_to_rgb( png_ptr );
		}

		if( iColorType == PNG_COLOR_TYPE_GRAY_ALPHA )
		{
			iChannels  = 4;
			iColorType = PNG_COLOR_TYPE_RGB_ALPHA;

			png_set_gray_to_rgb( png_ptr );
		}

		if( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
		{
			iChannels  = 4;
			iColorType = PNG_COLOR_TYPE_RGB_ALPHA;

			png_set_tRNS_to_alpha( png_ptr );
		}

		if( iBitDepth == 16 )
			png_set_strip_16( png_ptr );



		if( ( iColorType != PNG_COLOR_TYPE_RGB ) && ( iColorType != PNG_COLOR_TYPE_RGB_ALPHA ) && ( iColorType != PNG_COLOR_TYPE_GRAY ) )
		{
			neolog << LogLevel( ERROR ) << "*** Unable to read PNG image: Invalid color type" << endl;
			goto CLEANUP;
		}

		if( iBitDepth != 8 )
		{
			neolog << LogLevel( ERROR ) << "*** Unable to read PNG image: Unsupported channel bit depth" << endl;
			goto CLEANUP;
		}

		//now read the image data

		/* Optional call to gamma correct and add the background to the palette
		 * and update info structure.  REQUIRED if you are expecting libpng to
		 * update the palette for you (ie you selected such a transform above).
		 */
		png_read_update_info( png_ptr, info_ptr );

		/* The easiest way to read the image: */
		ppucRowPointers = new png_bytep[ iHeight ];

		for( iRow = 0; iRow < iHeight; iRow++ )
			ppucRowPointers[ iRow ] = (png_bytep) png_malloc( png_ptr, png_get_rowbytes( png_ptr, info_ptr ) );

		/* Now it's time to read the image */
		png_read_image( png_ptr, ppucRowPointers );

		/* read rest of file, and get additional chunks in info_ptr - REQUIRED */
		png_read_end( png_ptr, info_ptr );


		pkImage = new ImageData;

		pkImage->m_eFormat = ( iColorType == PNG_COLOR_TYPE_GRAY ) ? Texture::ALPHA : ( ( iColorType == PNG_COLOR_TYPE_RGB ) ? Texture::RGB : Texture::RGBA );
		pkImage->m_iWidth    = iWidth;
		pkImage->m_iHeight   = iHeight;
		pkImage->m_iChannels = iChannels;
		pkImage->m_iBPP      = iBitDepth * iChannels;
		pkImage->m_pucData   = new unsigned char[ iWidth * iHeight * iChannels ];

		for( j = 0; j < int( iHeight ); ++j )
			for( i = 0; i < int( iWidth * iChannels ); ++i )
				pkImage->m_pucData[ j * iWidth * iChannels + i ] = (ppucRowPointers[j])[i];


		CLEANUP:

		// clean up after the read, and free any memory allocated - REQUIRED
		for( iRow = 0; iRow < iHeight; iRow++ )
			png_free( png_ptr, ppucRowPointers[ iRow ] );

		png_destroy_read_struct( &png_ptr, &info_ptr, png_infopp_NULL );

		delete [] ppucRowPointers;

		pkFile->Seekg( iOffset, ios_base::beg );
		pkFile->SetBinary( bBinary );

		return pkImage;
	}


	void ImageCodec::FreeImage( ImageData *pkImageData )
	{
		if( pkImageData )
		{
			if( pkImageData->m_pucData )
				delete [] pkImageData->m_pucData;
			pkImageData->m_pucData = 0;

			delete pkImageData;
		}
	}

	static void png_save_to_callback_flush_func (png_structp png_ptr)
	{
			;
	}

	static void png_save_to_callback_write_func (png_structp pkPng,
									 png_bytep   pData,
									 png_size_t  iLength )
	{
		File *pkFile = (File*) png_get_io_ptr( pkPng );

		pkFile->Write( pData, (int)iLength );
	}

	static void png_simple_warning_callback( png_structp pkSave, png_const_charp msg )
	{
		// Don't print anything.
	}

	static void png_simple_error_callback( png_structp pkSave, png_const_charp msg )
	{
		neolog << LogLevel( WARNING ) << "Error while writing PNG file: " << msg << endl;
	}

	bool ImageCodec::WriteImage( ImageData *pkImageData, File *pkFile )
	{
		png_color_8 sig_bit;

		pkFile->SetBinary( true );

		png_structp pkPng = png_create_write_struct( PNG_LIBPNG_VER_STRING,
													 0,
													 png_simple_error_callback,
													 png_simple_warning_callback );

		if( !pkPng )
		{
			neolog << LogLevel( ERROR ) << "Failed to create PNG write struct!" << endl;
			return false;
		}

		png_infop pkInfo = png_create_info_struct( pkPng );

		if( !pkInfo )
		{
			neolog << LogLevel( ERROR ) << "Failed to create PNG info struct!" << endl;
			return false;
		}

		png_set_write_fn( pkPng, pkFile,
						  png_save_to_callback_write_func,
						  png_save_to_callback_flush_func );

		int iFormat;

		switch( pkImageData->m_eFormat )
		{
			case Texture::RGB:
				iFormat = PNG_COLOR_TYPE_RGB;
				break;

			case Texture::RGBA:
				iFormat = PNG_COLOR_TYPE_RGBA;
				break;

			case Texture::ALPHA:
				neolog << "PNG write (Texture::ALPHA) not implemented yet.. FIXME!!" << endl;
				return false;
				break;

			case Texture::GRAY:
				iFormat = PNG_COLOR_TYPE_GRAY;
				break;

			case Texture::GRAYALPHA:
				iFormat = PNG_COLOR_TYPE_GRAY_ALPHA;
				break;

			default:
				break;
		}

		/* Bits per channel */
		int iBPC = pkImageData->m_iBPP / pkImageData->m_iChannels;

		png_set_IHDR( pkPng, pkInfo, pkImageData->m_iWidth, pkImageData->m_iHeight, iBPC,
					  PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
					  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );

		sig_bit.red   = iBPC;
		sig_bit.green = iBPC;
		sig_bit.blue  = iBPC;
		sig_bit.alpha = iBPC;
		png_set_sBIT( pkPng, pkInfo, &sig_bit );
		png_write_info( pkPng, pkInfo );
		png_set_shift( pkPng, &sig_bit );
		png_set_packing( pkPng );

		int iHeight = pkImageData->m_iHeight;
		int iRowstride = pkImageData->m_iWidth * pkImageData->m_iChannels;

		unsigned char *pucData = pkImageData->m_pucData;
		png_bytep pRow;

		for( int y = 0; y < iHeight; y++ )
		{
			pRow = (png_bytep) pucData;
			png_write_rows( pkPng, &pRow, 1 );
			pucData += iRowstride;
		}

		png_write_end( pkPng, pkInfo );

		png_destroy_write_struct( &pkPng, &pkInfo );

		return true;
	}

	Link::Link()
	{
#if defined(WIN32) && defined(_DEBUG)
		g_pkStaticModule = new ModuleStatic( "neoicpng_debug" );
#else
		g_pkStaticModule = new ModuleStatic( "neoicpng" );
#endif

		g_pkStaticModule->m_Symbols.Insert( "LoadImageCodec", (void**)LoadImageCodec );
		g_pkStaticModule->m_Symbols.Insert( "GetVersion",     (void**)GetVersion     );
		g_pkStaticModule->m_Symbols.Insert( "Initialize",     (void**)Initialize     );
		g_pkStaticModule->m_Symbols.Insert( "Shutdown",       (void**)Shutdown       );

		NeoEngine::Core::GetModuleManager()->InsertModule( g_pkStaticModule );
	}

}; // namespace NeoPNG




See more files for this project here

NeoEngineNG

NeoenEngine NG (Next Generation) is the evolution of neoengine one,it\'s a different development from NeoEngine2, it\'s a direct inherits from NeoEngine one.\n

Project homepage: http://sourceforge.net/projects/neoengineng
Programming language(s): C,C++
License: other

  LICENSE
  Makefile.am
  SConscript
  adler32.c
  crc32.c
  deflate.c
  deflate.h
  infblock.c
  infblock.h
  infcodes.c
  infcodes.h
  inffast.c
  inffast.h
  inffixed.h
  inflate.c
  inftrees.c
  inftrees.h
  infutil.c
  infutil.h
  link.h
  neoicpng-static.dev
  neoicpng.cbp
  neoicpng.cpp
  neoicpng.dev
  neoicpng.dsp
  neoicpng.h
  neoicpng.layout
  neoicpng.vcproj
  png.c
  png.h
  pngasmrd.h
  pngconf.h
  pngerror.c
  pnggccrd.c
  pngget.c
  pngmem.c
  pngpread.c
  pngread.c
  pngrio.c
  pngrtran.c
  pngrutil.c
  pngset.c
  pngtest.c
  pngtrans.c
  pngvcrd.c
  pngwio.c
  pngwrite.c
  pngwtran.c
  pngwutil.c
  trees.c
  trees.h
  zconf.h
  zlib.h
  zutil.c
  zutil.h