void PNGImageWriter::beginOfImage(int cols, int rows) { _png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); _info_ptr = png_create_info_struct(_png_ptr); if (!_info_ptr) { png_destroy_write_struct(&_png_ptr, NULL); exit(1); } png_set_IHDR(_png_ptr, _info_ptr, cols, rows, 16, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, NULL/*PNG_COMPRESSION_TYPE_DEFAULT*/, PNG_FILTER_TYPE_DEFAULT); //png_set_filter(_png_ptr, 0, PNG_FILTER_NONE); //png_set_packing(_png_ptr); png_set_compression_level(_png_ptr, 0); // No compression png_set_filter(_png_ptr, 0 /* method */, PNG_NO_FILTERS); png_color_8 sig_bit; sig_bit.gray = 16; sig_bit.red = 0; sig_bit.green = 0; sig_bit.blue = 0; sig_bit.alpha = 0; png_set_sBIT(_png_ptr, _info_ptr, &sig_bit); //png_set_shift(_png_ptr, &sig_bit); //png_set_gamma(_png_ptr, 1., 1.); png_set_strip_16(_png_ptr); //if (lsb) //png_set_swap(_png_ptr); // flush output after every row if (_lineBuffered) png_set_flush(_png_ptr, 1); //png_set_filler(_png_ptr, 0, PNG_FILLER_BEFORE); // Represent black as 1 and white as 0 instead of the PNG default. //png_set_invert_mono(_png_ptr); png_init_io(_png_ptr, _output); /* write the file information */ png_write_info(_png_ptr, _info_ptr); }
static bool _save_image_RGBA_png(const char *fileName, unsigned char *buffer, int width, int height) { // open the file FILE *fp = fopen(fileName, "wb"); if (!fp) return false; // create the needed data structures png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { fclose(fp); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fclose(fp); png_destroy_write_struct(&png_ptr, (png_infopp) 0); return false; } // do the setjmp thingy if (setjmp(png_ptr->jmpbuf)) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return false; } // set up the io png_init_io(png_ptr, fp); // write the header png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); png_set_flush(png_ptr, 10); // write the image png_bytep *row_pointers = new png_bytep[height]; for (int y = 0 ; y < height ; y++) row_pointers[y] = (png_byte *) (buffer + (height - 1 - y) * width * 4); png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); // clean up memory, and finish fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); return true; }
/** * Generic .PNG file image writer. * @param name Filename, including extension. * @param callb Callback function for generating lines of pixels. * @param userdata User data, passed on to \a callb. * @param w Width of the image in pixels. * @param h Height of the image in pixels. * @param pixelformat Bits per pixel (bpp), either 8 or 32. * @param palette %Colour palette (for 8bpp images). * @return File was written successfully. * @see ScreenshotHandlerProc */ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette) { png_color rq[256]; FILE *f; uint i, y, n; uint maxlines; uint bpp = pixelformat / 8; png_structp png_ptr; png_infop info_ptr; /* only implemented for 8bit and 32bit images so far. */ if (pixelformat != 8 && pixelformat != 32) return false; f = fopen(name, "wb"); if (f == NULL) return false; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, const_cast<char *>(name), png_my_error, png_my_warning); if (png_ptr == NULL) { fclose(f); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fclose(f); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(f); return false; } png_init_io(png_ptr, f); png_set_filter(png_ptr, 0, PNG_FILTER_NONE); png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); #ifdef PNG_TEXT_SUPPORTED /* Try to add some game metadata to the PNG screenshot so * it's more useful for debugging and archival purposes. */ png_text_struct text[2]; memset(text, 0, sizeof(text)); text[0].key = const_cast<char *>("Software"); text[0].text = const_cast<char *>(_openttd_revision); text[0].text_length = strlen(_openttd_revision); text[0].compression = PNG_TEXT_COMPRESSION_NONE; char buf[8192]; char *p = buf; p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); p = strecpy(p, "NewGRFs:\n", lastof(buf)); for (const GRFConfig *c = _game_mode == GM_MENU ? NULL : _grfconfig; c != NULL; c = c->next) { p += seprintf(p, lastof(buf), "%08X ", BSWAP32(c->ident.grfid)); p = md5sumToString(p, lastof(buf), c->ident.md5sum); p += seprintf(p, lastof(buf), " %s\n", c->filename); } p = strecpy(p, "\nCompanies:\n", lastof(buf)); const Company *c; FOR_ALL_COMPANIES(c) { if (c->ai_info == NULL) { p += seprintf(p, lastof(buf), "%2i: Human\n", (int)c->index); } else { p += seprintf(p, lastof(buf), "%2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion()); } } text[1].key = const_cast<char *>("Description"); text[1].text = buf; text[1].text_length = p - buf; text[1].compression = PNG_TEXT_COMPRESSION_zTXt; png_set_text(png_ptr, info_ptr, text, 2); #endif /* PNG_TEXT_SUPPORTED */ if (pixelformat == 8) { /* convert the palette to the .PNG format. */ for (i = 0; i != 256; i++) { rq[i].red = palette[i].r; rq[i].green = palette[i].g; rq[i].blue = palette[i].b; } png_set_PLTE(png_ptr, info_ptr, rq, 256); } png_write_info(png_ptr, info_ptr); png_set_flush(png_ptr, 512); if (pixelformat == 32) { png_color_8 sig_bit; /* Save exact colour/alpha resolution */ sig_bit.alpha = 0; sig_bit.blue = 8; sig_bit.green = 8; sig_bit.red = 8; sig_bit.gray = 8; png_set_sBIT(png_ptr, info_ptr, &sig_bit); #if TTD_ENDIAN == TTD_LITTLE_ENDIAN png_set_bgr(png_ptr); png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); #else png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); #endif /* TTD_ENDIAN == TTD_LITTLE_ENDIAN */ } /* use by default 64k temp memory */ maxlines = Clamp(65536 / w, 16, 128); /* now generate the bitmap bits */ void *buff = CallocT<uint8>(w * maxlines * bpp); // by default generate 128 lines at a time. y = 0; do { /* determine # lines to write */ n = min(h - y, maxlines); /* render the pixels into the buffer */ callb(userdata, buff, y, w, n); y += n; /* write them to png */ for (i = 0; i != n; i++) { png_write_row(png_ptr, (png_bytep)buff + i * w * bpp); } } while (y != h); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); free(buff); fclose(f); return true; }
static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette) { png_color rq[256]; FILE *f; uint i, y, n; uint maxlines; uint bpp = pixelformat / 8; png_structp png_ptr; png_infop info_ptr; /* only implemented for 8bit and 32bit images so far. */ if (pixelformat != 8 && pixelformat != 32) return false; f = fopen(name, "wb"); if (f == NULL) return false; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)name, png_my_error, png_my_warning); if (png_ptr == NULL) { fclose(f); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fclose(f); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(f); return false; } png_init_io(png_ptr, f); png_set_filter(png_ptr, 0, PNG_FILTER_NONE); png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (pixelformat == 8) { /* convert the palette to the .PNG format. */ for (i = 0; i != 256; i++) { rq[i].red = palette[i].r; rq[i].green = palette[i].g; rq[i].blue = palette[i].b; } png_set_PLTE(png_ptr, info_ptr, rq, 256); } png_write_info(png_ptr, info_ptr); png_set_flush(png_ptr, 512); if (pixelformat == 32) { png_color_8 sig_bit; /* Save exact colour/alpha resolution */ sig_bit.alpha = 0; sig_bit.blue = 8; sig_bit.green = 8; sig_bit.red = 8; sig_bit.gray = 8; png_set_sBIT(png_ptr, info_ptr, &sig_bit); #if TTD_ENDIAN == TTD_LITTLE_ENDIAN png_set_bgr(png_ptr); png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); #else png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); #endif /* TTD_ENDIAN == TTD_LITTLE_ENDIAN */ } /* use by default 64k temp memory */ maxlines = Clamp(65536 / w, 16, 128); /* now generate the bitmap bits */ void *buff = CallocT<uint8>(w * maxlines * bpp); // by default generate 128 lines at a time. y = 0; do { /* determine # lines to write */ n = min(h - y, maxlines); /* render the pixels into the buffer */ callb(userdata, buff, y, w, n); y += n; /* write them to png */ for (i = 0; i != n; i++) png_write_row(png_ptr, (png_bytep)buff + i * w * bpp); } while (y != h); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); free(buff); fclose(f); return true; }