Skip to main content
gamedev.net
🔒 Locked

using libPNG

Started by DarkHamster Dec 17, 2002 at 7:11 PM 10 replies 750+ views
Original Post
DarkHamster
DarkHamster
I read the manual over a few times, and I was wondering, how would I go from png file to an OGL texture? I think I have most of it, but I''m entirely confused about the very last step (reading the image data from the png file). Thanks.

"There is no dark side of the moon really,
As a matter of fact, its all dark."


"There is no dark side of the moon really,
As a matter of fact, its all dark."
keethrus
keethrus
not sure if you would be intereseted, but i just finished writing my own PNG file loader (libPNG was way too bulky for me). mine just involves one header file and one ~.c file (and of course ZLIB to uncompress the PNG files). its extremely straightforward. as of now it loads the png image into an SDL_Image (im using SDL), but it could easily be modified in less than 5 minutes to give you the image data uncompressed in a nice fasion like...

struct MyImageblahblah
{
Uint32 width;
Uint32 height;
Uint8 *pixeldata;
}

...or however else you wanted it.

only catch is that since i wrote it, it only loads PNG files that are RGBA since thats what im using for my game. just wanted to share this with you in case it could help you any. :-)

- jeremiah

inlovewithGod.com
DarkHamster
DarkHamster
where could I get info on writing my own implementation of PNG, if that is a viable option?



"There is no dark side of the moon really,
As a matter of fact, its all dark."


"There is no dark side of the moon really,
As a matter of fact, its all dark."
keethrus
keethrus
check out the png specs: here.

a png file is simply made up of chunks, a chunk for header information (width, height, etc), a potential chunk for palette information, chunk(s) for the actual image data (which is probably compressed and would need uncompressing. i used ZLIB, which is free, unpatented, simple to use, and can be found here: www.gzip.org/zlib.), and an end chunk. there are critical chunks (have to be there: header, maybe a palette chunk depending on what the header chunk says, data chunk(s), and an end chunk) and other chunks (which you can just ignore).

chunks are in this format:
1) 32-bit length of chunk
2) 4-byte chunk type
3) chunk data
4) 4-byte CRC (Cyclic Redundancy Check) of this chunk's type and data

to load a PNG file, do the following...
---------------------------------------------------------------

// basic pseudo code

open file
read file into buffer (at least i do this...)
close file

check file signature
while( we havent reached end chunk "IEND" && we havent reached the end of our buffer )
{
get chunk length (read 32-bit int)
get chunk type (read 4 bytes)
switch (chunk type)
{
case "IHDR":
// handle IHDR, "Image header"
// load width, height, bit depth, color type,
// compression method, filter method,
// and interlace method.
break;
case "PLTE":
// load palette info
break;
case "IDAT":
// append this chunk's data onto end of
// some image buffer
break;
case "IEND":
// this is the "Image trailer" chunk, no data, just
// signals end of PNG file.
break;
default:
// dunno what this chunk is, so skip it
break;
}
get CRC of this chunk recorded in file (read 32 bit int)
calculate this chunk's CRC yourself (CRC is of chunk type and chunk data)
if they dont match then file is corrupt, bail!
}

if we didnt find an IHDR, (possibly a PLTE), at least one IDAT, and an IEND chunk then bail
if header told us image was compressed, then uncompress the image buffer
if header told us image was filtered, then unfilter the image buffer

// now you have everything you need (width, height, etc.; palette if applicable; and actual image pixel data)
// do with it as you please

free PNG file buffer and any other allocated memory


---------------------------------------------------------------

(editted for accuracy and clarity)

hope this helps some. :-)

- jeremiah

inlovewithGod.com

[edited by - keethrus on December 17, 2002 10:24:15 PM]
spiffgq
spiffgq
quote:
Original post by DarkHamster
I read the manual over a few times, and I was wondering, how would I go from png file to an OGL texture?



int textureObject = 0;
glGenTextures( 1, &textureObject);
glBindTextures (GL_TEXTURE_2D, textureObject);
gluBuild2DMipmaps (GL_TEXTURE_2D, 3, imageWidth, imageHeight, GL_RGB, GL_UNSIGNED_BYTE, imageData);


This code assumes that you have the image loaded. The gluBuild2DMipmaps is not the only way to do it, but it is one way. You''ll have to modify the parameters to fit your needs (imageWidth, ect).

quote:

I think I have most of it, but I''m entirely confused about the very last step (reading the image data from the png file).


libPNG comes with several example files and programs. Check those out; they are very helpful.
SpiffGQ
keethrus
keethrus
just for sake of accuracy, i think you might have to uncompress each IDAT chunk individually, instead of my pseudo-code which attempts to uncompress them all together at the end (which i dont think will work). the image i tested my PNG_loader on only had one IDAT chunk. :-)

heres the new pseudo-code:
--------------------------------------------------------------

// basic pseudo code
open file
read file into buffer (at least i do this...)
close file

