Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/Makefile	(revision 42348)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/Makefile	(revision 42349)
@@ -140,4 +140,5 @@
 $(SRC)/radial.$(ARCH).o	\
 $(SRC)/rd.$(ARCH).o		\
+$(SRC)/rdjpg.$(ARCH).o		\
 $(SRC)/rdseg.$(ARCH).o		\
 $(SRC)/read_vectors.$(ARCH).o	\
Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/init.c	(revision 42348)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/init.c	(revision 42349)
@@ -126,4 +126,5 @@
 int queue2book       PROTO((int, char **));
 int rd               PROTO((int, char **));
+int rdjpg            PROTO((int, char **));
 int rdseg            PROTO((int, char **));
 int read_vectors     PROTO((int, char **));
@@ -337,4 +338,5 @@
   {1, "ipptool2book", queue2book,       "convert queue with ipptool output to book"},
   {1, "rd",           rd,               "load fits image"},
+  {1, "rdjpg",        rdjpg,            "load jpeg image"},
   {1, "rdseg",        rdseg,            "read a segment of an image from a file"},
   {1, "read",         read_vectors,     "read vectors from datafile"},
Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/rdjpg.c
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/rdjpg.c	(revision 42349)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/rdjpg.c	(revision 42349)
@@ -0,0 +1,166 @@
+# include "data.h"
+#include <setjmp.h>
+# include "jpeglib.h"
+
+struct my_error_mgr {
+  struct jpeg_error_mgr pub;	/* "public" fields */
+  jmp_buf setjmp_buffer;	/* for return to caller */
+};
+
+typedef struct my_error_mgr * my_error_ptr;
+
+METHODDEF(void) my_error_exit (j_common_ptr cinfo)
+{
+  fprintf (stderr, "got an error\n");
+
+  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
+  my_error_ptr myerr = (my_error_ptr) cinfo->err;
+
+  /* Always display the message. */
+  /* We could postpone this until after returning, if we chose. */
+  (*cinfo->err->output_message) (cinfo);
+
+  /* Return control to the setjmp point */
+  longjmp(myerr->setjmp_buffer, 1);
+}
+
+int rdjpg (int argc, char **argv) {
+  
+  int i, N, blank;
+  Buffer *buf;
+
+  int VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: rdjpg <buffer> <filename>\n");
+    return (FALSE);
+  }
+
+  struct jpeg_decompress_struct cinfo;
+  struct my_error_mgr jerr;
+
+  JSAMPARRAY buffer;		/* Output row buffer */
+  int row_stride;		/* physical row width in output buffer */
+
+  // struct my_error_mgr jerr; : needed for error handling (deferred)
+
+  /* test if file exists */
+  FILE *f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "file %s not found\n", argv[2]);
+    return (FALSE);
+  }
+
+  /* find matrix, free old data */
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) {
+    fclose (f);
+    return (FALSE);
+  }
+  gfits_free_matrix (&buf[0].matrix);
+  gfits_free_header (&buf[0].header);
+
+  /* save file name */
+  char *filename = filebasename (argv[2]);
+  strcpy (buf[0].file, filename);
+  free (filename);
+
+  int status = FALSE;
+
+  cinfo.err = jpeg_std_error(&jerr.pub);
+  jerr.pub.error_exit = my_error_exit;
+  /* Establish the setjmp return context for my_error_exit to use. */
+  if (setjmp(jerr.setjmp_buffer)) {
+    /* If we get here, the JPEG code has signaled an error.
+     * We need to clean up the JPEG object, close the input file, and return.
+     */
+    jpeg_destroy_decompress(&cinfo);
+    fclose(f);
+    return FALSE;
+  }
+
+  /* Now we can initialize the JPEG decompression object. */
+  jpeg_create_decompress(&cinfo);
+  jpeg_stdio_src(&cinfo, f);
+  jpeg_read_header(&cinfo, TRUE);
+  jpeg_start_decompress(&cinfo);
+
+  /* We may need to do some setup of our own at this point before reading
+   * the data.  After jpeg_start_decompress() we have the correct scaled
+   * output image dimensions available, as well as the output colormap
+   * if we asked for color quantization.
+   * In this example, we need to make an output work buffer of the right size.
+   */ 
+
+  /* JSAMPLEs per row in output buffer */
+  row_stride = cinfo.output_width * cinfo.output_components;
+  // Nx = cinfo.output_width or row_stride
+  // Ny = cinfo.output_height
+
+  CreateBuffer (buf, cinfo.output_width, cinfo.output_height, -32, 0.0, 1.0);
+  float *Vout = (float *)buf[0].matrix.buffer;
+
+  /* Make a one-row-high sample array that will go away when done with image */
+  buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+
+  // read each of the scanlines
+  for (int iy = 0; iy < cinfo.output_height; iy++) {
+    jpeg_read_scanlines(&cinfo, buffer, 1);
+
+    /* Assume put_scanline_someplace wants a pointer and sample count. */
+    for (int ix = 0; ix < cinfo.output_width; ix ++) {
+      unsigned char Rpix = buffer[0][3*ix + 0];
+      unsigned char Gpix = buffer[0][3*ix + 1];
+      unsigned char Bpix = buffer[0][3*ix + 2];
+      float value = Rpix + Gpix + Bpix;
+      Vout[cinfo.output_width*iy + ix] = value;
+    }
+  }
+    
+  jpeg_finish_decompress(&cinfo);
+  jpeg_destroy_decompress(&cinfo);
+  
+  fclose (f);
+  
+  /* 
+  if (!status) {
+    gprint (GP_ERR, "problem reading file, buffer not opened\n");
+    DeleteBuffer (buf);
+    return (FALSE);
+    } 
+  */
+
+  buf[0].bitpix = buf[0].header.bitpix;    /* store the original values */
+  buf[0].bscale = buf[0].header.bscale;    /* store the original values */
+  buf[0].bzero  = buf[0].header.bzero;     /* store the original values */
+  buf[0].unsign = buf[0].header.unsign;
+
+  if (VERBOSE) gprint (GP_LOG, "read "OFF_T_FMT" bytes from %s into buffer %s\n", buf[0].header.datasize + buf[0].matrix.datasize, argv[2], argv[1]);
+
+  blank = 0xffff;
+
+  /** now - convert the matrix values to floats for internal use **/
+  // gfits_convert_format (&buf[0].header, &buf[0].matrix, -32, 1.0, 0.0, blank, gfits_get_unsign_mode());
+
+  return (TRUE);
+}
+
+# if (0)
+// XXX not sure about error handling here
+// cinfo.err = jpeg_std_error(&jerr.pub);
+// jerr.pub.error_exit = my_error_exit;
+
+/* Establish the setjmp return context for my_error_exit to use. */
+if (setjmp(jerr.setjmp_buffer)) {
+  /* If we get here, the JPEG code has signaled an error.
+   * We need to clean up the JPEG object, close the input file, and return.
+   */
+  jpeg_destroy_decompress(&cinfo);
+  fclose(f);
+  return 0;
+}
+# endif
+
