Jump to content
  • Advertisement
Sign in to follow this  

libpng: Worst manual ever or am I just dense?

This topic is 4815 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

The document in question. I've been looking over this thing for 20 minutes now and I still have no idea what I'm looking at or where to start. I have no idea what the functions are, what they do, why they're there, what their arguments are, or what caveats to look out for. Where the heck is the actual documentation for this thing? I'm having an easier time figuring this out by skimming through the source code. Surely that's a sign that something is horribly wrong with their manual. I guess that was more of a rant than an actual question. I'm just lost here. Anyone want to recommend an alternative thread safe cross platform image library that can use custom i/o routines?

Share this post


Link to post
Share on other sites
Advertisement
I remember digging through that document, it is pretty bad. I can post code that uses custom IO routines if you want. Once you have it working with the default file IO, it is not complex to switch it over to the custom routines. You just need these 3 functions:

void PngRead(png_structp png_ptr, png_bytep data, png_size_t length);
void PngWrite(png_structp png_ptr, png_bytep data, png_size_t length);
void PngFlush(png_structp png_ptr);

Then call this for writing images:

png_set_write_fn(PngStruct, &IO, PngWrite, PngFlush);

Or this for reading:

png_set_read_fn(PngStruct, &IO, PngRead);

Each goes after png_create_write_struct or png_create_read_struct. You can access whatever you passed for IO to those png_set_*_fn functions in your callbacks with png_ptr->io_ptr.

I can post my code if that would help.

edit: I'm not sure if you are still intested in libpng, I just got the impression that the problem was IO routines. Reading it again, it doesn't seem that way ;) DevIL is one image library I know of.

Share this post


Link to post
Share on other sites
Here is a class that implements png handling in my game:

vPng.h
vPng.cpp

I realize it is sorely lacking comments, if there is something you want more explanation with this code I have AIM: dillons23 and ICQ: 205897132.

Share this post


Link to post
Share on other sites
I looked at DevIL and FreeImage.

DevIL seems to be a state machine, and the I/O routines seem to be shared globally; I'm pretty sure I don't want that in a multithreaded environment. I could make sure none of my code tries to use it at the same time, but I could still get into trouble if another library or the user decides they want to use it, so I don't think so.

The best FreeImage could do was load an image from memory. I could load my data into memory first before passing it on, but that seems wasteful and inefficient.

There was a few others but they had obscure features for 3D volumes or dozens of strange transformations or drawing and a bunch of other things I don't need or want. That was about where I decided I should just dump the middle man and use libpng directly.

Thanks for the assistance.

Share this post


Link to post
Share on other sites
Another thing I just thought of that might be of some use is CxImage. I remember downloading this to get an example usage of libpng and libjpeg, maybe it will help also. I bet their code is better than mine ;)

Share this post


Link to post
Share on other sites
It works! Well, everything except the PNG_COLOR_MASK_xxx types, because I couldn't figure out how to determine which colour to use as the mask.

Lenna seems to be happy to be more than just a black square on the screen, and the library I'm writing is slowly getting to the point where it is almost able to sort of do something.

And that manual was of no help whatsoever.

Thanks again for the help.

Share this post


Link to post
Share on other sites
Yeah, the libpng manuals are pretty bad, last I checked. That's one of the problems with trying to be able to handle all and every situation in C. It's gernally a better idea to look at the libpng example programs.

Anyway, at one point I managed to write my own little include file that handled all the boring bits. It's missing explicit documentation, but the names should make sense. Enjoy!

pngio.h

#include <stdio.h>
#include <png.h>

typedef struct {
unsigned char red, green, blue, alpha;
} mycolour;

typedef struct {
FILE* fp;
png_structp png;
png_infop info;
png_infop end;
mycolour** rows;
} pngstuff;

int open_png(char *filename, pngstuff* ret) {
png_uint_32 width, height;
int y, bit_depth, colour_type, interlace_type;

ret->fp = fopen(filename, "rb");
if (!ret->fp) {
return 1;
}

ret->png = png_create_read_struct(
PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!ret->png) {
fclose(ret->fp);
return 2;
}

ret->info = png_create_info_struct(ret->png);
if (!ret->info) {
png_destroy_read_struct(&ret->png, NULL, NULL);
fclose(ret->fp);
return 3;
}

ret->end = png_create_info_struct(ret->png);
if (!ret->end) {
png_destroy_read_struct(&ret->png, &ret->info, NULL);
fclose(ret->fp);
return 4;
}

if (setjmp(png_jmpbuf(ret->png))) {
png_destroy_read_struct(&ret->png, &ret->info, &ret->end);
fclose(ret->fp);
return 5;
}

png_init_io(ret->png, ret->fp);
png_read_info(ret->png, ret->info);
png_get_IHDR(ret->png, ret->info, &width, &height, &bit_depth,
&colour_type, &interlace_type, NULL, NULL);
png_set_strip_16(ret->png);
png_set_packing(ret->png);
if (colour_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(ret->png);
}

if (colour_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
png_set_gray_1_2_4_to_8(ret->png);
}

if (png_get_valid(ret->png, ret->info, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(ret->png);
}

png_set_filler(ret->png, 0xff, PNG_FILLER_AFTER);

if (colour_type == PNG_COLOR_TYPE_GRAY ||
colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
png_set_gray_to_rgb(ret->png);
}

ret->rows = (mycolour**) malloc(height * sizeof(mycolour*));
for (y = 0; y < height; ++y) {
ret->rows[y] = (mycolour*) malloc(width * sizeof(mycolour));
}

png_read_image(ret->png, (png_bytepp) ret->rows);
png_read_end(ret->png, ret->info);

return 0;
}

void close_png(pngstuff* p) {
png_destroy_read_struct(&p->png, &p->info, &p->end);
fclose(p->fp);
p->fp = NULL;
}

int write_png(char* filename, mycolour** rows, int width, int height) {
FILE* fp_out;
png_structp ppng_out;
png_infop pinfo_out;

fp_out = fopen(filename, "wb");
if (!fp_out) {
return 1;
}

ppng_out = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!ppng_out) {
fclose(fp_out);
return 2;
}

pinfo_out = png_create_info_struct(ppng_out);
if (!pinfo_out) {
png_destroy_write_struct(&ppng_out, NULL);
fclose(fp_out);
return 3;
}

png_init_io(ppng_out, fp_out);
png_set_IHDR(ppng_out, pinfo_out, width, height, 8,
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

png_set_rows(ppng_out, pinfo_out, (png_bytepp)rows);

if (setjmp(png_jmpbuf(ppng_out))) {
png_destroy_write_struct(&ppng_out, &pinfo_out);
fclose(fp_out);
return 4;
}

png_write_png(ppng_out, pinfo_out, PNG_TRANSFORM_IDENTITY, NULL);

png_destroy_write_struct(&ppng_out, &pinfo_out);
fclose(fp_out);

return 0;
}


Share this post


Link to post
Share on other sites
Quote:
Original post by smart_idiot
And that manual was of no help whatsoever.

Thanks again for the help.

Glad I could help. Yeah the manual is pretty worthless. The only place I found it useful was looking up the transforms, which are pretty cool and helpful.

edit: Doc, much agreed on the C API thing. I especially hate the setjmp/longjmp system a lot of C libraries tend to use (libpng included).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!