From aee98e47696b6a5336bae22ac737834d763f35cc Mon Sep 17 00:00:00 2001
From: slevy <slevy>
Date: Wed, 26 Oct 2011 16:46:23 +0000
Subject: [PATCH] Use libpng for snapshotting if available.  Change default
 snapshot parameters:    - four digits by default    - use .png suffix if
 libpng available, or if unix (assumes "convert" available)    - use .ppm
 suffix if WIN32 and no libpng

---
 src/partiviewc.cc | 146 +++++++++++++++++++++++++++++++++++++---------
 1 file changed, 119 insertions(+), 27 deletions(-)

diff --git a/src/partiviewc.cc b/src/partiviewc.cc
index 2ab1790..23ce532 100644
--- a/src/partiviewc.cc
+++ b/src/partiviewc.cc
@@ -6,6 +6,7 @@
  * This file is part of partiview, released under the
  * Illinois Open Source License; see the file LICENSE.partiview for details.
  */
+#include "config.h"
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -26,6 +27,7 @@
 #include <math.h>
 #include <errno.h>
 #include <signal.h>
+#include <png.h>
 
 #include "specks.h"
 #include "partiview.H"
@@ -546,10 +548,12 @@ static int endswith(char *str, char *suf) {
 int parti_snapset( char *fname, char *frameno, char *imgsize )
 {
   int len;
-#if unix
-  static char suf[] = ".%03d.ppm.gz";
-#else
-  static char suf[] = ".%03d.ppm";
+#ifdef HAVE_PNG_H
+  static char suf[] = ".%04d.png";
+#elif unix
+  static char suf[] = ".%04d.ppm.gz";
+#else /* WIN32 */
+  static char suf[] = ".%04d.ppm";
 #endif
   int needsuf;
 
@@ -570,16 +574,84 @@ int parti_snapset( char *fname, char *frameno, char *imgsize )
   return ppui.snapfno;
 }
 
+
+#ifdef HAVE_PNG_H
+
+/* png image snapshotting */
+static png_structp png_ptr = NULL;
+static png_infop info_ptr = NULL;
+
+static void failpng() {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    msg("snapshot: error writing png header");
+}
+
+/* returns 0 on success, nonzero on failure */
+static int snappng( char *outfname, int xsize, int ysize, char *rgbbuf )
+{
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (png_ptr)
+	info_ptr = png_create_info_struct(png_ptr);
+    if(!info_ptr) {
+	msg("snapshot: can't init png library");
+	return 1;
+    }
+
+    if(setjmp(png_jmpbuf(png_ptr))) {
+	failpng();
+	return 1;
+    }
+
+    FILE *outf = fopen( outfname, "wb" );
+    if(outf == 0) {
+	return 1;
+    }
+
+    png_init_io( png_ptr, outf );
+
+    png_set_IHDR( png_ptr, info_ptr,
+		xsize, ysize, 8,/*bit depth*/
+		PNG_COLOR_TYPE_RGB,
+		PNG_INTERLACE_NONE,
+		PNG_COMPRESSION_TYPE_DEFAULT,
+		PNG_FILTER_TYPE_DEFAULT);
+
+    /* Don't really know that we're in sRGB color space, but let's say so anyway. */
+    png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_INFO_sRGB);
+
+    png_write_info( png_ptr, info_ptr );
+
+    png_bytep *rowps = new png_bytep[ysize];
+    for(int k = 0; k < ysize; k++)
+	rowps[k] = (png_bytep) &rgbbuf[k*xsize*3];
+    png_write_image( png_ptr, rowps );
+    delete rowps;
+
+    png_write_end(png_ptr, info_ptr);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    fclose(outf);
+    return 0;
+}
+
+#endif /* HAVE_PNG_H */
+
+
 int parti_snapshot( char *snapinfo )
 {
   char tfcmd[10240], *tftail;
   int fail;
+  int as_png = 0;
+
+#if defined(HAVE_PNG_H) || !WIN32
+  static char defsnap[] = "snap.%04d.png";
+#else
+  static char defsnap[] = "snap.%04d.ppm";
+#endif
+
 #if !WIN32  /* if unix */
-  static char defsnap[] = "snap.%03d.sgi";
   static char prefix[] = "|convert ppm:- ";
   static char gzprefix[] = "|gzip >";
 #else
-  static char defsnap[] = "snap.%03d.ppm";
   static char prefix[] = "";
 #endif
 
@@ -591,6 +663,14 @@ int parti_snapshot( char *snapinfo )
   
   if(ppui.snapfmt[0] == '|' || endswith(ppui.snapfmt, ".ppm")) {
     tfcmd[0] = '\0';
+
+#ifdef HAVE_PNG_H
+  } else if(endswith(ppui.snapfmt, ".png")) {
+    /* use built-in libpng writer if available */
+    as_png = 1;
+    tfcmd[0] = '\0';
+#endif
+
 #if unix
   } else if(endswith(ppui.snapfmt, ".ppm.gz")) {
     strcpy(tfcmd, gzprefix);
@@ -619,35 +699,47 @@ int parti_snapshot( char *snapinfo )
     return -2;
   }
 
-  FILE *p;
+  if(as_png) {
+#ifdef HAVE_PNG_H
+    fail = snappng( tfcmd, w, h, buf );
+#else
+    msg("Recompile with --with-libpng=... to write png images");
+    fail = 1;
+#endif
+
+  } else {
+     /* write ppm stream/file */
+    FILE *p;
 #if unix
-  void (*oldpipe)(int) = 0;
-  int popened = tfcmd[0] == '|';
-  if(popened) {
-    oldpipe = signal(SIGPIPE, SIG_IGN);
-    p = popen(tfcmd+1, "w");
-  } else
+    void (*oldpipe)(int) = 0;
+    int popened = tfcmd[0] == '|';
+    if(popened) {
+	oldpipe = signal(SIGPIPE, SIG_IGN);
+	p = popen(tfcmd+1, "w");
+    } else
 #endif
-    p = fopen(tfcmd, "wb");
+	p = fopen(tfcmd, "wb");
 
-  fprintf(p, "P6\n%d %d\n255\n", w, h);
-  for(y = h; --y >= 0 && fwrite(&buf[w*3*y], w*3, 1, p) > 0; )
-    ;
-  free(buf);
-  fflush(p);
-  fail = ferror(p);
+	fprintf(p, "P6\n%d %d\n255\n", w, h);
+	for(y = h; --y >= 0 && fwrite(&buf[w*3*y], w*3, 1, p) > 0; )
+	    ;
+	free(buf);
+	fflush(p);
+	fail = ferror(p) || y >= 0;
 
 #if unix
-  if(popened) {
-    pclose(p);
-    signal(SIGPIPE, oldpipe);
-  }
-  else
+	if(popened) {
+	    pclose(p);
+	    signal(SIGPIPE, oldpipe);
+	}
+	else
 #endif
-    fclose(p);  /* win32 */
+	    fclose(p);  /* win32 */
+    /* end of "write ppm" case */
+  }
 
 
-  if(y >= 0 || fail) {
+  if(fail) {
     msg("snapshot: Error writing to %s", tfcmd);
     return -1;
   }
-- 
GitLab