Index: /trunk/psLib/configure.ac
===================================================================
--- /trunk/psLib/configure.ac	(revision 29541)
+++ /trunk/psLib/configure.ac	(revision 29542)
@@ -202,4 +202,82 @@
 CPPFLAGS=${TMP_CPPFLAGS}
 
+dnl ------------------ kapa,libkapa options -------------------------
+dnl -- libkapa implies the requirement for libpng, libjpeg as well --
+
+dnl save LIBS/CFLAGS/LDFLAGS
+TMP_LIBS=${LIBS}
+TMP_CFLAGS=${CFLAGS}
+TMP_LDFLAGS=${LDFLAGS}
+TMP_CPPFLAGS=${CPPFLAGS}
+
+dnl test for command-line options: use ohana-config if not supplied
+KAPA_CFLAGS_CONFIG="true"
+KAPA_LIBS_CONFIG="true"
+AC_ARG_WITH(kapa,
+[AS_HELP_STRING(--with-kapa=DIR,Specify location of libkapa)],
+[KAPA_CFLAGS="-I$withval/include" KAPA_LIBS="-L$withval/lib" 
+ KAPA_CFLAGS_CONFIG="false"       KAPA_LIBS_CONFIG="false"])
+AC_ARG_WITH(kapa-include,
+[AS_HELP_STRING(--with-kapa-include=DIR,Specify libkapa include directory.)],
+[KAPA_CFLAGS="-I$withval" KAPA_CFLAGS_CONFIG="false"])
+AC_ARG_WITH(kapa-lib,
+[AS_HELP_STRING(--with-kapa-lib=DIR,Specify libkapa library directory.)],
+[KAPA_LIBS="-L$withval" KAPA_LIBS_CONFIG="false"])
+
+echo "KAPA_CFLAGS_CONFIG: $KAPA_CFLAGS_CONFIG"
+echo "KAPA_LIBS_CONFIG: $KAPA_LIBS_CONFIG"
+echo "KAPA_CFLAGS: $KAPA_CFLAGS"
+echo "KAPA_LIBS: $KAPA_LIBS"
+
+dnl HAVE_KAPA is set to false if any of the tests fail
+HAVE_KAPA="true"
+AC_MSG_NOTICE([checking for libkapa])
+if test "$KAPA_CFLAGS_CONFIG" = "true" -o "$KAPA_LIBS_CONFIG" = "true"; then
+  AC_MSG_NOTICE([kapa info supplied by ohana-config])
+  KAPA_CONFIG=`which ohana-config`
+  AC_CHECK_FILE($KAPA_CONFIG,[],
+    [HAVE_KAPA="false"; AC_MSG_WARN([libkapa is not found: output plots disabled.  Obtain libkapa at http://kiawe.ifa.hawaii.edu/Elixir/Ohana or use --with-kapa to specify location])])
+  
+  echo "HAVE_KAPA: $HAVE_KAPA"
+  echo "KAPA_CFLAGS_CONFIG: $KAPA_CFLAGS_CONFIG"
+
+  if test "$HAVE_KAPA" = "true" -a "$KAPA_CFLAGS_CONFIG" = "true" ; then
+   AC_MSG_NOTICE([libkapa cflags info supplied by ohana-config])
+   AC_MSG_CHECKING([libkapa cflags])
+   KAPA_CFLAGS="`${KAPA_CONFIG} --cflags`"
+   AC_MSG_RESULT([${KAPA_CFLAGS}])
+  fi
+
+  if test "$HAVE_KAPA" = "true" -a "$KAPA_LIBS_CONFIG" = "true" ; then
+   AC_PATH_X
+   if test "$no_x" = "yes" ; then
+      AC_MSG_WARN([X11 not found: output plots using kapa disabled.  Use --x-includes and --x-libraries if required.])
+      HAVE_KAPA="false"
+   else
+      AC_MSG_NOTICE([libkapa ldflags info supplied by ohana-config])
+      AC_MSG_CHECKING([libkapa ldflags])
+      if test -n "$x_libraries" ; then
+            KAPA_LIBS="`${KAPA_CONFIG} --libs` -L$x_libraries -lX11"
+      else
+            KAPA_LIBS="`${KAPA_CONFIG} --libs` -lX11"
+      fi
+      if test -n "$x_includes" ; then
+            KAPA_CFLAGS="${KAPA_CFLAGS} -I$x_includes"
+      else
+            KAPA_CFLAGS="${KAPA_CFLAGS}"
+      fi
+      AC_MSG_RESULT([${KAPA_LIBS}])
+   fi
+  fi
+fi
+
+if test "$HAVE_KAPA" = "true" ; then
+ AC_MSG_NOTICE([libkapa supplied])
+ PSLIB_CFLAGS="${PSLIB_CFLAGS} ${KAPA_CFLAGS}"
+ PSLIB_LIBS="${PSLIB_LIBS} ${KAPA_LIBS}"
+else
+ AC_MSG_NOTICE([libkapa ignored])
+fi
+
 dnl ------------------ libjpeg options ---------------------
 
@@ -239,4 +317,53 @@
 LDFLAGS=${TMP_LDFLAGS}
 CPPFLAGS=${TMP_CPPFLAGS}
+
+dnl ------------------ libpng options ---------------------
+
+dnl save LIBS/CFLAGS/LDFLAGS
+TMP_LIBS=${LIBS}
+TMP_CFLAGS=${CFLAGS}
+TMP_LDFLAGS=${LDFLAGS}
+TMP_CPPFLAGS=${CPPFLAGS}
+
+AC_ARG_WITH(png,
+[AS_HELP_STRING(--with-png=DIR,Specify location of libpng.)],
+[PNG_CFLAGS="-I$withval/include"
+ PNG_LDFLAGS="-L$withval/lib"])
+AC_ARG_WITH(png-include,
+[AS_HELP_STRING(--with-png-include=DIR,Specify libpng include directory.)],
+[PNG_CFLAGS="-I$withval"])
+AC_ARG_WITH(png-lib,
+[AS_HELP_STRING(--with-png-lib=DIR,Specify libpng library directory.)],
+[PNG_LDFLAGS="-L$withval"])
+
+CFLAGS="${CFLAGS} ${PNG_CFLAGS}"
+CPPFLAGS=${CFLAGS}
+LDFLAGS="${LDFLAGS} ${PNG_LDFLAGS}"
+
+AC_CHECK_HEADERS([png.h],
+  [PSLIB_CFLAGS="$PSLIB_CFLAGS $PNG_CFLAGS" AC_SUBST(PNG_CFLAGS)],
+  [HAVE_KAPA=false; AC_MSG_WARN([libpng headers not found: output plots disabled.  Obtain libpng from http://www.ijg.org/ or use --with-png to specify location.])]
+)
+
+AC_CHECK_LIB(png,png_init_io,
+  [PSLIB_LIBS="$PSLIB_LIBS $PNG_LDFLAGS -lpng"],
+  [HAVE_KAPA=false; AC_MSG_WARN([libpng library not found: output plots disabled.  Obtain libpng from http://www.ijg.org/ or use --with-png to specify location.])]
+)
+
+dnl restore the CFLAGS/LDFLAGS
+LIBS=${TMP_LIBS}
+CFLAGS=${TMP_CFLAGS}
+LDFLAGS=${TMP_LDFLAGS}
+CPPFLAGS=${TMP_CPPFLAGS}
+
+dnl ------------------ use kapa or not? ---------------------
+
+if test "$HAVE_KAPA" == "true" ; then
+  AC_MSG_RESULT([including plotting functions])
+  AC_DEFINE([HAVE_KAPA],[1],[enable use of libkapa])
+else
+  AC_MSG_RESULT([skipping plotting functions])
+  AC_DEFINE([HAVE_KAPA],[0],[disable use of libkapa])
+fi
 
 dnl ------------------- SWIG options ---------------------
Index: /trunk/psLib/src/jpeg/psImageJpeg.c
===================================================================
--- /trunk/psLib/src/jpeg/psImageJpeg.c	(revision 29541)
+++ /trunk/psLib/src/jpeg/psImageJpeg.c	(revision 29542)
@@ -15,359 +15,366 @@
 #include "psImageJpeg.h"
 
+/* XXX this to do to make this reasonably complete
+ * update bDraw APIs to accept a bDrawBuffer structure as an input operand
+ */
+
 #ifdef HAVE_STDLIB_H
 // jpeglib.h includes jconfig.h which is full of autoconf generated HAVE_*
 // defines. This is a hack to work around CPP redefinition errors.  Arrrrrgh!!!
 // -JH
+
+// XXX specifically, jconfig.h has defines like the following.  these
+// could be individually tested here and specifically undefed. EAM.
+// #define HAVE_PROTOTYPES 
+// #define HAVE_UNSIGNED_CHAR 
+// #define HAVE_UNSIGNED_SHORT 
+
 # undef HAVE_STDLIB_H
 # include <jpeglib.h>
 #endif // ifdef HAVE_STDLIB_H
 
-static void imageJpegColormapFree(psImageJpegColormap *map)
+static void imageJpegOptionsFree(psImageJpegOptions *options)
 {
 
-    if (!map) {
-        return;
-    }
-
-    psFree(map->red);
-    psFree(map->green);
-    psFree(map->blue);
+  if (!options) {
     return;
-}
-
-psImageJpegColormap *psImageJpegColormapAlloc(void)
+  }
+
+  psFree(options->red);
+  psFree(options->green);
+  psFree(options->blue);
+  return;
+}
+
+psImageJpegOptions *psImageJpegOptionsAlloc(void)
 {
-    psImageJpegColormap *map = psAlloc(sizeof(psImageJpegColormap));
-    psMemSetDeallocator(map, (psFreeFunc)imageJpegColormapFree);
-
-    map->red   = psVectorAlloc(256, PS_TYPE_U8);
-    map->blue  = psVectorAlloc(256, PS_TYPE_U8);
-    map->green = psVectorAlloc(256, PS_TYPE_U8);
-
-    return map;
-}
-
-psImageJpegColormap *psImageJpegColormapSet(psImageJpegColormap *map, const char *name)
+
+  psImageJpegOptions *options = psAlloc(sizeof(psImageJpegOptions));
+  psMemSetDeallocator(options, (psFreeFunc)imageJpegOptionsFree);
+
+  options->red   = psVectorAlloc(256, PS_TYPE_U8);
+  options->blue  = psVectorAlloc(256, PS_TYPE_U8);
+  options->green = psVectorAlloc(256, PS_TYPE_U8);
+
+  options->min = 0.0;
+  options->max = 1000.0;
+
+  options->xFlip = false;
+  options->yFlip = false;
+  options->showScale = PS_JPEG_SHOWSCALE_BOTTOM;
+
+  psImageJpegColormapSet(options, "greyscale");
+
+  return options;
+}
+
+bool psImageJpegColormapSet(psImageJpegOptions *options, const char *name)
 {
-
-    if (!map) {
-        map = psImageJpegColormapAlloc ();
-    }
-
-    /* grayscale */
-    if ((!strcasecmp (name, "grayscale")) || (!strcasecmp (name, "greyscale"))) {
-        for (int i = 0; i < map->red->n; i++) {
-            map->red->data.U8[i]   = PS_JPEG_RANGELIM(i);
-            map->green->data.U8[i] = PS_JPEG_RANGELIM(i);
-            map->blue->data.U8[i]  = PS_JPEG_RANGELIM(i);
-        }
-        return map;
-    }
-
-    /* -grayscale */
-    if ((!strcasecmp (name, "-grayscale")) || (!strcasecmp (name, "-greyscale"))) {
-        for (int i = 0; i < map->red->n; i++) {
-            map->red->data.U8[i]   = PS_JPEG_RANGELIM(256 - i);
-            map->green->data.U8[i] = PS_JPEG_RANGELIM(256 - i);
-            map->blue->data.U8[i]  = PS_JPEG_RANGELIM(256 - i);
-        }
-        return map;
-    }
-
-    /* rainbow */
-    if (!strcasecmp (name, "rainbow")) {
-        int I1 = 0.25*map->red->n;
-        int I2 = 0.50*map->red->n;
-        int I3 = 0.75*map->red->n;
-        for (int i = 0; i < I1; i++) {
-            map->red->data.U8[i]   = 0;
-            map->green->data.U8[i] = 0;
-            map->blue->data.U8[i]  = PS_JPEG_RANGELIM(4*i);
-        }
-        for (int i = I1; i < I2; i++) {
-            map->red->data.U8[i]   = PS_JPEG_RANGELIM(4*(i - I1));
-            map->green->data.U8[i] = 0;
-            map->blue->data.U8[i]  = PS_JPEG_RANGELIM(4*(I2 - i));
-        }
-        for (int i = I2; i < I3; i++) {
-            map->red->data.U8[i]   = 255;
-            map->green->data.U8[i] = 4*(i - I2);
-            map->blue->data.U8[i]  = 0;
-        }
-        for (int i = I3; i < map->red->n; i++) {
-            map->red->data.U8[i]   = 255;
-            map->green->data.U8[i] = 255;
-            map->blue->data.U8[i]  = PS_JPEG_RANGELIM(4*(i - I3));
-        }
-        return map;
-    }
-
-    /* heat */
-    if (!strcasecmp (name, "heat")) {
-        int I1 = 0.25*map->red->n;
-        int I2 = 0.50*map->red->n;
-        int I3 = 0.75*map->red->n;
-        for (int i = 0; i < I1; i++) {
-            map->red->data.U8[i]   = PS_JPEG_RANGELIM(2*i);
-            map->green->data.U8[i] = 0;
-            map->blue->data.U8[i]  = 0;
-        }
-        for (int i = I1; i < I2; i++) {
-            map->red->data.U8[i]   = PS_JPEG_RANGELIM(2*i);
-            map->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1));
-            map->blue->data.U8[i]  = 0;
-        }
-        for (int i = I2; i < I3; i++) {
-            map->red->data.U8[i]   = 255;
-            map->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1));
-            map->blue->data.U8[i]  = PS_JPEG_RANGELIM(2*(i - I2));
-        }
-        for (int i = I3; i < map->red->n; i++) {
-            map->red->data.U8[i]   = 255;
-            map->green->data.U8[i] = 255;
-            map->blue->data.U8[i]  = PS_JPEG_RANGELIM(2*(i - I2));
-        }
-        return map;
-    }
-
-    // invalid colormap: warn user
-    psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Invalid colormap name: %s --- using greyscale\n", name);
-    return psImageJpegColormapSet (map, "greyscale");
-}
-
-// XXX need to fix library references for this (psLib does not depend on libkapa)
-# if (0)
-// XXX Add colormap bar with scale (min -> max)
-// XXX Add option to plot the source overlay (pass in bDrawBuffer populated with points?)
+  PS_ASSERT_PTR_NON_NULL(options, false);
+
+  /* grayscale */
+  if ((!strcasecmp (name, "grayscale")) || (!strcasecmp (name, "greyscale"))) {
+    for (int i = 0; i < options->red->n; i++) {
+      options->red->data.U8[i]   = PS_JPEG_RANGELIM(i);
+      options->green->data.U8[i] = PS_JPEG_RANGELIM(i);
+      options->blue->data.U8[i]  = PS_JPEG_RANGELIM(i);
+    }
+    options->white = 255;
+    options->black = 0;
+    return options;
+  }
+
+  /* -grayscale */
+  if ((!strcasecmp (name, "-grayscale")) || (!strcasecmp (name, "-greyscale"))) {
+    for (int i = 0; i < options->red->n; i++) {
+      options->red->data.U8[i]   = PS_JPEG_RANGELIM(256 - i);
+      options->green->data.U8[i] = PS_JPEG_RANGELIM(256 - i);
+      options->blue->data.U8[i]  = PS_JPEG_RANGELIM(256 - i);
+    }
+    options->white = 0;
+    options->black = 255;
+    return options;
+  }
+
+  /* rainbow */
+  if (!strcasecmp (name, "rainbow")) {
+    int I1 = 0.25*options->red->n;
+    int I2 = 0.50*options->red->n;
+    int I3 = 0.75*options->red->n;
+    for (int i = 0; i < I1; i++) {
+      options->red->data.U8[i]   = 0;
+      options->green->data.U8[i] = 0;
+      options->blue->data.U8[i]  = PS_JPEG_RANGELIM(4*i);
+    }
+    for (int i = I1; i < I2; i++) {
+      options->red->data.U8[i]   = PS_JPEG_RANGELIM(4*(i - I1));
+      options->green->data.U8[i] = 0;
+      options->blue->data.U8[i]  = PS_JPEG_RANGELIM(4*(I2 - i));
+    }
+    for (int i = I2; i < I3; i++) {
+      options->red->data.U8[i]   = 255;
+      options->green->data.U8[i] = 4*(i - I2);
+      options->blue->data.U8[i]  = 0;
+    }
+    for (int i = I3; i < options->red->n; i++) {
+      options->red->data.U8[i]   = 255;
+      options->green->data.U8[i] = 255;
+      options->blue->data.U8[i]  = PS_JPEG_RANGELIM(4*(i - I3));
+    }
+    options->white = 255;
+    options->black = 0;
+    return options;
+  }
+
+  /* heat */
+  if (!strcasecmp (name, "heat")) {
+    int I1 = 0.25*options->red->n;
+    int I2 = 0.50*options->red->n;
+    int I3 = 0.75*options->red->n;
+    for (int i = 0; i < I1; i++) {
+      options->red->data.U8[i]   = PS_JPEG_RANGELIM(2*i);
+      options->green->data.U8[i] = 0;
+      options->blue->data.U8[i]  = 0;
+    }
+    for (int i = I1; i < I2; i++) {
+      options->red->data.U8[i]   = PS_JPEG_RANGELIM(2*i);
+      options->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1));
+      options->blue->data.U8[i]  = 0;
+    }
+    for (int i = I2; i < I3; i++) {
+      options->red->data.U8[i]   = 255;
+      options->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1));
+      options->blue->data.U8[i]  = PS_JPEG_RANGELIM(2*(i - I2));
+    }
+    for (int i = I3; i < options->red->n; i++) {
+      options->red->data.U8[i]   = 255;
+      options->green->data.U8[i] = 255;
+      options->blue->data.U8[i]  = PS_JPEG_RANGELIM(2*(i - I2));
+    }
+    options->white = 255;
+    options->black = 0;
+    return options;
+  }
+
+  // invalid colormap: warn user 
+  psWarning("Invalid colormap name: %s --- using greyscale\n", name);
+  return psImageJpegColormapSet (options, "greyscale");
+}
+
+bDrawBuffer *psImageJpegOverlayInit (const psImage *image) {
+
+  int dx = image->numCols;
+  int dy = image->numRows;
+  
+  bDrawBuffer *bdbuf = bDrawBufferCreate(dx, dy);
+
+  return bdbuf;
+}
+
+// copy the buffer pixels which are not white (probably should be "not blank")
+bool psImageJpegOverlayDraw (JSAMPLE *jpegImage, bDrawBuffer *bdbuf, int offX, int offY) {
+
+  // XXX check valid limits
+
+  int dx = bdbuf->Nx;
+  int dy = bdbuf->Ny;
+
+  int Npalette;
+  png_color *palette = KapaPNGPalette (&Npalette);
+  bDrawColor white = KapaColorByName ("white");
+  for (int j = 0; j < dy; j++) {
+    for (int i = 0; i < dx; i++) {
+      bDrawColor color = bdbuf->pixels[j][i];
+      if (color == white) continue;
+      jpegImage[(j + offY)*3*dx + 3*(i + offX) + 0] = palette[color].red;
+      jpegImage[(j + offY)*3*dx + 3*(i + offX) + 1] = palette[color].green;
+      jpegImage[(j + offY)*3*dx + 3*(i + offX) + 2] = palette[color].blue;
+    }
+  }
+  return true;
+}
+
+bool sprint_double (char *string, double value) {
+
+  int Nexp = fabs(log10(fabs(value)));
+  
+  if (Nexp > 3) {
+    sprintf (string, "%.1e", value);
+  } else {
+    sprintf (string, "%.1f", value);
+  }
+  return true;
+}
+
 // XXX need to update bDraw APIs to pass in/out structure and avoid the local static 
