2

I'm trying to create a png image with the libpng library using C (gcc on linux). This should expose my problem:

void createPng(char *filename, int width, int height) {
    FILE *fp = fopen(filename, "wb");;
    png_bytep row = NULL;
    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop info_ptr = png_create_info_struct(png_ptr);
    setjmp(png_jmpbuf(png_ptr));
    png_init_io(png_ptr, fp);
    png_set_IHDR(png_ptr, info_ptr, width, height,
        8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

    png_text title_text;
    title_text.compression = PNG_TEXT_COMPRESSION_NONE;
    title_text.key = "Title";
    title_text.text = "My title";
    png_set_text(png_ptr, info_ptr, &title_text, 1);
    png_write_info(png_ptr, info_ptr);

    row = (png_bytep) malloc(sizeof(png_byte)*width*3); //I think the problems start here

    for(int y=0; y<height; y++) {
        for(int x=0; x<width; x++) {
            row[x*3] = 0; //Red
            row[x*3+1] = 0; //Green
            row[x*3+2] = 0; //Blue
        }
        png_write_row(png_ptr, row); //I think this causes the segmentation fault
    }

    png_write_end(png_ptr, row);
}

In my mind this function should create a black image, the problem is that the execution stops with a segmentation fault. I think this happens because I'm not passing a well created png_bytep to png_write_row.

I know it isn't a good pratice to not check if all these function calls (in the first part of the program) return a valid pointer (and not NULL). Nevertheless I chose to post a minimal code without the checks but I've verified that the problem isn't there.

Andrea Ciceri
  • 436
  • 6
  • 16
  • Did you try getting a backtrace of the segfault? – Christian Gibbons Feb 12 '18 at 23:38
  • One return value you *cannot* ignore under any circumstance is `setjmp()`. It returns 0 on first call, and non-zero when invoked by `longjmp()`, which libpng uses for some errors. You'll have to test for non-zero and return the error before the other calls, or you'll end up in an infinite loop. – Lee Daniel Crocker Feb 12 '18 at 23:41

1 Answers1

1

The code is OK, except for that last line:

png_write_end(png_ptr, row);

This should be ...

png_write_end(png_ptr, info_ptr);

because the png_write_end() function takes an info_ptr (whatever that is) as the second argument.

Other than that, the code works fine.

Thanks for a good starting-point-example of writing a PNG image line-by-line.

Kingsley
  • 14,398
  • 5
  • 31
  • 53