PNGの読み込みのエラー

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
とにー

PNGの読み込みのエラー

#1

投稿記事 by とにー » 9年前

pngファイルを読み込む処理を作ったのですが最後の方のpng_destroy_read_struct
の中でExpression:_CrtIsValidHeapPointerのエラーが起きてしまいます。
どこがおかしいのか教えてください。
libpng1.6.5 とzlib1.2.8を使っています。
Visual studio2013 を使っています。
OSは Windows7 Professionalです。

コード:

bool PngLoad::loadPngFileTexture( Texture* texture, const char* fileName )
{
	FILE *fp;
	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 width;
	png_uint_32 height;
	int bit_depth;
	int color_type;
	int interlace_type;
	png_byte** image;
	png_bytep tex_image;

	//ファイルを開く

	fopen_s( &fp, fileName, "rb" );
	if( !fp )
    {
		DEBUG_LOG("%s ファイルが開けませんでした。",fileName);
		return ERROR;
    }
	//png_ptr構造体を確保・初期化
	png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
	//確保・初期化に失敗したら
	if( !png_ptr )
	{
	    //ファイルを閉じる
		fclose( fp );
	    return false;
	}
	//info_ptr構造体を確保・初期化
	info_ptr = png_create_info_struct( png_ptr );
	//確保・初期化に失敗したら
	if( !info_ptr )
	{
		//構造体のメモリを解放
		png_destroy_read_struct( &png_ptr, (png_infopp)NULL, (png_infopp)NULL);
	    //ファイルを閉じる
		fclose( fp );
	    return false;
	}
	//libpngにfpを知らせる
	png_init_io( png_ptr, fp );
	//PNGファイルのヘッダを読み込む
	png_read_info( png_ptr, info_ptr );
	//IHDRチャンク情報を取得
	png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL );

	float screen_gamma = 2.2f;
    double image_gamma;
    int intent;

    if( png_get_sRGB( png_ptr, info_ptr, &intent ) )
    {
        png_set_gamma( png_ptr, screen_gamma, 0.45455 );
    }
	else if( png_get_gAMA( png_ptr, info_ptr, &image_gamma ) )
    {
        png_set_gamma( png_ptr, screen_gamma, image_gamma );
    }

	if( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
	{
		//グレイスケール画像をRGB形式に変換
		png_set_gray_to_rgb(png_ptr);
	}

	if( color_type == PNG_COLOR_TYPE_PALETTE )
	{
		//パレット付き画像をRGB形式に変換
		png_set_palette_to_rgb(png_ptr);
	}
	if( bit_depth < 8 )
	{
		//各要素8ビットに拡張
		png_set_packing( png_ptr );
	}
	if( bit_depth < 8 )
	{
		//各要素8ビットに縮小
		png_set_strip_16( png_ptr );
	}

	//tRNSチャンクがあれば
	if( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
	{
		//tRNSチャンクをアルファチャンネルに変換
		png_set_tRNS_to_alpha( png_ptr );
	}
	else if( !( color_type & PNG_COLOR_MASK_ALPHA ) )
	{
		// 不透明で埋めた完全なアルファチャンネルを追加
		png_set_add_alpha( png_ptr, 0xff, PNG_FILLER_AFTER);
	}

	png_read_update_info( png_ptr, info_ptr );
	
	//メモリを確保する
	texture->inisialize( TEX_RGBA, width, height );
	tex_image = (png_bytep)texture->lockTexture();
	
	image = (png_bytep*)malloc( sizeof( unsigned int ) * height * width );
	
	for( unsigned int i = 0 ; i < height ; i++ )
	{
		image[i] = &tex_image[i * width * sizeof(unsigned int)];
	}
	
	png_read_image( png_ptr, image );
	
	free( image );

	png_read_end(png_ptr, info_ptr);
	//構造体のメモリを解放
	png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp)NULL);
	//ファイルを閉じる
	fclose( fp );
	return true;
}

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: PNGの読み込みのエラー