-bool psImageJpegNew(const psImageJpegColormap *map, const psImage *image, const char *filename,
-                 float min, float max)
+bool psImageJpeg(const psImageJpegOptions *options, const psImage *image, bDrawBuffer *bdbuf, const char *filename)
 {
-    PS_ASSERT_PTR_NON_NULL(map, false);
-    PS_ASSERT_IMAGE_NON_NULL(image, false);
-    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
-    PS_ASSERT_VECTOR_NON_NULL(map->red, false);
-    PS_ASSERT_VECTOR_NON_NULL(map->green, false);
-    PS_ASSERT_VECTOR_NON_NULL(map->blue, false);
-    PS_ASSERT_PTR_NON_NULL(filename, false);
-    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
-    PS_ASSERT_FLOAT_REAL(min, false);
-    PS_ASSERT_FLOAT_REAL(max, false);
-
-    float zero, scale;
-    struct jpeg_compress_struct cinfo;
-    struct jpeg_error_mgr jerr;
-
-    long pixel;
-    JSAMPLE *jpegLine;   // Points to data for current line
-    JSAMPROW jpegLineList[1];  // pointer to JSAMPLE row[s]
-    JSAMPLE *jpegImage;
-    JSAMPLE *outPix;
-
-    /* JPEG init calls */
-    cinfo.err = jpeg_std_error (&jerr);
-    jpeg_create_compress (&cinfo);
-
-    /* open file, prep for jpeg */
-    FILE *f = fopen(filename, "w");
-    if (!f) {
-	psError(PS_ERR_IO, true, "failed to open %s for output\n", filename);
-	return false;
-    }
-    jpeg_stdio_dest(&cinfo, f);
-
-    /* set up color jpeg buffers */
-    int quality = 75;
-    cinfo.image_width = image->numCols; // image width and height, in pixels
-    cinfo.image_height = image->numRows;
-    cinfo.input_components = 3;
-    cinfo.in_color_space = JCS_RGB;
-    jpeg_set_defaults (&cinfo);
-    jpeg_set_quality (&cinfo, quality, true); // limit to baseline-JPEG values
-    jpeg_start_compress (&cinfo, true);
-
-    psU8 *Rpix = map->red->data.U8;
-    psU8 *Gpix = map->green->data.U8;
-    psU8 *Bpix = map->blue->data.U8;
-
-    if (max == min) {
-	zero = min - 0.1;
-	scale = 256.0/0.2;
-    } else {
-	zero = min;
-	scale = 256.0/(max - min);
-    }
-
-    int dx = image->numCols;
-    int dy = image->numRows;
-
-    // output image buffer and line buffer
-    jpegLine = psAlloc (3*dx*sizeof(JSAMPLE));
-    jpegImage = psAlloc (3*dx*dy*sizeof(JSAMPLE));
-
-    // first copy the image data into the output buffer 
-    for (int j = 0; j < dy; j++) {
-	psF32 *row = image->data.F32[j];
-
-	outPix = jpegLine;
-	for (int i = 0; i < dx; i++, outPix += 3) {
-	    if (isfinite(row[i])) {
-		pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale);
-		outPix[0] = Rpix[pixel];
-		outPix[1] = Gpix[pixel];
-		outPix[2] = Bpix[pixel];
-	    } else {
-		// XXX NAN value should be set per-color map
-		outPix[0] = 0x00;
-		outPix[1] = 0xff;
-		outPix[2] = 0x00;
-	    }
-	}
-	memcpy (&jpegImage[j*3*dx], jpegLine, 3*dx);
-    }
-
-    bDrawBuffer *bdbuf = bDrawBufferCreate(dx, dy);
-    bDrawSetBuffer(bdbuf);
-    bDrawColor red = KapaColorByName("red");
-    bDrawSetStyle (red, 1, 0);
-    bDrawCircle(40.0, 20.0, 3.0);
-
-    {
-	int Npalette;
-	png_color *palette = KapaPNGPalette (&Npalette);
-	bDrawColor white = KapaColorByName ("white");
-	for (int j = 0; j < dy; j++) {
-	    for (int i = 0; i < dx; i++) {
-		bDrawColor color = bdbuf[0].pixels[j][i];
-		if (color == white) continue;
-		jpegImage[j*3*dx + 3*i + 0] = palette[color].red;
-		jpegImage[j*3*dx + 3*i + 1] = palette[color].green;
-		jpegImage[j*3*dx + 3*i + 2] = palette[color].blue;
-	    }
-	}
-    }
-    bDrawBufferFree (bdbuf);
-
-    // write out the image buffer
-    for (int j = 0; j < image->numRows; j++) {
-	jpegLineList[0] = &jpegImage[j*3*dx];
-	if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) {
-	    psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j);
-	    psFree(jpegLine);
-	    psFree(jpegImage);
-	    fclose(f);
-	    return false;
-	}
-    }
-
-    jpeg_finish_compress(&cinfo);
-    if (fclose(f) == EOF) {
-	psError(PS_ERR_IO, true, "Failed to close %s", filename);
-	psFree(jpegLine);
-	psFree(jpegImage);
-	return false;
-    }
-    jpeg_destroy_compress(&cinfo);
-
+  PS_ASSERT_PTR_NON_NULL(options, false);
+  PS_ASSERT_VECTOR_NON_NULL(options->red, false);
+  PS_ASSERT_VECTOR_NON_NULL(options->green, false);
+  PS_ASSERT_VECTOR_NON_NULL(options->blue, false);
+  PS_ASSERT_FLOAT_REAL(options->min, false);
+  PS_ASSERT_FLOAT_REAL(options->max, false);
+  PS_ASSERT_IMAGE_NON_NULL(image, false);
+  PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
+  PS_ASSERT_PTR_NON_NULL(filename, false);
+  PS_ASSERT_INT_POSITIVE(strlen(filename), false);
+
+  float zero, scale;
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+
+  long pixel;
+  JSAMPLE *jpegLine;   // Points to data for current line
+  JSAMPROW jpegLineList[1];  // pointer to JSAMPLE row[s]
+  JSAMPLE *jpegImage;
+  JSAMPLE *outPix;
+
+  /* JPEG init calls */
+  cinfo.err = jpeg_std_error (&jerr);
+  jpeg_create_compress (&cinfo);
+
+  /* open file, prep for jpeg */
+  FILE *f = fopen(filename, "w");
+  if (!f) {
+    psError(PS_ERR_IO, true, "failed to open %s for output\n", filename);
+    return false;
+  }
+  jpeg_stdio_dest(&cinfo, f);
+
+  /* set up color jpeg buffers */
+  int quality = 75;
+  cinfo.image_width = image->numCols; // image width and height, in pixels
+  cinfo.image_height = image->numRows;
+
+  if (options->showScale != PS_JPEG_SHOWSCALE_NONE) {
+    cinfo.image_height += PS_JPEG_COLORPAD + PS_JPEG_LABELPAD;
+  }
+
+  cinfo.input_components = 3;
+  cinfo.in_color_space = JCS_RGB;
+  jpeg_set_defaults (&cinfo);
+  jpeg_set_quality (&cinfo, quality, true); // limit to baseline-JPEG values
+  jpeg_start_compress (&cinfo, true);
+
+  psU8 *Rpix = options->red->data.U8;
+  psU8 *Gpix = options->green->data.U8;
+  psU8 *Bpix = options->blue->data.U8;
+
+  if (options->max == options->min) {
+    zero = options->min - 0.1;
+    scale = 256.0/0.2;
+  } else {
+    zero = options->min;
+    scale = 256.0/(options->max - options->min);
+  }
+
+  // dx,dy is the size of the image itself.  the drawing window may be larger
+  // by the size of the scalebar (depending on the location)
+
+  int dx = image->numCols;
+  int dy = image->numRows;
+  int Nx = cinfo.image_width;
+  int Ny = cinfo.image_height;
+
+  // output image buffer and line buffer
+  jpegLine = psAlloc (3*Nx*sizeof(JSAMPLE));
+  jpegImage = psAlloc (3*Nx*Ny*sizeof(JSAMPLE));
+
+  // first copy the image data into the output buffer 
+  // output image ranges from offset to offset + dy
+  int offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? PS_JPEG_COLORPAD + PS_JPEG_LABELPAD : 0;
+  for (int j = 0; j < dy; j++) {
+
+    psF32 *row = options->yFlip ? image->data.F32[j] : image->data.F32[dy - j - 1];
+
+    outPix = options->xFlip ?  jpegLine + 3*(dx - 1) : jpegLine;
+    int delta = options->xFlip ? -3 : 3;
+    for (int i = 0; i < dx; i++, outPix += delta) {
+      if (isfinite(row[i])) {
+	pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale);
+	outPix[0] = Rpix[pixel];
+	outPix[1] = Gpix[pixel];
+	outPix[2] = Bpix[pixel];
+      } else {
+	// XXX NAN value should be set per-color map
+	outPix[0] = 0x00;
+	outPix[1] = 0xff;
+	outPix[2] = 0x00;
+      }
+    }
+    memcpy (&jpegImage[(j + offset)*3*dx], jpegLine, 3*dx);
+  }
+
+  if (options->showScale != PS_JPEG_SHOWSCALE_NONE) {
+    offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? 0 : dy;
+    zero = 0;
+    scale = 256.0 / dx;
+    for (int j = 0; j < PS_JPEG_COLORPAD; j++) {
+      outPix = jpegLine;
+      for (int i = 0; i < dx; i++, outPix += 3) {
+	pixel = PS_JPEG_SCALEVALUE(i, zero, scale);
+	outPix[0] = Rpix[pixel];
+	outPix[1] = Gpix[pixel];
+	outPix[2] = Bpix[pixel];
+      }
+      memcpy (&jpegImage[(j + offset)*3*dx], jpegLine, 3*dx);
+    }
+
+    // set the LABEL region to white
+    psU8 white = options->white;
+    offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? PS_JPEG_COLORPAD : PS_JPEG_COLORPAD + dy; 
+    for (int j = 0; j < PS_JPEG_LABELPAD; j++) {
+      outPix = jpegLine;
+      for (int i = 0; i < dx; i++, outPix += 3) {
+	outPix[0] = Rpix[white];
+	outPix[1] = Gpix[white];
+	outPix[2] = Bpix[white];
+      }
+      memcpy (&jpegImage[(j + offset)*3*dx], jpegLine, 3*dx);
+    }
+
+    // set the scalebar labels
+    char string[64];
+    bDrawBuffer *labels = bDrawBufferCreate(dx, PS_JPEG_LABELPAD);
+    SetRotFont ("helvetica", 8);
+    bDrawSetBuffer(labels);
+    sprint_double (string, options->min);
+    bDrawRotText(2, 2, string, 2, 0.0);
+    sprint_double (string, options->max);
+    bDrawRotText(dx - 2, 2, string, 0, 0.0);
+    sprint_double (string, 0.5*(options->min + options->max));
+    bDrawRotText(0.5*dx, 2, string, 1, 0.0);
+    psImageJpegOverlayDraw(jpegImage, labels, 0, offset);
+  }
+    
+  if (bdbuf) {
+    offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? PS_JPEG_COLORPAD + PS_JPEG_LABELPAD : 0;
+    psImageJpegOverlayDraw(jpegImage, bdbuf, 0, offset);
+  }
+
+  // write out the image buffer
+  for (int j = 0; j < Ny; j++) {
+    jpegLineList[0] = &jpegImage[j*3*dx];
+    if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) {
+      psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j);
+      psFree(jpegLine);
+      psFree(jpegImage);
+      fclose(f);
+      return false;
+    }
+  }
+
+  jpeg_finish_compress(&cinfo);
+  if (fclose(f) == EOF) {
+    psError(PS_ERR_IO, true, "Failed to close %s", filename);
     psFree(jpegLine);
     psFree(jpegImage);
-    return true;
-}
-# endif
-
-bool psImageJpeg(const psImageJpegColormap *map, const psImage *image, const char *filename,
-                 float min, float max)
-{
-    PS_ASSERT_PTR_NON_NULL(map, false);
-    PS_ASSERT_IMAGE_NON_NULL(image, false);
-    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
-    PS_ASSERT_VECTOR_NON_NULL(map->red, false);
-    PS_ASSERT_VECTOR_NON_NULL(map->green, false);
-    PS_ASSERT_VECTOR_NON_NULL(map->blue, false);
-    PS_ASSERT_PTR_NON_NULL(filename, false);
-    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
-    PS_ASSERT_FLOAT_REAL(min, false);
-    PS_ASSERT_FLOAT_REAL(max, false);
-
-    float zero, scale;
-    struct jpeg_compress_struct cinfo;
-    struct jpeg_error_mgr jerr;
-
-    long pixel;
-    JSAMPLE *jpegLine;   // Points to data for current line
-    JSAMPROW jpegLineList[1];  // pointer to JSAMPLE row[s]
-    JSAMPLE *outPix;
-
-    /* JPEG init calls */
-    cinfo.err = jpeg_std_error (&jerr);
-    jpeg_create_compress (&cinfo);
-
-    /* open file, prep for jpeg */
-    FILE *f = fopen(filename, "w");
-    if (!f) {
-        psError(PS_ERR_IO, true, "failed to open %s for output\n", filename);
-        return false;
-    }
-    jpeg_stdio_dest(&cinfo, f);
-
-    /* set up color jpeg buffers */
-    int quality = 75;
-    cinfo.image_width = image->numCols; // image width and height, in pixels
-    cinfo.image_height = image->numRows;
-    cinfo.input_components = 3;
-    cinfo.in_color_space = JCS_RGB;
-    jpeg_set_defaults (&cinfo);
-    jpeg_set_quality (&cinfo, quality, true); // limit to baseline-JPEG values
-    jpeg_start_compress (&cinfo, true);
-
-    jpegLine = psAlloc (3*image->numCols*sizeof(JSAMPLE));
-    jpegLineList[0] = jpegLine;
-
-    psU8 *Rpix = map->red->data.U8;
-    psU8 *Gpix = map->green->data.U8;
-    psU8 *Bpix = map->blue->data.U8;
-
-    if (max == min) {
-        zero = min - 0.1;
-        scale = 256.0/0.2;
-    } else {
-        zero = min;
-        scale = 256.0/(max - min);
-    }
-
-    for (int j = 0; j < image->numRows; j++) {
-        psF32 *row = image->data.F32[j];
-
-        outPix = jpegLine;
-        for (int i = 0; i < image->numCols; i++, outPix += 3) {
-            if (isfinite(row[i])) {
-                pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale);
-                outPix[0] = Rpix[pixel];
-                outPix[1] = Gpix[pixel];
-                outPix[2] = Bpix[pixel];
-            } else {
-                // XXX NAN value should be set per-color map
-                outPix[0] = 0xff;
-                outPix[1] = 0x00;
-                outPix[2] = 0xff;
-            }
-        }
-        if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) {
-            psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j);
-            psFree(jpegLine);
-            return false;
-        }
-    }
-
-    jpeg_finish_compress(&cinfo);
-    if (fclose(f) == EOF) {
-        psError(PS_ERR_IO, true, "Failed to close %s", filename);
-        psFree(jpegLine);
-        return false;
-    }
-    jpeg_destroy_compress(&cinfo);
-
-    psFree(jpegLine);
-
-    return true;
-}
+    return false;
+  }
+  jpeg_destroy_compress(&cinfo);
+
+  psFree(jpegLine);
+  psFree(jpegImage);
+  return true;
+}
Index: /trunk/psLib/src/jpeg/psImageJpeg.h
===================================================================
--- /trunk/psLib/src/jpeg/psImageJpeg.h	(revision 29541)
+++ /trunk/psLib/src/jpeg/psImageJpeg.h	(revision 29542)
@@ -15,31 +15,47 @@
 #include "psImage.h"
 