check file signature
while( we havent reached end chunk "IEND" && we havent reached the end of our buffer )
{
get chunk length (read 32-bit int)
get chunk type (read 4 bytes)
switch (chunk type)
{
case "IHDR":
// handle IHDR, "Image header"
// load width, height, bit depth, color type,
// compression method, filter method,
// and interlace method.
break;
case "PLTE":
// load palette info
break;
case "IDAT":
// if compressed, uncompress
// append this chunk's data onto end of
// some image buffer
break;
case "IEND":
// this is the "Image trailer" chunk, no data, just
// signals end of PNG file.
break;
default:
// dunno what this chunk is, so skip it
break;
}
get CRC of this chunk recorded in file (read 32 bit int)
calculate this chunk's CRC yourself (CRC is of chunk type and chunk data)
if they dont match then file is corrupt, bail!
}

if we didnt find an IHDR, (possibly a PLTE), at least one IDAT, and an IEND chunk then bail
if header told us image was filtered, then unfilter the image buffer
// now you have everything you need (width, height, etc.; palette if applicable; and actual image pixel data)
// do with it as you please
free PNG file buffer and any other allocated memory

--------------------------------------------------------------

- jeremiah

inlovewithGod.com


[edited by - keethrus on December 18, 2002 10:00:23 AM]
DarkHamster
DarkHamster
maybe I''m just stupid but... I cant figure out how to use zlib now =( Ive got everything else I need to load pngs written (well I''m pretty sure...) Once again the manual was confusing, and it never actually says "you do x to inflate/deflate some data"...



"There is no dark side of the moon really,
As a matter of fact, its all dark."


"There is no dark side of the moon really,
As a matter of fact, its all dark."
spiffgq
spiffgq
quote:
Original post by DarkHamster
maybe I''m just stupid but... I cant figure out how to use zlib now =( Ive got everything else I need to load pngs written (well I''m pretty sure...) Once again the manual was confusing, and it never actually says "you do x to inflate/deflate some data"...


LibPNG uses zlib transparently; you do not have to interact with zlib at all.
SpiffGQ
DarkHamster
DarkHamster
Im not using libPNG -- I''m writing my own implementation because I only need it for one case (I''m making all the data I need to load), and I already have just about everything written (aside from inflating the data).



"There is no dark side of the moon really,
As a matter of fact, its all dark."


"There is no dark side of the moon really,
As a matter of fact, its all dark."
spiffgq
spiffgq
quote:
Original post by DarkHamster
Im not using libPNG -- I''m writing my own implementation because I only need it for one case (I''m making all the data I need to load), and I already have just about everything written (aside from inflating the data).


Oh. In that case, I don''t know. Why are you not using libPNG?

SpiffGQ
keethrus
keethrus
quick answer: use zlib's "uncompress" function.

long answer: see below...

at top of my "loadPNG.c" source file, i include "zlib.h".
then (after you compile them all) link with...
crc32.o infblock.o inflate.o uncompr.o adler32.o deflate.o infcodes.o inftrees.o zutil.o compress.o gzio.o inffast.o infutil.o trees.o
which is basically every source that comes with zlib minus the examples.
(im not sure you need them all, or if you could get away with not linking to all of them. however, since i dont know, i just go ahead and link 'em all in.)

in the "uncompress IDAT" part of your code:

1) allocate enough memory for the uncompressed image data.
this is (width + 1) * height * (bytes_per_pixel)
in my case, RGBA, it was "(width + 1) * height * 4" bytes.
why "(width + 1)" instead of just "width"? because at the
beginning of each scan line, there is one byte that tells
you which filter was used on that scan line. (that is, if
filters are used, and im guessing they generally always will
be used, since they help greatly). you could always check
if the header chunk said filters were used, and if not, just
leave off the "+ 1" part of "(width + 1)".
2) pass the complete IDAT chunk data to the zlib function
"uncompress". heres some modified code out of my program...

Uint32 err = 0;
Uint32 uncompressedlength = 0;
// output buffer is a pointer to memory where the uncompressed
// data will be put.
// myLoadedFilebuffer is the pointer to memory where the PNG
// file was loaded.
// indexOfIDATdata is the offset where this IDAT's data begins
// thisIDATschunklength is simply this chunk's length loaded at
// the beginning of the chunk.

err = uncompress(outputbuffer, &uncompressedlength, &myLoadedFileBuffer[ indexOfIDATdata ], thisIDATschunklength );
if (err != Z_OK)
{
// while not a complete list, here are some error meanings...
// if err == -3 then input data was corrupted
// if err == -4 then zlib didnt have enough memory
// if err == -5 then there wasnt enough memory in the output
// buffer

// free whatever memory needs freeing before we return
// "failed"
return -1;
}
// the variable "uncompressedlength" equals the length of the
// uncompressed image pixel data.



hope this helps some. if you have anymore questions, feel free to ask. :-)

- jeremiah

inlovewithGod.com

[edited by - keethrus on December 18, 2002 10:56:46 PM]

[edited by - keethrus on December 18, 2002 10:59:16 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.