#2

投稿記事 by h2so5 » 9年前

texture->inisializeとtexture->lockTextureの中はどうなっていますか?

とにー

Re: PNGの読み込みのエラー

#3

投稿記事 by とにー » 9年前

これがinisializeです。

コード:

void Texture::inisialize(TextureFormat format,int width,int height)
{
	unsigned int size;

	/* テクチャのクリーンアップ */
	clear();

	/* テクスチャフォーマットの設定 */
	m_Param.Format = format;

	/* イメージサイズを求める */
	if((size = sizeof(unsigned int) * width * height) == 0)
	{
		return;
	}

	/* テクスチャの幅と高さを設定 */
	m_Param.dwWidth  = width;
	m_Param.dwHeight = height;

	/* テクスチャイメージの生成*/
	m_Param.pImage = malloc(sizeof(unsigned int) * width * height);
	/* 初期設定では白 */
	memset(m_Param.pImage,0xff,size);

	m_Param.isRegistration = false;
}

コード:

void* Texture::lockTexture()
{
	return m_Param.pImage;
}
初期化で使っているclearはこれです

コード:

void Texture::clear()
{
	/* テクチャイメージの削除 */
	if(m_Param.pImage != NULL)
	{
		delete m_Param.pImage;
		/* テクスチャオブジェクトの削除 */
		glDeleteTextures(1,&m_Param.dwTexName);
	}
	m_Param.Format    = TEX_RGBA;
	m_Param.dwWidth   = 0;
	m_Param.dwHeight  = 0;
	m_Param.pImage    = NULL;
	m_Param.dwTexName = 0;
}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: PNGの読み込みのエラー

#4

投稿記事 by みけCAT » 9年前

(No:1だけに対するレスポンス)

とりあえずg++ 4.8.1でコンパイルできるようにしてlipng 1.6.3、zlib1.2.8で実験した所、エラーは発生しませんでした。
78行目の不等号の向きが逆かもしれないと思いましたが、depthが0x10のpngファイルを入力してもエラーは発生しませんでした。

コード:

#include <png.h>
#include <cstdio>
#include <cstdlib>

void fopen_s(FILE** fp,const char *f,const char *t) {
	*fp=fopen(f,t);
}

#define DEBUG_LOG printf

const bool ERROR=false;
const int TEX_RGBA=0;

struct Texture {
	char* p;
	Texture():p(NULL){}
	~Texture(){if(p!=NULL)delete[] p;}
	void inisialize(int a,int w,int h) {
		p=new char[w*h*4];
	}
	char* lockTexture(){return p;}
};

struct PngLoad {
	static bool loadPngFileTexture( Texture* texture, const char* fileName );
};