-typedef struct
-{
-    psVector *red;                      // Red colormap
-    psVector *green;                    // Green colormap
-    psVector *blue;                     // Blue colormap
-}
-psImageJpegColormap;
+typedef enum {
+  PS_JPEG_SHOWSCALE_NONE,
+  PS_JPEG_SHOWSCALE_TOP,
+  PS_JPEG_SHOWSCALE_BOTTOM
+} psImageJpegShowScaleOption;  
+
+typedef struct {
+  psVector *red;                      // Red colormap
+  psVector *green;                    // Green colormap
+  psVector *blue;                     // Blue colormap
+  psU8 white;			      // colormap-independent values
+  psU8 black;
+  float min;
+  float max;
+  bool xFlip;
+  bool yFlip;
+  psImageJpegShowScaleOption showScale; 
+  // XXX include bDrawBuffer in here?
+} psImageJpegOptions;
 
 #define PS_JPEG_RANGELIM(A)(PS_MAX(0,PS_MIN(255,(A))))
-
 #define PS_JPEG_SCALEVALUE(VALUE,ZERO,SCALE)(PS_MAX(0,PS_MIN(255,(SCALE*(VALUE-ZERO)))))
 
+#define PS_JPEG_COLORPAD 10
+#define PS_JPEG_LABELPAD 12
+
 // allocate a colormap (does not define the map values)
