
#include	"stdafx.h"
#include	"../ExtractBase.h"
#include	"Png.h"

//////////////////////////////////////////////////////////////////////////////////////////
//	コンストラクタ

CPng::CPng()
{
	m_pstPNG = NULL;
	m_pstPNGInfo = NULL;
	m_nCompressLevel = 1;
	m_dwMode = 0;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	デストラクタ

CPng::~CPng()
{
	Close();
}

//////////////////////////////////////////////////////////////////////////////////////////
//	圧縮率の設定

void	CPng::SetCompressLevel(
	int					nCompressLevel					// 圧縮レベル
	)
{
	m_nCompressLevel = nCompressLevel;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	圧縮率の取得
//
//	return	圧縮レベル

int		CPng::GetCompressLevel()
{
	return	m_nCompressLevel;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	コールバック関数の設定

void	CPng::SetCallback(
	
	)
{

}

//////////////////////////////////////////////////////////////////////////////////////////
//	モードの設定

void	CPng::SetMode(
	DWORD				dwMode							// モード
	)
{
	m_dwMode = dwMode;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	モードの取得
//
//	return	モード

DWORD	CPng::GetMode()
{
	return	m_dwMode;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	PNG構造体の解放

void	CPng::Close()
{
	if( m_pstPNG != NULL )
	{
		switch( GetMode() )
		{
		case	modeRead:
			// 読み込みモード
/*
			if( m_pstPNGInfo != NULL )
			{
				png_read_end( m_pstPNG, m_pstPNGInfo );
				png_destroy_read_struct( &m_pstPNG, &m_pstPNGInfo, NULL );
			}
			else
			{
				png_destroy_read_struct( &m_pstPNG, NULL, NULL );
			}
*/
			break;

		case	modeWrite:
			// 書き込みモード

			if( m_pstPNGInfo != NULL )
			{
				png_write_end( m_pstPNG, m_pstPNGInfo );
				png_destroy_write_struct( &m_pstPNG, &m_pstPNGInfo );
			}
			else
			{
				png_destroy_write_struct( &m_pstPNG, NULL );
			}

			break;
		}

		m_pstPNG = NULL;
		m_pstPNGInfo = NULL;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////
//	BMPからPNGに変換

BOOL	CPng::Compress(
	LPCTSTR				pszPathToDst,					// 出力先ファイルパス
	const void*			pvBMP,							// ビットマップデータ
	DWORD				dwBMPSize						// ビットマップデータサイズ
	)
{

	return	TRUE;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	DIBからPNGに変換

BOOL	CPng::Compress(
	LPCTSTR				pszPathToDst,					// 出力先ファイルパス
	const void*			pvDIB,							// DIBデータ
	DWORD				dwDIBSize,						// DIBデータサイズ
	const void*			pvPallet,						// パレット
	DWORD				dwPalletSize,					// パレットサイズ
	WORD				wPalletBpp,						// パレットのビット数
	long				lWidth,							// 横幅
	long				lHeight,						// 縦幅
	WORD				wBpp							// ビット数
	)
{
	return	TRUE;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	BMPからPNGに変換

BOOL	CPng::Compress(
	void*				pvDst,							// 格納先
	DWORD				dwDstSize,						// 格納先サイズ
	const void*			pvBMP,							// ビットマップデータ
	DWORD				dwBMPSize						// ビットマップデータサイズ
	)
{


	return	TRUE;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	DIBからPNGに変換

BOOL	CPng::Compress(
	void*				pvDst,							// 格納先
	DWORD				dwDstSize,						// 格納先サイズ
	const void*			pvDIB,							// DIBデータ
	DWORD				dwDIBSize,						// DIBデータサイズ
	const void*			pvPallet,						// パレット
	DWORD				dwPalletSize,					// パレットサイズ
	WORD				wPalletBpp,						// パレットのビット数
	long				lWidth,							// 横幅
	long				lHeight,						// 縦幅
	WORD				wBpp							// ビット数
	)
{
/*	BYTE*				pbtDst = (BYTE*) pvDst;
	const BYTE*			pbtDIB = (const BYTE*) pvDIB;
	const BYTE*			pbtPallet = (const BYTE*) pvPallet;

	// モードの設定

	SetMode( modeWrite );

	// カラータイプの取得

	int					nColorType;

	switch( wBpp )
	{
		case	8:
			// 8bit

			nColorType = PNG_COLOR_TYPE_PALETTE;
			break;

		case	24:
			// 24bit

			nColorType = PNG_COLOR_TYPE_RGB;
			break;

		case	32:
			// 32bit

			nColorType = PNG_COLOR_TYPE_RGB_ALPHA;
			break;

		default:
			// その他

			return	FALSE;
	}

	// PNG構造体の作成

	m_pstPNG = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );

	if( m_pstPNG == NULL )
	{
		return	FALSE;
	}

	// PNG情報構造体の作成

	m_pstPNGInfo = png_create_info_struct( m_pstPNG );

	if( m_pstPNGInfo == NULL )
	{
		return	FALSE;
	}

	// パラメータの設定

	SMemory				stmDst;

	stmDst.pbtData = pbtDst;
	stmDst.dwDataPtr = 0;

	png_set_write_fn( m_pstPNG, &stmDst, WritePNGToMemory, NULL );

	png_set_bgr( m_pstPNG );
	png_set_compression_level( m_pstPNG, GetCompressLevel() );

	if( wBpp == 8 )
	{
		png_set_PLTE( m_pstPNG, m_pstPNGInfo, m_astPallet, 256 );
	}

	png_set_IHDR( m_pstPNG, m_pstPNGInfo, lWidth, lHeight, 8, nColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );

	// PNGヘッダの出力

	png_write_info( m_pstPNG, m_pstPNGInfo );

	// PNGデータの出力

	if( IsRequireAlphaBlend() )
	{
		// アルファブレンド要求あり

		long				lPitch = CalculatePitch( lWidth, wBpp );
		YCMemory<BYTE>		clmAlphaBlendBuffer( lPitch );

		for( long lY = 0 ; lY < lHeight ; lY++ )
		{
			AlphaBlend( &clmAlphaBlendBuffer[0], &pbtDIB[lY * lPitch] );

			png_write_row( m_pstPNG, &clmAlphaBlendBuffer[0] );
		}
	}
	else
	{
		// アルファブレンド要求なし

		long				lPitch = CalculatePitch( lWidth, wBpp );

		for( long lY = 0 ; lY < lHeight ; lY++ )
		{
			png_write_row( m_pstPNG, &pbtDIB[lY * lPitch] );
		}
	}
*/
	return	TRUE;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	DIBに変換

BOOL	CPng::Decompress()
{
	return	TRUE;
}






//////////////////////////////////////////////////////////////////////////////////////////
//	初期化

BOOL	CPng::OnInit(
	const YCString&		rfclsFileName					// ファイル名
	)
{
	int					nColorType;

	switch( m_wBpp )
	{
		case	8:
			// 8bit

			nColorType = PNG_COLOR_TYPE_PALETTE;
			break;

		case	24:
			// 24bit

			nColorType = PNG_COLOR_TYPE_RGB;
			break;

		case	32:
			// 32bit

			nColorType = PNG_COLOR_TYPE_RGB_ALPHA;
			break;

		default:
			// その他

			return	FALSE;
	}

	m_png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );

	if( m_png_ptr == NULL )
	{
		return	FALSE;
	}

	m_info_ptr = png_create_info_struct( m_png_ptr );

	if( m_info_ptr == NULL )
	{
		png_destroy_write_struct( &m_png_ptr, NULL );
		return	FALSE;
	}

	png_set_write_fn( m_png_ptr, m_pclArc, WritePNG, NULL );

	png_set_bgr( m_png_ptr );
	png_set_compression_level( m_png_ptr, m_pclArc->GetOpt()->CmplvPng );

	if( m_wBpp == 8 )
	{
		png_set_PLTE( m_png_ptr, m_info_ptr, m_astPallet, 256 );
	}

	png_set_IHDR( m_png_ptr, m_info_ptr, m_lWidth, m_lHeight, 8, nColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );

	// 出力ファイルを開く

	m_pclArc->OpenFile( rfclsFileName );

	// ヘッダの出力

	png_write_info( m_png_ptr, m_info_ptr );

	return	TRUE;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	パレットの作成

BOOL	CPng::OnCreatePallet(
	const void*			pvSrcPallet,					// 参照元パレット
	DWORD				dwSrcPalletSize					// 参照元パレットのサイズ
	)
{
	png_colorp			pstPallet = m_astPallet;
	const BYTE*			pbtSrcPallet = (const BYTE*) pvSrcPallet;

	ZeroMemory( m_astPallet, sizeof(m_astPallet) );

	if( pbtSrcPallet == NULL )
	{
		// デフォルトのパレットを使用(グレースケール)

		for( int i = 0 ; i < 256 ; i++ )
		{
			pstPallet[i].blue = i;
			pstPallet[i].green = i;
			pstPallet[i].red = i;
		}
	}
	else
	{
		// パレットを参照

		if( dwSrcPalletSize == 1024 )
		{
			// 1024バイトのパレット

			for( int i = 0 ; i < 256 ; i++ )
			{
				pstPallet[i].blue = *pbtSrcPallet++;
				pstPallet[i].green = *pbtSrcPallet++;
				pstPallet[i].red = *pbtSrcPallet++;
				pbtSrcPallet++;
			}
		}
		else if( dwSrcPalletSize == 768 )
		{
			// 768バイトのパレット(アルファなし)

			for( int i = 0 ; i < 256 ; i++ )
			{
				pstPallet[i].blue = *pbtSrcPallet++;
				pstPallet[i].green = *pbtSrcPallet++;
				pstPallet[i].red = *pbtSrcPallet++;
			}
		}
		else
		{
			// その他のサイズのパレット

			for( int i = 0 ; i < dwSrcPalletSize / 4 ; i++ )
			{
				pstPallet[i].blue = *pbtSrcPallet++;
				pstPallet[i].green = *pbtSrcPallet++;
				pstPallet[i].red = *pbtSrcPallet++;
				pbtSrcPallet++;
			}
		}
	}

	return	TRUE;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	1ライン書き込み

void	CPng::WriteLine(
	const void*			pvBuffer						// データ
	)
{
	png_write_row( m_png_ptr, (png_bytep) pvBuffer );
	m_pclArc->GetProg()->UpdatePercent( m_dwRowSize );
}

//////////////////////////////////////////////////////////////////////////////////////////
//	アルファブレンディングして1ライン書き込み

void	CPng::WriteLineWithAlphaBlend(
	void*				pvBuffer24,						// 格納先
	const void*			pvBuffer32						// 32bitデータ
	)
{
	// アルファブレンディング

	AlphaBlend( pvBuffer24, pvBuffer32 );

	png_write_row( m_png_ptr, (png_bytep) pvBuffer24 );
	m_pclArc->GetProg()->UpdatePercent( m_dwRowSize );
}

//////////////////////////////////////////////////////////////////////////////////////////
//	出力終了

void	CPng::OnWriteFinish()
{
	png_write_end( m_png_ptr, m_info_ptr );
	png_destroy_write_struct( &m_png_ptr, &m_info_ptr );
}

//////////////////////////////////////////////////////////////////////////////////////////
//	PNG出力

void	CPng::WritePNG(
	png_structp			png_ptr,
	png_bytep			data,
	png_size_t			length
	)
{
	CArcFile*			pclArc = (CArcFile*) png_get_io_ptr( png_ptr );

	pclArc->WriteFile( data, length, 0 );
}

//////////////////////////////////////////////////////////////////////////////////////////
//	ファイルに出力

void	CPng::WritePNGToFile(
	png_struct*			pstPNG,
	png_byte*			pbtData,
	png_size_t			siLength
	)
{
	YCFile*				pclfDst = (YCFile*) png_get_io_ptr( pstPNG );

	pclfDst->Write( pbtData, siLength );
}

//////////////////////////////////////////////////////////////////////////////////////////
//	メモリに出力

void	CPng::WritePNGToMemory(
	png_struct*			pstPNG,
	png_byte*			pbtData,
	png_size_t			siLength
	)
{
	SMemory*			pstmDst = (SMemory*) png_get_io_ptr( pstPNG );

	memcpy( &pstmDst->pbtData[pstmDst->dwDataPtr], pbtData, siLength );

	pstmDst->dwDataPtr += siLength;
}
