Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

libpng png_set_add_alpha | png_set_filler error: sequential row overflow

I'm trying to read a PNG file with C for use with OpenCL. OpenCL has no support for 24-bit RGB images so I need to expand the data from RGB to RGBA. The PNGs I am using are all 24-bit so that headache can be avoided.

I have attempted to use png_set_filler and png_set_add_alpha which I assume are roughly identical to solve the problem but they both cause this error:

libpng error: sequential row overflow

Here is the function in full:

int LoadPNG24(unsigned char ** pixelBuffer, const char *filename, unsigned int *width, unsigned int *height) {
    png_byte header[8];

    //open file as binary
    FILE *fp = fopen(filename, "rb");
    if (!fp) {
        return TEXTURE_LOAD_ERROR;
    }

    //read the header
    fread(header, 1, 8, fp);

    //test if png
    int is_png = !png_sig_cmp(header, 0, 8);
    if (!is_png) {
        fclose(fp);
        return TEXTURE_LOAD_ERROR;
    }

    //create png struct
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        fclose(fp);
        return (TEXTURE_LOAD_ERROR);
    }

    //create png info struct
    png_infop 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 (TEXTURE_LOAD_ERROR);
    }

    //create png info struct
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
        fclose(fp);
        return (TEXTURE_LOAD_ERROR);
    }

    //png error stuff, not sure libpng man suggests this.
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        fclose(fp);
        return (TEXTURE_LOAD_ERROR);
    }

    //init png reading
    png_init_io(png_ptr, fp);

    //let libpng know you already read the first 8 bytes
    png_set_sig_bytes(png_ptr, 8);

    // read all the info up to the image data
    png_read_info(png_ptr, info_ptr);

    //variables to pass to get info
    int bit_depth, color_type;
    png_uint_32 twidth, theight;

    // get info about png
    png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, NULL, NULL, NULL);

    // Update the png info struct.
    png_read_update_info(png_ptr, info_ptr);

    // Row size in bytes.
    //png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    png_size_t rowbytes = sizeof(png_byte) * 4 * twidth;

    // Allocate the image_data as a big block, to be given to opencl
    png_byte *image_data = (png_byte *)malloc(sizeof(png_byte) * 4 * twidth * theight);
    if (!image_data) {
        //clean up memory and close stuff
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        fclose(fp);
        return TEXTURE_LOAD_ERROR;
    }

    //row_pointers is for pointing to image_data for reading the png with libpng
    png_bytep *row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * theight);
    if (!row_pointers) {
        //clean up memory and close stuff
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        free(image_data);
        fclose(fp);
        return TEXTURE_LOAD_ERROR;
    }

    // set the individual row_pointers to point at the correct offsets of image_data
    for (int i = 0; i < theight; ++i) {
        row_pointers[i] = image_data + (i * rowbytes);
    }

    // PNG Transforms
    if (color_type == PNG_COLOR_TYPE_RGB) {
        //png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
        png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
    }

    //read the png into image_data through row_pointers
    png_read_image(png_ptr, row_pointers);

    //clean up memory and close stuff
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
    free(row_pointers);
    fclose(fp);

    //update width and height based on png info
    (*pixelBuffer) = image_data;
    if (width) {*width = twidth;}
    if (height) {*height = theight;}

    return TEXTURE_LOAD_OK;
}

Thanks.

like image 914
Jonathan Hatchett Avatar asked Feb 20 '12 16:02

Jonathan Hatchett


1 Answers

Ok, a bit more googling provided the answer.

Adding

 png_read_update_info(png_ptr, info_ptr);

After the transformed updated the info ptr and the row pointers and fixed the problem.

I'll leave the answer here in the hopes of helping someone else with this problem.

like image 107
Jonathan Hatchett Avatar answered Sep 28 '22 08:09

Jonathan Hatchett