-psImageJpegColormap *psImageJpegColormapAlloc(void) PS_ATTR_MALLOC;
+psImageJpegOptions *psImageJpegOptionsAlloc(void) PS_ATTR_MALLOC;
 
 // set the colormap values using the supplied name
-psImageJpegColormap *psImageJpegColormapSet(psImageJpegColormap *map, // Colormap to set
-        const char *name // Name of colormap
-                                           );
+bool psImageJpegColormapSet(psImageJpegOptions *options, // Colormap to set
+			    const char *name // Name of colormap
+			    );
 
 // write out a JPEG file using the supplied image and colormap
 // output goes to the specified filename
-bool psImageJpeg(const psImageJpegColormap *map, // Color map
+bool psImageJpeg(const psImageJpegOptions *options, // Color map
                  const psImage *image,  // Image to write
-                 const char *filename,  // Filename of JPEG
-                 float min, float max   // Minimum and maximum values
-                );
+		 bDrawBuffer *bdbuf, 
+                 const char *filename  // Filename of JPEG
+		 );
+
+bDrawBuffer *psImageJpegOverlayInit (const psImage *image);
 
 /// @}
Index: /trunk/psLib/src/math/psMinimizeLMM.c
===================================================================
--- /trunk/psLib/src/math/psMinimizeLMM.c	(revision 29541)
+++ /trunk/psLib/src/math/psMinimizeLMM.c	(revision 29542)
@@ -325,7 +325,7 @@
         chisq += PS_SQR(delta) * dy->data.F32[i];
 
