+#ifdef HAVE_LIBPNG
+/* write status callback */
+static
+void display_png_write_row_cb_(png_structp png_ptr, png_uint_32 row, int pass) {
+ (void)png_ptr, (void)row, (void)pass;
+ /*
+ fprintf(stderr, "%s:%u:%d\n", __func__, row, pass);
+ */
+}
+
+static
+void display_png_user_error_fn_(png_structp png_ptr, png_const_charp error_msg) {
+ (void)png_ptr;
+ fprintf(stderr, "PNG:ERROR:%s\n", error_msg);
+ exit(EX_SOFTWARE);
+}
+
+static
+void display_png_user_warning_fn_(png_structp png_ptr, png_const_charp warning_msg) {
+ (void)png_ptr;
+ fprintf(stderr, "PNG:WARNING:%s\n", warning_msg);
+ return;
+}
+
+/* write png file */
+static
+void display_png_write_(struct dcpu16_display_ *d) {
+ FILE *f;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ size_t i;
+
+ png_voidp user_error_ptr = NULL;
+
+#ifdef HAVE_FOPENCOOKIE
+ /* linux-style memory stream */
+ cookie_io_functions_t cookie_io_functions = {
+ .read = NULL,
+ .write = memstream_write_fn_,
+ .seek = NULL,
+ .close = NULL
+ };
+ f = fopencookie(&d->memstream_cookie, "wb", cookie_io_functions);
+ if (f == NULL) {
+ fprintf(stderr, "%s():%s\n", "fopencookie", strerror(errno));
+ return;
+ }
+
+#else /* HAVE_FOPENCOOKIE */
+#ifdef HAVE_FUNOPEN
+ /* BSD-style memory stream */
+ f = funopen(&d->memstream_cookie,
+ NULL, /* don't care about read */
+ memstream_write_fn_,
+ NULL, /* don't care about seek */
+ NULL /* don't care about close */
+ );
+ if (f == NULL) {
+ fprintf(stderr, "%s():%s\n", "funopen", strerror(errno));
+ return;
+ }
+
+#else /* HAVE_FUNOPEN */
+ /* default to writing file if we can't buffer in memory */
+ f = fopen(d->outfile, "wb");
+ if (f == NULL) {
+ return;
+ }
+#endif /* HAVE_FUNOPEN */
+#endif /* HAVE_FOPENCOOKIE */
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, display_png_user_error_fn_, display_png_user_warning_fn_);
+ if (png_ptr == NULL) {
+ goto f_done;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL) {
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ goto f_done;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ goto f_done;
+}
+
+ png_init_io(png_ptr, f);
+ png_set_write_status_fn(png_ptr, display_png_write_row_cb_);
+
+ /* png_set_filter(png_ptr, 0, PNG_FILTER_NONE); */
+ /* png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); */
+
+ png_set_IHDR(png_ptr, info_ptr, PIX_X, PIX_Y, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ png_write_info(png_ptr, info_ptr);
+
+ for (i = 0; i < PIX_Y; i++) {
+ png_write_row(png_ptr, (unsigned char *)(d->pixbuf + (i * PIX_X)));
+ }
+
+ png_write_end(png_ptr, info_ptr);
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+f_done:
+ fclose(f);
+}
+#else /* HAVE_LIBPNG */
+
+/* if PNG not available, just write pnm file */
+static
+void display_pnm_write_(struct dcpu16_display_ *d) {