Thread: Reading PNG chunks.

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    903

    Reading PNG chunks.

    Hey there. I'm currently working on a project suggested by Mario F. However I'm stuck in a logical error I don't understand. The code seems right (of course it does) but next.length member gets a ridiculous value (>200000) yet next.name gets the correct first value ('IHDR'). I don't understand how this happens. It is said in the PNG specification that all chunks start with a 4-byte unsigned integer representing the length of the chunk's data section and then follows the chunk name which is also 4-byte-long. That leads me to think that if I have next.name correct, then I am obviously reading in the correct 4-byte unsigned integer for next.length.. Arrr =/

    Here's the code section:

    Code:
    bool imd::imd_png::parse_info_tags()
    {
        chunk c;
        this->skip_png_signature();
        this->get_next_chunk(c);
        return false;
    }
    
    void imd::imd_png::skip_png_signature()
    {
        fseek(this->file_handle, PNG_LENGTH_PNGSIGNATURE, SEEK_SET);
    }
    
    void imd::imd_png::get_next_chunk(imd::imd_png::chunk& next)
    {
        fread(&next.length, PNG_LENGTH_DATASIZE, 1, this->file_handle);
        fread(next.name, PNG_LENGTH_CHUNKNAME, 1, this->file_handle);
    
        if(next.length > 0)
        {
            if(next.data != 0) delete[] next.data;
            next.data = new char[next.length];
    
            fread(next.data, next.length, 1, this->file_handle);
        }
    
        fread(&next.crc, PNG_LENGTH_CRC, 1, this->file_handle);
        int a = 1;
    }
    The problematic function is (I think) get_next_chunk() but I fail to see the problem. parse_info_tags() shows how I am calling the get_next_chunk() but it's only in a test situation, it is not the actual real code.

    Any ideas ?

    Edit:

    PNG_LENGTH_DATASIZE = 4
    PNG_LENGTH_CHUNKNAME = 4
    PNG_LENGTH_CRC = 4
    PNG_LENGTH_PNGSIGNATURE = 8
    Last edited by Desolation; 03-12-2008 at 10:52 PM.

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Why is a number greater than 200,000 ridiculous? Images are big.

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    903
    I'm sorry. The IHDR chunk (Image HeaDeR) should be 17-bytes long, including the characters 'IHDR'.

  4. #4
    Registered User
    Join Date
    May 2006
    Posts
    903
    Here's the actual definition of the IHDR chunk.

    http://www.w3.org/TR/PNG/#11IHDR

    I have done a test and read two 4-byte unsigned integers after reading in the name of the chunk (which would be respectively width and height) and they turned out to be ridiculous values as well. I'm wondering if the problem is not in how I am passing the unsigned integer variables. I'm not too familiar to C-style file IO but it seemed much easier to read bytes than with C++ streams and so I opted for C-style.

    Edit: Oh and I was wrong, it's not >200,000, it's >1,000,000 (well theoretically 1,000,000 is also >200,000 but it's not as accurate).
    Last edited by Desolation; 03-12-2008 at 11:21 PM.

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    The value you're getting doesn't happen to be 285212672, is it?

  6. #6

  7. #7
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    >Nope, it's 218103808.
    The specification says that all integers are stored in network byte order:
    All integers that require more than one byte shall be in network byte order (as illustrated in figure 7.1): the most significant byte comes first, then the less significant bytes in descending order of significance
    Now your system appears to be little endian, and consequently the bytes appear reversed. For example:
    218103808 = 0D0000000 hex
    If you reversed the bytes, you would have the desired 0000000D hex = 13.

    Now I think there are some network POSIX functions to reverse this byte ordering. Or one can read into an array of unsigned char, and build the integer:
    Code:
        unsigned char buf[4];
    
        fread(buf, PNG_LENGTH_DATASIZE, 1, this->file_handle);
        next.length = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
    Last edited by swoopy; 03-13-2008 at 12:48 AM.

  8. #8
    Registered User
    Join Date
    May 2006
    Posts
    903
    Thanks ! I thought I read about that and searched for "endian" in the page but it turned out no results and I abandoned that idea. I use ntohl() right now but I'll try and make my own so I don't depend on it (especially since it's in winsock and I want to reduce external library usage to a minimum).

    Thanks again ! =)

  9. #9
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Quote Originally Posted by Desolation View Post
    Thanks ! I thought I read about that and searched for "endian" in the page but it turned out no results and I abandoned that idea.
    When I followed the link you provided I also had trouble finding the information about byte ordering. And I didn't know what network byte order meant until I read that link. It sounds like the same ordering as big endian, but maybe the term endian is only used when talking about processors.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 7
    Last Post: 02-02-2009, 07:27 AM
  2. Replies: 2
    Last Post: 01-28-2008, 03:07 AM
  3. Replies: 4
    Last Post: 05-04-2007, 01:09 AM
  4. Reading a file in 1-kilobyte chunks...
    By Crilston in forum C Programming
    Replies: 1
    Last Post: 06-30-2005, 04:33 PM
  5. Reading chunks from a file
    By Skarr in forum Linux Programming
    Replies: 1
    Last Post: 09-07-2002, 04:53 AM