-        if (isnan(dy->data.F32[i])) return NAN;
-        if (isnan(delta)) return NAN;
-        if (isnan(chisq)) return NAN;
+        if (isnan(dy->data.F32[i])) goto escape;
+        if (isnan(delta)) goto escape;
+        if (isnan(chisq)) goto escape;
 
         // we track alpha,beta and params,deriv separately
@@ -354,4 +354,8 @@
     psFree(deriv);
     return(chisq);
+
+escape:
+    psFree(deriv);
+    return NAN;
 }
 
@@ -448,4 +452,9 @@
     if (isnan(min->value)) {
         min->iter = min->maxIter;
+	psFree(alpha);
+	psFree(Alpha);
+	psFree(beta);
+	psFree(Beta);
+	psFree(Params);
         return(false);
     }
Index: /trunk/psLib/src/pslib.h
===================================================================
--- /trunk/psLib/src/pslib.h	(revision 29541)
+++ /trunk/psLib/src/pslib.h	(revision 29542)
@@ -17,4 +17,5 @@
 #define PS_LIB_H
 
+#include <kapa.h>
 #include "pslib_strict.h"
 
Index: /trunk/psLib/test/jpeg/Makefile.am
===================================================================
--- /trunk/psLib/test/jpeg/Makefile.am	(revision 29541)
+++ /trunk/psLib/test/jpeg/Makefile.am	(revision 29542)
@@ -1,9 +1,17 @@
-AM_CPPFLAGS = $(SRCINC) -I$(top_srcdir)/test/tap/src $(PSLIB_CFLAGS)
+
+AM_CPPFLAGS = \
+	$(SRCINC) \
+	-I$(top_srcdir)/test/tap/src \
+	-I$(top_srcdir)/test/pstap/src \
+	$(PSLIB_CFLAGS)
+
 AM_LDFLAGS = \
 	$(top_builddir)/src/libpslib.la  \
 	$(top_builddir)/test/tap/src/libtap.la \
