Patrick Mullen wrote: > I just checked, I do actually have libpng in my pygame folder. So if > you could bypass SDL_Image and go straight to libpng for saving png > files, it would be extremely useful. Png has become the standard > format for me, because of the good lossless compression and the alpha > channel support. By the way, in case you didn't know, PNG is also a > lossless format. > >
Here is some lightly modified C code which I wrote for the 'mupen64' emulator, so it's licensed under the GPL. It's written to save a screenshot from an OpenGL context, but it could be easily modified to access a pygame surface instead. Anyone who wishes is welcome to use this to add PNG saving support, because that would be a nice feature. Richard #include <png.h> static void OGL_png_error(png_structp png_write, const char *message) { printf("PNG Error: %s\n", message); } static void OGL_png_warn(png_structp png_write, const char *message) { printf("PNG Warning: %s\n", message); } void OGL_SaveScreenshot() { // start by getting the base file path char filename[2048]; strcpy(filename, "SavedImage.png"); // allocate PNG structures png_structp png_write = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, OGL_png_error, OGL_png_warn); if (!png_write) { printf("Error creating PNG write struct.\n"); return; } png_infop png_info = png_create_info_struct(png_write); if (!png_info) { png_destroy_write_struct(&png_write, (png_infopp)NULL); printf("Error creating PNG info struct.\n"); return; } // Set the jumpback if (setjmp(png_jmpbuf(png_write))) { png_destroy_write_struct(&png_write, &png_info); printf("Error calling setjmp()\n"); return; } // open the file to write FILE *savefile = fopen(filename, "wb"); if (savefile == NULL) { printf("Error opening '%s' to save screenshot.\n", filename); return; } // give the file handle to the PNG compressor png_init_io(png_write, savefile); // read pixel data from OpenGL char *pixels = (char*)malloc( OGL.width * OGL.height * 3 ); glReadBuffer( GL_FRONT ); glReadPixels( 0, OGL.heightOffset, OGL.width, OGL.height, GL_RGB, GL_UNSIGNED_BYTE, pixels ); glReadBuffer( GL_BACK ); // set the info int width = OGL.width; int height = OGL.height; png_set_IHDR(png_write, png_info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // lock the screen, get a pointer and row pitch long pitch = width * 3; // allocate row pointers and scale each row to 24-bit color png_byte **row_pointers; row_pointers = (png_byte **) malloc(height * sizeof(png_bytep)); for (int i = 0; i < height; i++) { row_pointers[i] = (png_byte *) (pixels + i * pitch); } // set the row pointers png_set_rows(png_write, png_info, row_pointers); // write the picture to disk png_write_png(png_write, png_info, 0, NULL); // free memory free(row_pointers); png_destroy_write_struct(&png_write, &png_info); free(pixels); // all done }