Yes, that’s how libpng is designed and the manpage makes it clear you’re
expected to do it this way. All in all, libpng’s interface is more complex
than necessary, and I will make a note to complain to Andreas about that,
not that it’s going to change anything at this point. Still, when you actually
use the libpng interface, it’s just a one-time cost to deal with the complexity
and bury it in a utility function. And it is really hard to complain about the
quality of the results.
OK, here’s the new, improved error handling, which I think is right, but I
haven’t actually forced any errors to check that. I stand by my use of gotos
here, in this case they actually help clarify the code flow rather than
obfuscate it. The real reason the code hurts the eyes a little is that we’re
doing resource management that would be done automatically and nicely hidden
away in C++, but because it’s C, all the gory details have to be written out
by hand. On the bright side, at least you can see what you’re getting.
I didn’t put in the volatiles because I strongly suspect it doesn’t matter, and that
the compiler thoughtfully takes care of making sure no locals are destroyed by
a longjmp, i.e., it sees the longjmp and prudently doesn’t create any register
variables. Nothing else would make sense, since none of the examples of
libpng usage out there bother to declare volatiles. On the other hand, the
compiler is really noisy about warning when the volatile attributes get stripped
off by being passed to subfunctions, which means I’d have to put in more casts,
and make the code less type-safe. Sigh. Anybody who thinks these variables
need to be declared volatile, please provide evidence
int write_png(char *file_name, png_bytep *rows, int w, int h, int colortype, int bitdepth)
{
png_structp png_ptr;
png_infop info_ptr;
FILE *fp = fopen(file_name, “wb”);
char *doing = “open for writing”;
int error = 0;
if (!(fp = fopen(file_name, "wb"))) goto fail;
doing = "create png write struct";
if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
doing = "create png info struct";
if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
if (setjmp(png_jmpbuf(png_ptr))) goto fail;
doing = "init IO";
png_init_io(png_ptr, fp);
doing = "write header";
png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
doing = "write info";
png_write_info(png_ptr, info_ptr);
doing = "write image";
png_write_image(png_ptr, rows);
doing = "write end";
png_write_end(png_ptr, NULL);
out: if (png_ptr) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
if (fp) fclose(fp);
return error;
fail: printf(“Write_png: could not %s\n”, doing);
error = -1;
goto out;
}On Mon 17 Feb 03 17:36, you wrote:
Either way, do you actually have to use setjmp/longjmp with libpng?
Seems a bit nasty to me…