+	$(top_builddir)/test/pstap/src/libpstap.la \
 	$(PSLIB_LIBS)
 
-TEST_PROGS =
+TEST_PROGS = \
+	tap_psImageJpeg
 
 if BUILD_TESTS
Index: /trunk/psLib/test/jpeg/tap_psImageJpeg.c
===================================================================
--- /trunk/psLib/test/jpeg/tap_psImageJpeg.c	(revision 29542)
+++ /trunk/psLib/test/jpeg/tap_psImageJpeg.c	(revision 29542)
@@ -0,0 +1,209 @@
+#include <pslib.h>
+#include "tap.h"
+#include "pstap.h"
+
+# define DX 512
+# define DY 512
+# define ZMIN -50 
+# define ZMAX 500
+
+int main(int argc, char **argv)
+{
+  plan_tests(6);
+  InitRotFonts();
+
+  {
+    bool status;
+    psMemId id = psMemGetId();
+
+    psImageJpegOptions *options = psImageJpegOptionsAlloc();
+    ok (options, "allocate colormap");
+    skip_start (!options, 4, "skipping psImageJpeg tests");
+
+    status = psImageJpegColormapSet(options, "rainbow");
+    ok (status, "set colormap");
+	
+    psImage *image = psImageAlloc(DX, DY, PS_TYPE_F32);
+    ok (image, "allocate image");
+
+    // define some random image
+    for (int iy = 0; iy < DY; iy++) {
+      for (int ix = 0; ix < DX; ix++) {
+	image->data.F32[iy][ix] = hypot((ix - 0.5*DX), iy - 0.5*DY);
+      }
+    }
+	
+    options->min = ZMIN;
+    options->max = ZMAX;
+    options->xFlip = false;
+    options->yFlip = false;
+
+    options->showScale = PS_JPEG_SHOWSCALE_NONE;
+    status = psImageJpeg(options, image, NULL, "test.00.jpg");
+    ok (status, "wrote jpeg without scale");
+
+    options->showScale = PS_JPEG_SHOWSCALE_TOP;
+    status = psImageJpeg(options, image, NULL, "test.01.jpg");
+    ok (status, "wrote jpeg with scale");
+
+    options->showScale = PS_JPEG_SHOWSCALE_BOTTOM;
+    status = psImageJpeg(options, image, NULL, "test.02.jpg");
+    ok (status, "wrote jpeg with scale");
+
+    psFree(image);
+    psFree(options);
+
+    skip_end();
+    ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+  }
+
+  {
+    bool status;
+    psMemId id = psMemGetId();
+
+    psImageJpegOptions *options = psImageJpegOptionsAlloc();
+    ok (options, "allocate colormap");
+    skip_start (!options, 4, "skipping psImageJpeg tests");
+
+    status = psImageJpegColormapSet(options, "rainbow");
+    ok (status, "set colormap");
+	
+    psImage *image = psImageAlloc(DX, DY, PS_TYPE_F32);
+    ok (image, "allocate image");
+
+    // define some random image
+    for (int iy = 0; iy < DY; iy++) {
+      for (int ix = 0; ix < DX; ix++) {
+	image->data.F32[iy][ix] = hypot((ix - 0.5*DX), iy - 0.5*DY);
+      }
+    }
+	
+    bDrawBuffer *bdbuf = psImageJpegOverlayInit (image);
+
+    // add elements to bDraw buffer
+    bDrawSetBuffer(bdbuf);
+    bDrawColor red = KapaColorByName("red");
+    bDrawSetStyle (red, 1, 0);
+    bDrawCircle(40.0, 20.0, 3.0);
+
+    options->min = ZMIN;
+    options->max = ZMAX;
+    options->xFlip = false;
+    options->yFlip = false;
+
+    options->showScale = PS_JPEG_SHOWSCALE_NONE;
+    status = psImageJpeg(options, image, bdbuf, "test.03.jpg");
+    ok (status, "wrote jpeg without scale");
+
+    options->showScale = PS_JPEG_SHOWSCALE_TOP;
+    status = psImageJpeg(options, image, bdbuf, "test.04.jpg");
+    ok (status, "wrote jpeg with scale");
+
+    options->showScale = PS_JPEG_SHOWSCALE_BOTTOM;
+    status = psImageJpeg(options, image, bdbuf, "test.05.jpg");
+    ok (status, "wrote jpeg with scale");
+
+    bDrawBufferFree (bdbuf);
+    psFree(image);
+    psFree(options);
+
+    skip_end();
+    ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+  }
+  {
+    bool status;
+    psMemId id = psMemGetId();
+
+    psImageJpegOptions *options = psImageJpegOptionsAlloc();
+    ok (options, "allocate colormap");
+    skip_start (!options, 4, "skipping psImageJpeg tests");
+
+    status = psImageJpegColormapSet(options, "greyscale");
+    ok (status, "set colormap");
+	
+    psImage *image = psImageAlloc(DX, DY, PS_TYPE_F32);
+    ok (image, "allocate image");
+
+    // define some random image
+    for (int iy = 0; iy < DY; iy++) {
+      for (int ix = 0; ix < DX; ix++) {
+	image->data.F32[iy][ix] = hypot((ix - 0.5*DX), iy - 0.5*DY);
+      }
+    }
+	
+    options->min = ZMIN;
+    options->max = ZMAX;
+    options->xFlip = false;
+    options->yFlip = false;
+
+    options->showScale = PS_JPEG_SHOWSCALE_NONE;
+    status = psImageJpeg(options, image, NULL, "test.06.jpg");
+    ok (status, "wrote jpeg without scale");
+
+    options->showScale = PS_JPEG_SHOWSCALE_TOP;
+    status = psImageJpeg(options, image, NULL, "test.07.jpg");
+    ok (status, "wrote jpeg with scale");
+
+    options->showScale = PS_JPEG_SHOWSCALE_BOTTOM;
+    status = psImageJpeg(options, image, NULL, "test.08.jpg");
+    ok (status, "wrote jpeg with scale");
+
+    psFree(image);
+    psFree(options);
+
+    skip_end();
+    ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+  }
+
+  {
+    bool status;
+    psMemId id = psMemGetId();
+
+    psImageJpegOptions *options = psImageJpegOptionsAlloc();
+    ok (options, "allocate colormap");
+    skip_start (!options, 4, "skipping psImageJpeg tests");
+
+    status = psImageJpegColormapSet(options, "greyscale");
+    ok (status, "set colormap");
+	
+    psImage *image = psImageAlloc(DX, DY, PS_TYPE_F32);
+    ok (image, "allocate image");
+
+    // define some random image
+    for (int iy = 0; iy < DY; iy++) {
+      for (int ix = 0; ix < DX; ix++) {
+	image->data.F32[iy][ix] = ix + iy;
+      }
+    }
+	
+    options->min = ZMIN;
+    options->max = 1000.0;
+    options->showScale = PS_JPEG_SHOWSCALE_BOTTOM;
+
+    options->xFlip = false;
+    options->yFlip = false;
+    status = psImageJpeg(options, image, NULL, "test.09.jpg");
+    ok (status, "wrote jpeg without scale");
+
+    options->xFlip = true;
+    options->yFlip = false;
+    status = psImageJpeg(options, image, NULL, "test.10.jpg");
+    ok (status, "wrote jpeg without scale");
+
+    options->xFlip = false;
+    options->yFlip = true;
+    status = psImageJpeg(options, image, NULL, "test.11.jpg");
+    ok (status, "wrote jpeg without scale");
+
+    options->xFlip = true;
+    options->yFlip = true;
+    status = psImageJpeg(options, image, NULL, "test.12.jpg");
+    ok (status, "wrote jpeg without scale");
+
+    psFree(image);
+    psFree(options);
+
+    skip_end();
+    ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+  }
+}
