libpng doesn't seem to read

Discussion in 'Mac Programming' started by Duke Leto, Jun 15, 2010.

  1. Duke Leto macrumors regular

    Joined:
    Mar 17, 2008
    #1
    I am trying to get a program that will read pixel data of a PNG image.

    Here's the issue:
    I installed libpng and then used the code from this tutorial. It compiles and runs, but when I cout the data from rowPtrs (which, from what I understand, should contain the data from the pixels in each row), it always displays "\377".

    I copied the code exactly from the tutorial, and the only code that I changed was the initialization of the istream, from which I copied the cpp reference code. (If you can't tell, I just wanted a quick, dirty, and temporary program).

    Here's the code:
    Code:
    #include <iostream>
    #include <fstream>
    #include <stdlib.h>
    
    #include "libpng14/png.h"
    
    #define PNGSIGSIZE			8
    using namespace std;
    
    bool validate(std::istream& source);
    void userReadData(png_structp pngPtr, png_bytep data, png_size_t length);
    
    png_infop infoPtr;
    png_structp pngPtr;
    png_bytep* rowPtrs;
    int main (int argc, char * const argv[]) {
    	filebuf fb;
    	fb.open ("image.png",ios::in);
    	istream source(&fb);
    	//so First, we validate our stream with the validate function I just mentioned
    	if (!validate(source)) {
    		std::cerr << "ERROR: Data is not valid PNG-data" << std::endl;
    		return 0; //Do your own error recovery/handling here
    	}
    	
    	//Here we create the png read struct. The 3 NULL's at the end can be used
    	//for your own custom error handling functions, but we'll just use the default.
    	//if the function fails, NULL is returned. Always check the return values!
    	png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    	if (!pngPtr) {
    		cerr << "ERROR: Couldn't initialize png read struct" << std::endl;
    		return 0; //Do your own error recovery/handling here
    	}
    	
    	//Here we create the png info struct.
    	//Note that this time, if this function fails, we have to clean up the read struct!
    	infoPtr = png_create_info_struct(pngPtr);
    	if (!infoPtr) {
    		cerr << "ERROR: Couldn't initialize png info struct" << std::endl;
    		png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0);
    		return 0; //Do your own error recovery/handling here
    	}
    	
    	//Here I've defined 2 pointers up front, so I can use them in error handling.
    	//I will explain these 2 later. Just making sure these get deleted on error.
    	rowPtrs = NULL;
    	char* data = NULL;
    	
    	if (setjmp(png_jmpbuf(pngPtr))) {
    		//An error occured, so clean up what we have allocated so far...
    		png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0);
    		if (rowPtrs != NULL) delete [] rowPtrs;
    		if (data != NULL) delete [] data;
    		
    		cout << "ERROR: An error occured while reading the PNG file";
    		
    		//Make sure you return here. libPNG will jump to here if something
    		//goes wrong, and if you continue with your normal code, you might
    		//End up with an infinite loop.
    		return 0; // Do your own error handling here.
    	}
    	png_set_read_fn(pngPtr,(voidp)&source, userReadData);
    	//Set the amount signature bytes we've already read:
        //We've defined PNGSIGSIZE as 8;
        png_set_sig_bytes(pngPtr, PNGSIGSIZE);
    	
        //Now call png_read_info with our pngPtr as image handle, and infoPtr to receive the file info.
        png_read_info(pngPtr, infoPtr);
    	png_uint_32 imgWidth =  png_get_image_width(pngPtr, infoPtr);
        png_uint_32 imgHeight = png_get_image_height(pngPtr, infoPtr);
    	
        //bits per CHANNEL! note: not per pixel!
        png_uint_32 bitdepth   = png_get_bit_depth(pngPtr, infoPtr);
        //Number of channels
        png_uint_32 channels   = png_get_channels(pngPtr, infoPtr);
        //Color type. (RGB, RGBA, Luminance, luminance alpha... palette... etc)
        png_uint_32 color_type = png_get_color_type(pngPtr, infoPtr);
    	//Here's one of the pointers we've defined in the error handler section:
        //Array of row pointers. One for every row.
        rowPtrs = new png_bytep[imgHeight];
    	
        //Alocate a buffer with enough space.
        //(Don't use the stack, these blocks get big easily)
        //This pointer was also defined in the error handling section, so we can clean it up on error.
        data = new char[imgWidth * imgHeight * bitdepth * channels / 8];
    
        //This is the length in bytes, of one row.
        const unsigned int stride = imgWidth * bitdepth * channels / 8;
    	
        //A little for-loop here to set all the row pointers to the starting
        //Adresses for every row in the buffer
    	
        for (size_t i = 0; i < imgHeight; i++) {
            //Set the pointer to the data pointer + i times the row stride.
            //Notice that the row order is reversed with q.
            int q = (imgHeight-i-1) * stride;
            rowPtrs[i] = (png_bytep)(data + q);
        }
    
        //And here it is! The actual reading of the image!
        //Read the imagedata and write it to the adresses pointed to
        //by rowptrs (in other words: our image databuffer)
    	png_read_image(pngPtr, rowPtrs);
    	fb.close();
    	return 0;
    }
    
    void userReadData(png_structp pngPtr, png_bytep data, png_size_t length) {
        //Here we get our IO pointer back from the read struct.
        //This is the parameter we passed to the png_set_read_fn() function.
        //Our std::istream pointer.
        png_voidp a = png_get_io_ptr(pngPtr);
        //Cast the pointer to std::istream* and read 'length' bytes into 'data'
        ((std::istream*)a)->read((char*)data, length);
    }
    
    bool validate(std::istream& source) {
    	
        //Allocate a buffer of 8 bytes, where we can put the file signature.
        png_byte pngsig[PNGSIGSIZE];
        int is_png = 0;
    	
        //Read the 8 bytes from the stream into the sig buffer.
        source.read((char*)pngsig, PNGSIGSIZE);
    	
        //Check if the read worked...
        if (!source.good()) return false;
    	
        //Let LibPNG check the sig. If this function returns 0, everything is OK.
        is_png = png_sig_cmp(pngsig, 0, PNGSIGSIZE);
        return (is_png == 0);
    }
    
    I've been stuck on this for quite some time, and any help is appreciated! Thanks!
     
  2. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #2
    Show your cout code. I don't see any in what you posted.

    Exactly what is in the png image you're reading? What are its channel count, channel bitsize, etc.?

    Do you realize that '\377' is 0xFF, or 100% of a single 8-bit RGB channel? If all channels are 0xFF, then that would be white.
     
  3. Duke Leto thread starter macrumors regular

    Joined:
    Mar 17, 2008
    #3
    Oh, I get it! I had a pure black and white image. Black probably didn't show up in the debugger. I tried it again with a reddish color, and now I am seeing how it works. *facepalm*

    Thanks for helping!
    :D

    Does anyone know of a helpful resource on libpng that would help me get understand what's going on?
     

Share This Page