Saving pixel data using libpng
Below is a simple function that you can use to save PNGs. It's a thin wrapper around the
libpng
library, but which gives you a bit of flexibility. For example you can use the
transformations that are provided by the libpng library.
One feature I like is that you can save a BGRA buffer which you often get when downloading textures from a GPU without modifying the pixel data; simply pass the PNG_TRANSFORM_BGR for the transform parameter. You can 'OR' multiple of these transforms together.
/* save_png ----------------------------------------------------- A simple to save a png with a bit more flexibility. This function returns 0 on success otherwise -1. - filename: the path where you want to save the png. - width: width of the image - height: height of the image - bitdepth: how many bits per pixel (e.g. 8). - colortype: PNG_COLOR_TYEP_GRAY PNG_COLOR_TYPE_PALETTE PNG_COLOR_TYPE_RGB PNG_COLOR_TYPE_RGB_ALPHA PNG_COLOR_TYPE_GRAY_ALPHA PNG_COLOR_TYPE_RGBA (alias for _RGB_ALPHA) PNG_COLOR_TYPE_GA (alias for _GRAY_ALPHA) - pitch: The stride (e.g. '4 * width' for RGBA). - transform: PNG_TRANSFORM_IDENTITY PNG_TRANSFORM_PACKING PNG_TRANSFORM_PACKSWAP PNG_TRANSFORM_INVERT_MONO PNG_TRANSFORM_SHIFT PNG_TRANSFORM_BGR PNG_TRANSFORM_SWAP_ALPHA PNG_TRANSFORM_SWAP_ENDIAN PNG_TRANSFORM_INVERT_ALPHA PNG_TRANSFORM_STRIP_FILLER */ static int save_png(std::string filename, int width, int height, int bitdepth, int colortype, unsigned char* data, int pitch, int transform = PNG_TRANSFORM_IDENTITY); /* ----------------------------------------------------------------------- */ static int save_png(std::string filename, int width, int height, int bitdepth, int colortype, unsigned char* data, int pitch, int transform) { int i = 0; int r = 0; FILE* fp = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytep* row_pointers = NULL; if (NULL == data) { printf("Error: failed to save the png because the given data is NULL.\n"); r = -1; goto error; } if (0 == filename.size()) { printf("Error: failed to save the png because the given filename length is 0.\n"); r = -2; goto error; } if (0 == pitch) { printf("Error: failed to save the png because the given pitch is 0.\n"); r = -3; goto error; } fp = fopen(filename.c_str(), "wb"); if (NULL == fp) { printf("Error: failed to open the png file: %s\n", filename.c_str()); r = -4; goto error; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (NULL == png_ptr) { printf("Error: failed to create the png write struct.\n"); r = -5; goto error; } info_ptr = png_create_info_struct(png_ptr); if (NULL == info_ptr) { printf("Error: failed to create the png info struct.\n"); r = -6; goto error; } png_set_IHDR(png_ptr, info_ptr, width, height, bitdepth, /* e.g. 8 */ colortype, /* PNG_COLOR_TYPE_{GRAY, PALETTE, RGB, RGB_ALPHA, GRAY_ALPHA, RGBA, GA} */ PNG_INTERLACE_NONE, /* PNG_INTERLACE_{NONE, ADAM7 } */ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); for (i = 0; i < height; ++i) { row_pointers[i] = data + i * pitch; } png_init_io(png_ptr, fp); png_set_rows(png_ptr, info_ptr, row_pointers); png_write_png(png_ptr, info_ptr, transform, NULL); error: if (NULL != fp) { fclose(fp); fp = NULL; } if (NULL != png_ptr) { if (NULL == info_ptr) { printf("Error: info ptr is null. not supposed to happen here.\n"); } png_destroy_write_struct(&png_ptr, &info_ptr); png_ptr = NULL; info_ptr = NULL; } if (NULL != row_pointers) { free(row_pointers); row_pointers = NULL; } printf("And we're all free.\n"); return r; }