bool PngLoad::loadPngFileTexture( Texture* texture, const char* fileName )
{
	FILE *fp;
	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 width;
	png_uint_32 height;
	int bit_depth;
	int color_type;
	int interlace_type;
	png_byte** image;
	png_bytep tex_image;

	//ファイルを開く

	fopen_s( &fp, fileName, "rb" );
	if( !fp )
    {
		DEBUG_LOG("%s ファイルが開けませんでした。",fileName);
		return ERROR;
    }
	//png_ptr構造体を確保・初期化
	png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
	//確保・初期化に失敗したら
	if( !png_ptr )
	{
	    //ファイルを閉じる
		fclose( fp );
	    return false;
	}
	//info_ptr構造体を確保・初期化
	info_ptr = png_create_info_struct( png_ptr );
	//確保・初期化に失敗したら
	if( !info_ptr )
	{
		//構造体のメモリを解放
		png_destroy_read_struct( &png_ptr, (png_infopp)NULL, (png_infopp)NULL);
	    //ファイルを閉じる
		fclose( fp );
	    return false;
	}
	//libpngにfpを知らせる
	png_init_io( png_ptr, fp );
	//PNGファイルのヘッダを読み込む
	png_read_info( png_ptr, info_ptr );
	//IHDRチャンク情報を取得
	png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL );

	float screen_gamma = 2.2f;
    double image_gamma;
    int intent;

    if( png_get_sRGB( png_ptr, info_ptr, &intent ) )
    {
        png_set_gamma( png_ptr, screen_gamma, 0.45455 );
    }
	else if( png_get_gAMA( png_ptr, info_ptr, &image_gamma ) )
    {
        png_set_gamma( png_ptr, screen_gamma, image_gamma );
    }

	if( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
	{
		//グレイスケール画像をRGB形式に変換
		png_set_gray_to_rgb(png_ptr);
	}

	if( color_type == PNG_COLOR_TYPE_PALETTE )
	{
		//パレット付き画像をRGB形式に変換
		png_set_palette_to_rgb(png_ptr);
	}
	if( bit_depth < 8 )
	{
		//各要素8ビットに拡張
		png_set_packing( png_ptr );
	}
	if( bit_depth < 8 )
	{
		//各要素8ビットに縮小
		png_set_strip_16( png_ptr );
	}

	//tRNSチャンクがあれば
	if( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
	{
		//tRNSチャンクをアルファチャンネルに変換
		png_set_tRNS_to_alpha( png_ptr );
	}
	else if( !( color_type & PNG_COLOR_MASK_ALPHA ) )
	{
		// 不透明で埋めた完全なアルファチャンネルを追加
		png_set_add_alpha( png_ptr, 0xff, PNG_FILLER_AFTER);
	}

	png_read_update_info( png_ptr, info_ptr );
	
	//メモリを確保する
	texture->inisialize( TEX_RGBA, width, height );
	tex_image = (png_bytep)texture->lockTexture();
	
	image = (png_bytep*)malloc( sizeof( unsigned int ) * height * width );
	
	for( unsigned int i = 0 ; i < height ; i++ )
	{
		image[i] = &tex_image[i * width * sizeof(unsigned int)];
	}
	
	png_read_image( png_ptr, image );
	
	free( image );

	png_read_end(png_ptr, info_ptr);
	//構造体のメモリを解放
	png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp)NULL);
	//ファイルを閉じる
	fclose( fp );
	return true;
}

int main(int argc,char *argv[]) {
	Texture t;
	bool ret=PngLoad::loadPngFileTexture(&t,argc>1?argv[1]:"test.png");
	printf("#%c\n",ret?'t':'f');
	return 0;
}
(No:3に対するレスポンス)
mallocした領域をdeleteで開放するのは、予期せぬ不都合を引き起こす可能性があり、やるべきではないことです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: PNGの読み込みのエラー

#5

投稿記事 by h2so5 » 9年前

エラーとは関係ないですが、imageを余分に確保していますね。本来必要なサイズは sizeof(png_bytep) * height です。

みけさんの補足ですが、newによって返されたポインタ以外のものをdeleteに渡した場合の動作は未定義となっています。

§ 3.7.4.2
3 If a deallocation function terminates by throwing an exception, the behavior is undefined. The value of the
first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation
function is one supplied in the standard library, the call has no effect. Otherwise, the behavior is undefined
if the value supplied to operator delete(void*) in the standard library is not one of the values returned
by a previous invocation of either operator new(std::size_t) or operator new(std::size_t, const
std::nothrow_t&) in the standard library, and the behavior is undefined if the value supplied to operator
delete[](void*) in the standard library is not one of the values returned by a previous invocation of
either operator new[](std::size_t) or operator new[](std::size_t, const std::nothrow_t&) in the
standard library.

とにー

Re: PNGの読み込みのエラー

#6

投稿記事 by とにー » 9年前

lipng のバージョンをlipng 1.6.5からlipng 1.6.3にダウングレードしたらエラーが出なくなりました。
回答していただきありがとうございました。

pngの読み込み以外での指摘もありがとうございました。すぐに修正しようと思います。

またわからないことがあった時によろしくお願いします。

閉鎖

“C言語何でも質問掲示板” へ戻る