PDA

View Full Version : reading and using PNG images



Neonic
04-13-2009, 10:20 AM
Hello,

I'm using libPNG to load PNG images to be used as textures in my openGL applications. However, something appears to be wrong. Only the left halves of the images are correctly shown in the openGL rendering. The other half is always black with zero alpha.

This is my code for loading the image and creating the texture.



Tex_Impl* GLW_Impl::LoadPNG(const char* filename,bool mipmap)
{
Tex_Impl* tex=0;
FILE *fp=0;
png_info* info_ptr=0, *end_info=0;
png_struct* png_ptr=0;
png_bytep *row_pointers=0;
png_bytep data=0;

fp=fopen(filename, "rb");
if(!fp) return 0;

png_byte header[PNGHEADER_READSIZE];
fread(header, 1, PNGHEADER_READSIZE, fp);
bool is_png = !png_sig_cmp(header, 0, PNGHEADER_READSIZE);
if(!is_png)goto pngload_failure;

png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRI NG,(png_voidp)NULL,NULL,NULL);
if(!png_ptr)goto pngload_failure;

info_ptr=png_create_info_struct(png_ptr);
if(!info_ptr)goto pngload_failure;

end_info = png_create_info_struct(png_ptr);
if(!end_info) goto pngload_failure;

if(setjmp(png_jmpbuf(png_ptr))) goto pngload_failure;

png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, PNGHEADER_READSIZE);

png_read_info(png_ptr, info_ptr);

png_uint_32 width,height;
int bit_depth, color_type;
png_get_IHDR(png_ptr, info_ptr, &width, &height,
&bit_depth, &color_type, NULL, NULL, NULL);

png_byte num_channels=png_get_channels(png_ptr, info_ptr);

if(color_type==PNG_COLOR_TYPE_PALETTE)
{
png_set_palette_to_rgb(png_ptr);
color_type=PNG_COLOR_TYPE_RGB;
}
if(bit_depth<8)
{
png_set_packing(png_ptr);
bit_depth=8;
}
else if(bit_depth==16)
{
png_set_strip_16(png_ptr);
bit_depth=8;
}
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);

png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);

row_pointers=new png_bytep[height];
data=(png_bytep)png_malloc(png_ptr,height*rowbytes );

for(png_uint_32 i=0; i<height; i++) row_pointers[i]=&amp;data[i*rowbytes];

for(DWORD y=0; y<height; y++)
{
png_read_row(png_ptr, row_pointers[y], NULL);
}

png_read_end(png_ptr, end_info);
fclose(fp);
png_destroy_read_struct(&amp;png_ptr, &amp;info_ptr,NULL);
delete[] row_pointers;

if(data)
{
tex=new Tex_Impl;
tex->next=textures;
textures=tex;

glGenTextures(1, &amp;tex->tex);
tex->width=width;
tex->height=width;

GLenum internal_format;
switch(color_type)
{
case PNG_COLOR_TYPE_GRAY: internal_format=GL_LUMINANCE8; break;
case PNG_COLOR_TYPE_GRAY_ALPHA: internal_format=GL_LUMINANCE8_ALPHA8; break;
case PNG_COLOR_TYPE_RGB: internal_format=GL_RGB; break;
case PNG_COLOR_TYPE_RGB_ALPHA: internal_format=GL_RGBA; break;
}
if(color_type==PNG_COLOR_TYPE_GRAY_ALPHA)
{
for(DWORD i=0; i<width*height*2; i+=2)
{
if(data[i+1]<255)
{
tex->transparent=true;
break;
}
}
}
else if(color_type==PNG_COLOR_TYPE_RGB_ALPHA)
{
for(DWORD i=0; i<width*height*4; i+=4)
{
if(data[i+3]<255)
{
tex->transparent=true;
break;
}
}
}

glBindTexture(GL_TEXTURE_2D, tex->tex);

if(mipmap) gluBuild2DMipmaps( GL_TEXTURE_2D, internal_format, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
else glTexImage2D( GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR);
}
else goto pngload_failure;

return tex;

pngload_failure:

delete[] row_pointers;
fclose(fp);
png_destroy_read_struct(&amp;png_ptr, &amp;info_ptr,NULL);

return 0;
}


The function returns a nonzero value, but only half of the texture has the pixel values of the image. The other half turns black, even when I initialize all the bytes in "data" with 255.

I submitted this problem on this forum because I'm not sure whether the problem is with my openGL or libPNG usage.