Index: trunk/Ohana/src/kapa2/Makefile
===================================================================
--- trunk/Ohana/src/kapa2/Makefile	(revision 41319)
+++ trunk/Ohana/src/kapa2/Makefile	(revision 41320)
@@ -23,4 +23,34 @@
 install: $(DESTBIN)/kapa
 
+PDF = \
+$(SRC)/PDFit.$(ARCH).o                  \
+$(SRC)/PDF_Frame.$(ARCH).o              \
+$(SRC)/PDF_Objects.$(ARCH).o            \
+$(SRC)/PDF_Labels.$(ARCH).o             \
+$(SRC)/PDF_Image.$(ARCH).o              \
+$(SRC)/PDF_Overlay.$(ARCH).o            \
+$(SRC)/PDF_Textlines.$(ARCH).o          \
+$(SRC)/PDF_Pixmap.$(ARCH).o             \
+$(SRC)/PDF_Alpha.$(ARCH).o              \
+$(SRC)/PDF_PrintUtils.$(ARCH).o 
+
+BDRAW = \
+$(SRC)/bDrawIt.$(ARCH).o            	\
+$(SRC)/bDrawFrame.$(ARCH).o         	\
+$(SRC)/bDrawObjects.$(ARCH).o		\
+$(SRC)/bDrawLabels.$(ARCH).o            \
+$(SRC)/bDrawImage.$(ARCH).o             \
+$(SRC)/bDrawOverlay.$(ARCH).o 
+
+PSFILES = \
+$(SRC)/PSit.$(ARCH).o                   \
+$(SRC)/PSFrame.$(ARCH).o            	\
+$(SRC)/PSObjects.$(ARCH).o		\
+$(SRC)/PSLabels.$(ARCH).o		\
+$(SRC)/PSimage.$(ARCH).o                \
+$(SRC)/PSOverlay.$(ARCH).o 	        \
+$(SRC)/PSTextlines.$(ARCH).o            \
+$(SRC)/PSPixmap.$(ARCH).o
+
 KAPA = \
 $(SRC)/kapa.$(ARCH).o                     $(SRC)/args.$(ARCH).o               \
@@ -38,11 +68,6 @@
 $(SRC)/DrawObjects.$(ARCH).o              $(SRC)/DrawFrame.$(ARCH).o          \
 $(SRC)/DrawTextlines.$(ARCH).o		  $(SRC)/DrawLabels.$(ARCH).o         \
-$(SRC)/PSObjects.$(ARCH).o		  $(SRC)/PSFrame.$(ARCH).o            \
-$(SRC)/PSLabels.$(ARCH).o		  $(SRC)/PSTextlines.$(ARCH).o        \
-$(SRC)/bDrawObjects.$(ARCH).o	  	  $(SRC)/bDrawFrame.$(ARCH).o         \
-$(SRC)/bDrawLabels.$(ARCH).o              $(SRC)/bDrawIt.$(ARCH).o            \
-$(SRC)/bDrawImage.$(ARCH).o               $(SRC)/MemoryDump.$(ARCH).o	      \
+$(SRC)/MemoryDump.$(ARCH).o	      \
 $(SRC)/PNGit.$(ARCH).o                    $(SRC)/PPMit.$(ARCH).o	      \
-$(SRC)/PSit.$(ARCH).o                     $(SRC)/CrossHairs.$(ARCH).o         \
 $(SRC)/CheckPipe.$(ARCH).o                $(SRC)/EventLoop.$(ARCH).o          \
 $(SRC)/Reconfig.$(ARCH).o                 $(SRC)/Refresh.$(ARCH).o            \
@@ -52,5 +77,5 @@
 $(SRC)/ErasePlots.$(ARCH).o               $(SRC)/EraseImage.$(ARCH).o         \
 $(SRC)/EraseCurrentPlot.$(ARCH).o         $(SRC)/EraseSections.$(ARCH).o      \
-$(SRC)/SetToolbox.$(ARCH).o                                                   \
+$(SRC)/SetToolbox.$(ARCH).o               $(SRC)/CrossHairs.$(ARCH).o         \
 $(SRC)/SetSection.$(ARCH).o		  $(SRC)/DefineSection.$(ARCH).o      \
 $(SRC)/SetLimits.$(ARCH).o                $(SRC)/SetFont.$(ARCH).o            \
@@ -75,11 +100,10 @@
 $(SRC)/CheckButtons.$(ARCH).o             $(SRC)/InvertButton.$(ARCH).o       \
 $(SRC)/UpdatePointer.$(ARCH).o            $(SRC)/JPEGit24.$(ARCH).o           \
-$(SRC)/bDrawOverlay.$(ARCH).o             $(SRC)/ButtonFunctions.$(ARCH).o    \
-$(SRC)/PSimage.$(ARCH).o                  $(SRC)/PSPixmap.$(ARCH).o           \
-$(SRC)/PSOverlay.$(ARCH).o                $(SRC)/SetChannel.$(ARCH).o         \
+$(SRC)/ButtonFunctions.$(ARCH).o    \
+$(SRC)/SetChannel.$(ARCH).o         \
 $(SRC)/SetColorScale.$(ARCH).o            $(SRC)/ColorCube.$(ARCH).o          \
 $(SRC)/ColorHistogram.$(ARCH).o           $(SRC)/CreateWide.$(ARCH).o
 
-OBJ  =  $(KAPA)
+OBJ  =  $(KAPA) $(PDF) $(BDRAW) $(PSFILES)
 
 # dependancy rules for include files ########################
Index: trunk/Ohana/src/kapa2/include/prototypes.h
===================================================================
--- trunk/Ohana/src/kapa2/include/prototypes.h	(revision 41319)
+++ trunk/Ohana/src/kapa2/include/prototypes.h	(revision 41320)
@@ -120,4 +120,40 @@
 void          FreeLayout          PROTO((void));
 
+/* PDF drawing primitives */
+double        PDF_SetLineWeight  PROTO((IOBuffer *buffer, double lweightIn));
+void          PDF_SetKapaColor   PROTO((IOBuffer *buffer, bDrawColor color));
+void          PDF_SetScaledColor PROTO((IOBuffer *buffer, float *pixel1, float *pixel2, float *pixel3, float value, int Npixels));
+void          PDF_DrawCircle     PROTO((IOBuffer *buffer, float Xc, float Yc, float R, int isFill));
+
+/* PDF print utils */
+PDF_FILE     *PDF_Open           PROTO((char *filename));
+int           PDF_Print          PROTO((PDF_FILE *obj, int newObject, char *format, ...));
+int           PDF_Close          PROTO((PDF_FILE *obj));
+int           PDF_CreateStream   PROTO((IOBuffer *buffer, float scale, int Xoff, int Yoff));
+int           PDF_WriteStream    PROTO((PDF_FILE *obj, IOBuffer *buffer));
+int           PDF_WriteImage     PROTO((PDF_FILE *obj, IOBuffer *buffer, int dX, int dY));
+void          PDF_AlphaDump      PROTO((PDF_FILE *obj));
+void          PDF_AlphaSet       PROTO((Gobjects *object, IOBuffer *buffer));
+void          PDF_AlphaInit      PROTO(());
+
+/* PDF drawing utilities */
+int           PDFcommand          PROTO((int sock));
+int           PDFit               PROTO((char *filename, char *pagename, int scaleMode, int pageMode));
+int           PDF_Frame           PROTO((KapaGraphWidget *graph, IOBuffer *buffer));
+int           PDF_Objects         PROTO((KapaGraphWidget *graph, IOBuffer *buffer));
+void          PDF_Labels          PROTO((KapaGraphWidget *graph, IOBuffer *buffer));
+void	      PDF_Textlines	  PROTO((KapaGraphWidget *graph, IOBuffer *buffer));
+int           PDF_ObjectsN        PROTO((KapaGraphWidget *graph, Gobjects *objects, IOBuffer *buffer));
+void          PDF_Connect         PROTO((KapaGraphWidget *graph, Gobjects *objects, IOBuffer *buffer));
+void          PDF_Histogram       PROTO((KapaGraphWidget *graph, Gobjects *objects, IOBuffer *buffer));
+void          PDF_Points          PROTO((KapaGraphWidget *graph, Gobjects *objects, IOBuffer *buffer));
+void          PDF_XErrors         PROTO((KapaGraphWidget *graph, Gobjects *objects, IOBuffer *buffer));
+void          PDF_YErrors         PROTO((KapaGraphWidget *graph, Gobjects *objects, IOBuffer *buffer));
+void	      PDF_Tick		  PROTO((Graphic *graphic, Axis *axis, int P, TickMarkData *tick, int naxis, IOBuffer *buffer));
+void          PDF_ClipLine        PROTO((double x0, double y0, double x1, double y1, double X0, double Y1, double X1, double Y0, IOBuffer *buffer));
+int           PDF_Image    	  PROTO((PDF_FILE *obj, KapaImageWidget *image, IOBuffer *buffer));
+void 	      PDF_Overlay  	  PROTO((KapaImageWidget *image, int N, IOBuffer *buffer, int extra));
+void          PDF_Pixmap          PROTO((Graphic *graphic, KapaImageWidget *image, IOBuffer *buffer));
+
 /* PS drawing utilities */
 int           PSit                PROTO((char *filename, char *pagename, int scaleMode, int pageMode));
Index: trunk/Ohana/src/kapa2/include/structures.h
===================================================================
--- trunk/Ohana/src/kapa2/include/structures.h	(revision 41319)
+++ trunk/Ohana/src/kapa2/include/structures.h	(revision 41320)
@@ -250,2 +250,19 @@
   char *name;
 } Section;
+
+typedef struct {
+  FILE *f;
+  int Nsegment;
+  int NSEGMENT;
+  int *offset;
+  int *objnum;
+
+  int Nstream;
+  int NSTREAM;
+  int *streamObjnum;
+
+  int Nimage;
+  int NIMAGE;
+  int *imageObjnum;
+} PDF_FILE;
+
Index: trunk/Ohana/src/kapa2/src/CheckPipe.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CheckPipe.c	(revision 41319)
+++ trunk/Ohana/src/kapa2/src/CheckPipe.c	(revision 41320)
@@ -94,4 +94,10 @@
   }
   
+  if (!strcmp (word, "PDFT")) {
+    status = PDFcommand (sock);
+    KiiSendCommand (sock, 4, "DONE");
+    FINISHED (status);
+  }
+  
   if (!strcmp (word, "PNGF")) {
     status = PNGcommand (sock);
Index: trunk/Ohana/src/kapa2/src/PDF_Alpha.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDF_Alpha.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDF_Alpha.c	(revision 41320)
@@ -0,0 +1,44 @@
+# include "Ximage.h"
+
+static int   Nalpha = 0;
+static int   NALPHA = 0;
+static float *alpha = NULL;
+
+void PDF_AlphaInit () {
+
+  if (alpha) FREE (alpha);
+  
+  Nalpha =  0;
+  NALPHA = 64;
+
+  ALLOCATE (alpha, float, NALPHA);
+}
+
+void PDF_AlphaSet (Gobjects *object, IOBuffer *buffer) {
+
+  if (object->alpha >= 1.0) {
+    PrintIOBuffer (buffer, "q\n");
+    return;
+  }
+
+  PrintIOBuffer (buffer, "q /GS%d gs\n", Nalpha);
+  alpha[Nalpha] = object->alpha;
+  Nalpha ++;
+
+  if (Nalpha >= NALPHA) {
+    NALPHA += 64;
+    REALLOCATE (alpha, float, NALPHA);
+  }
+  return;
+}
+
+void PDF_AlphaDump (PDF_FILE *obj) {
+  
+  // write out the graphic states accumulated above
+  PDF_Print (obj, 6, "6 0 obj <<\n");
+  for (int i = 0; i < Nalpha; i++) {
+    PDF_Print (obj, 0, "/GS%d << /Type /ExtGState /CA %.3f /ca %.3f >>\n", i, alpha[i], alpha[i]);
+  }
+  PDF_Print (obj, 0, ">> endobj\n");
+  return;
+}
Index: trunk/Ohana/src/kapa2/src/PDF_Frame.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDF_Frame.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDF_Frame.c	(revision 41320)
@@ -0,0 +1,136 @@
+# include "Ximage.h"
+
+// things still broken:
+// text
+// line weight
+// line type
+// polygon, polyfill not ported to PS (so missing here as well)
+
+# define DrawLine(X1,Y1,DX,DY) (PrintIOBuffer (buffer, " %6.2f %6.2f m %6.2f %6.2f l S\n", X1, Y1, X1+DX, Y1+DY))
+
+void PDF_Tick (Graphic *graphic, Axis *axis, int P, TickMarkData *tick, int naxis, IOBuffer *buffer);
+
+int PDF_Frame (KapaGraphWidget *graph, IOBuffer *buffer) {
+  
+  int i, j, Nticks, doffset;
+  double fx, fy, dfx, dfy, dx = 0, dy = 0;
+  Graphic *graphic;
+  TickMarkData *ticks;
+
+  graphic = GetGraphic();
+
+  // P = 0.5 * (1 + 0.25*graph[0].axis[0].lweight) * (hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy) + hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy));
+
+  int Px = 0.5 * (1 + 0.25*graph[0].axis[0].lweight) * (hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy) + hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy));
+  int Py = 0.5 * (1 + 0.25*graph[0].axis[1].lweight) * (hypot (graph[0].axis[1].dfx, graph[0].axis[1].dfy) + hypot (graph[0].axis[1].dfx, graph[0].axis[1].dfy));
+  int P = MIN (Px, Py);
+
+  /* each axis is drawn independently */
+  PDF_SetLineWeight (buffer, 1.0);
+  for (i = 0; i < 4; i++) {
+
+    // PDF_SetLineWeight enforces LineWeight limits
+    double lweight = PDF_SetLineWeight (buffer, graph[0].axis[i].lweight);
+    PDF_SetKapaColor (buffer, graph[0].axis[i].color);
+
+    /* temporarily assume rectilinear axes */
+    doffset = ((int)(lweight) % 2) ? 0.5*(lweight - 1) : 0.5*lweight;
+    if (i == 0) { dx = doffset; dy = 0.0; }
+    if (i == 2) { dx = doffset; dy = 0.0; }
+    if (i == 1) { dx = 0.0; dy = doffset; }
+    if (i == 3) { dx = 0.0; dy = doffset; }
+
+    fx  = graph[0].axis[i].fx - dx;
+    fy  = graphic->dy - graph[0].axis[i].fy - dy;
+    dfx = graph[0].axis[i].dfx + 2*dx;
+    dfy = -graph[0].axis[i].dfy + 2*dy;
+
+    // P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
+    // P *= (1 + 0.25*lweight);
+
+    // no need to init rot font
+
+    if (graph[0].axis[i].isaxis) { 
+      DrawLine (fx, fy, dfx, dfy); 
+    }
+    
+    if (graph[0].axis[i].areticks) {
+      ticks = CreateAxisTicks (&graph[0].axis[i], &Nticks);
+      for (j = 0; j < Nticks; j++) {
+	PDF_Tick (graphic, &graph[0].axis[i], P, &ticks[j], i, buffer);
+      }
+      FREE (ticks);
+    }      
+  }
+  return (TRUE);
+}
+
+void PDF_Tick (Graphic *graphic, Axis *axis, int P, TickMarkData *tick, int naxis, IOBuffer *buffer) {
+  
+  double x, y, dx, dy;
+  int pos, dir, fontsize;
+  double size, pad;
+  char string[64];
+
+  double fx  = axis->fx;
+  double fy  = graphic->dy - axis->fy;
+  double dfx = axis->dfx;
+  double dfy = -axis->dfy;
+
+  double min = axis->min;
+  double max = axis->max;
+
+  double value = tick->value;
+
+  pos = size = 0;
+
+  if (tick->IsMajor) { 
+    size = MIN (0.50*P, MAX (0.030 * P, 10.0)); 
+  } else {
+    size = MIN (0.25*P, MAX (0.015 * P, 5.0)); 
+  }
+  dir = ((naxis == 2) || (naxis == 3)) ? -1 : +1;
+
+  x = fx + (value-min)*dfx/(max - min);
+  y = fy + (value-min)*dfy/(max - min);
+
+  dx = 0;
+  dy = 0;
+
+  if ((naxis == 0) || (naxis == 2)) {
+    dx = 0;
+    dy = dir*size;
+    x = MIN(MAX(x, fx),fx+dfx);
+  }
+  if ((naxis == 1) || (naxis == 3)) {
+    dx = dir*size;
+    dy = 0;
+    y = MIN(MAX(y, fy),fy+dfy);
+  }
+  
+  DrawLine (x, y, dx, dy);
+
+  if (tick->IsLabel) {
+    int xt, yt;
+
+    // char *fontname is returned by not needed
+    GetRotFont (&fontsize);
+
+    pad = !isnan(axis->ticktextPad) ? axis->ticktextPad*fontsize : fontsize + 4.0;
+    // pad = !isnan(axis->ticktextPad) ? axis->ticktextPad*fontsize : 0.8*fontsize + 1.0;
+    
+    /* temporarily assume rectilinear axes */
+    if (naxis == 0) { dx = 0; dy = -pad; pos = 1; }
+    if (naxis == 2) { dx = 0; dy = +pad; pos = 7; }
+
+    if (naxis == 1) { dy = 0; dx = -pad; pos = 3; }
+    if (naxis == 3) { dy = 0; dx = +pad; pos = 5; }
+
+    xt = fx + (value-min)*dfx/(max - min) + dx;
+    yt = fy + (value-min)*dfy/(max - min) + dy;
+
+    // PrintTick write the characters into the string 
+    PrintTick (string, value, min, max, tick->nsignif);
+    PDFRotText (buffer, xt, yt, string, pos, 0.0);
+  }
+}
Index: trunk/Ohana/src/kapa2/src/PDF_Image.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDF_Image.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDF_Image.c	(revision 41320)
@@ -0,0 +1,51 @@
+# include "Ximage.h"
+
+// this function is called with an initialized stream buffer
+int PDF_Image (PDF_FILE *obj, KapaImageWidget *image, IOBuffer *buffer) {
+  
+  if (!USE_XWINDOW) {
+    fprintf (stderr, "PDF_Image not working yet for no X mode\n");
+    return (TRUE);
+  }
+
+  Graphic *graphic = GetGraphic();
+
+  // for a PDF image, we need to (1) generate the image dictionary containing the image
+  // data and (2) generate a content stream placing the image along with the overlay
+  // elements.  We actually generate (2) first and then write (1)
+
+  int Xoff = (int) image[0].picture.x;
+  int Yoff = graphic->dy - (int) image[0].picture.y - image[0].picture.dy;
+  int dX = image[0].picture.dx;
+  int dY = image[0].picture.dy;
+
+  PrintIOBuffer (buffer, "q %d 0 0 %d %d %d cm\n", dX, dY, Xoff, Yoff);
+  PrintIOBuffer (buffer, "/Image%d Do\n", obj->Nimage);
+  PrintIOBuffer (buffer, "Q\n");
+
+  fprintf (stderr, "%d %d : %d %d : %d %d\n", image->picture.x, image->picture.y, image->picture.dx, image->picture.dy, graphic->dx, graphic->dy);
+
+  PrintIOBuffer (buffer, "q 1 0 0 1 %d %d cm\n", Xoff, Yoff);
+  // add the overlay to the stream with the image 
+  for (int i = 0; i < NOVERLAYS; i++) {
+    if (image[0].overlay[i].active) {
+      PrintIOBuffer (buffer, "%% overlay %d\n", i);
+      PDF_Overlay (image, i, buffer, 0);
+    }
+  }
+  for (int i = 0; i < NOVERLAYS; i++) {
+    if (image[0].overlay[i].active) {
+      PrintIOBuffer (buffer, "%% overlay %d\n", i);
+      PDF_Overlay (image, i, buffer, 1);
+    }
+  }
+  PrintIOBuffer (buffer, "Q\n");
+
+  // Write Content stream to file
+  PDF_WriteStream (obj, buffer);
+
+  PDF_Pixmap (graphic, image, buffer);
+  PDF_WriteImage (obj, buffer, dX, dY);
+
+  return (TRUE);
+}
Index: trunk/Ohana/src/kapa2/src/PDF_Labels.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDF_Labels.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDF_Labels.c	(revision 41320)
@@ -0,0 +1,49 @@
+# include "Ximage.h"
+  
+void PDF_Labels (KapaGraphWidget *graph, IOBuffer *buffer) {
+  
+  int i, pos, x, y, size;
+  double angle;
+  char *fontname;
+  Graphic *graphic;
+
+  graphic = GetGraphic();
+
+  pos = 0;
+  fontname = GetRotFont (&size);
+  for (i = 0; i < 8; i++) {
+    if (strcmp (graph[0].label[i].text, "")) {
+      angle = 0;
+      switch (i) {
+      case 0: pos = 7; break;
+      case 1: pos = 1; angle = -90; break;
+      case 2: pos = 1; break;
+      case 3: pos = 1; angle =  90; break;
+      case 4: pos = 2; break;
+      case 5: pos = 0; break;
+      case 6: pos = 8; break;
+      case 7: pos = 6; break;
+      }	
+      x = graph[0].label[i].x;
+      y = graphic->dy - graph[0].label[i].y;
+      SetRotFont (graph[0].label[i].font, graph[0].label[i].size); 
+      PDFRotText (buffer, x, y, graph[0].label[i].text, pos, angle);
+    }
+  }
+  SetRotFont (fontname, size);
+}
+
+  /*
+            
+ 4____2___5 
+  |       | 
+  |       | 
+ 1|       |3
+  |       |
+  |       |
+  ---------
+  6   0   7
+
+  */
+
+
Index: trunk/Ohana/src/kapa2/src/PDF_Objects.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDF_Objects.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDF_Objects.c	(revision 41320)
@@ -0,0 +1,1056 @@
+# include "Ximage.h"
+
+# define BEZIER_C 0.55191502449
+
+double PDF_SetLineWeight (IOBuffer *buffer, double lweightIn) {
+  double lweight = MAX (0, MIN (10, lweightIn));
+  PrintIOBuffer (buffer, "%.1f w\n", lweight);
+  return lweight;
+}
+
+void PDF_SetKapaColor (IOBuffer *buffer, bDrawColor color) {
+    PrintIOBuffer (buffer, "%s rg\n", KapaColorRGBString(color));
+    PrintIOBuffer (buffer, "%s RG\n", KapaColorRGBString(color));
+    return;
+}
+
+void PDF_SetScaledColor (IOBuffer *buffer, float *pixel1, float *pixel2, float *pixel3, float value, int Npixels) {
+  if (!finite(value)) return;
+  int pixel = MIN (Npixels - 2, MAX (0, value*(Npixels - 1)));
+  PrintIOBuffer (buffer, "%4.2f %4.2f %4.2f rg\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+  PrintIOBuffer (buffer, "%4.2f %4.2f %4.2f RG\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+  return;
+}
+
+// http://spencermortensen.com/articles/bezier-circle/
+/** OK for PDF **/
+void PDF_DrawCircle (IOBuffer *buffer, float Xc, float Yc, float R, int isFill) {
+  PrintIOBuffer (buffer, " %6.2f %6.2f m\n", Xc, Yc + R);
+
+  PrintIOBuffer (buffer, " %6.2f %6.2f ",    Xc + R*BEZIER_C, Yc + R);
+  PrintIOBuffer (buffer, " %6.2f %6.2f ",    Xc + R,          Yc + R*BEZIER_C);
+  PrintIOBuffer (buffer, " %6.2f %6.2f c\n", Xc + R,          Yc);
+
+  PrintIOBuffer (buffer, " %6.2f %6.2f ",    Xc + R,          Yc - R*BEZIER_C);
+  PrintIOBuffer (buffer, " %6.2f %6.2f ",    Xc + R*BEZIER_C, Yc - R);
+  PrintIOBuffer (buffer, " %6.2f %6.2f c\n", Xc,              Yc - R);
+
+  PrintIOBuffer (buffer, " %6.2f %6.2f ",    Xc - R*BEZIER_C, Yc - R);
+  PrintIOBuffer (buffer, " %6.2f %6.2f ",    Xc - R,          Yc - R*BEZIER_C);
+  PrintIOBuffer (buffer, " %6.2f %6.2f c\n", Xc - R,          Yc);
+
+  PrintIOBuffer (buffer, " %6.2f %6.2f ",    Xc - R,          Yc + R*BEZIER_C);
+  PrintIOBuffer (buffer, " %6.2f %6.2f ",    Xc - R*BEZIER_C, Yc + R);
+  PrintIOBuffer (buffer, " %6.2f %6.2f c\n", Xc,              Yc + R);
+
+  if (isFill) {
+    PrintIOBuffer (buffer, " f\n");
+  } else {
+    PrintIOBuffer (buffer, " S\n");
+  }    
+}
+
+void PDF_Bars (KapaGraphWidget *graph, Gobjects *object, IOBuffer *buffer, int mode);
+
+/* DrawRectangle & FillRectangle : take rectangle lower-left corner and widths 
+   DrawCircle & FillCircle : take circle center and radius
+*/
+
+# define DrawLine(X1,Y1,X2,Y2)    (PrintIOBuffer (buffer, " %6.2f %6.2f m %6.2f %6.2f l S\n", X1, (graphic->dy - Y1), X2, (graphic->dy - Y2)))
+# define DrawRectangle(X,Y,dX,dY) (PrintIOBuffer (buffer, " %6.2f %6.2f %6.2f %6.2f re S\n", (X), (graphic->dy-Y), (dX), (dY)))
+# define FillRectangle(X,Y,dX,dY) (PrintIOBuffer (buffer, " %6.2f %6.2f %6.2f %6.2f re f\n", (X), (graphic->dy-Y), (dX), (dY)))
+
+# define DrawCircle(X1,Y1,R) {PDF_DrawCircle(buffer, X1, graphic->dy - Y1, R, FALSE);}
+# define FillCircle(X1,Y1,R) {PDF_DrawCircle(buffer, X1, graphic->dy - Y1, R, TRUE); }
+
+# define FillTriangle(X1,Y1,X2,Y2, X3, Y3) (PrintIOBuffer (buffer, " %6.2f %6.2f m %6.2f %6.2f l %6.2f %6.2f l f\n", (X1), (graphic->dy-Y1), (X2), (graphic->dy-Y2), (X3), (graphic->dy-Y3)))
+
+# define CAPSTYLE 1 /* CapButt */
+# define JOINSTYLE 0 /* JoinMiter */
+
+// XXX this is not thread safe, but that is OK
+static Graphic *graphic;
+
+/** OK for PDF **/
+int PDF_Objects (KapaGraphWidget *graph, IOBuffer *buffer) {
+  
+  int i;
+  
+  // the functions below use this global value
+  graphic = GetGraphic();
+
+  // this function calls all of the supporting Draw... functions below
+  for (i = 0; i < graph[0].Nobjects; i++) {
+    PDF_ObjectsN (graph, &graph[0].objects[i], buffer);
+  }
+  // reset to default color and style
+  PrintIOBuffer (buffer, "[] 0 d\n");
+  PrintIOBuffer (buffer, "0.00 0.00 0.00 rg\n");
+  PrintIOBuffer (buffer, "0.00 0.00 0.00 RG\n");
+
+  return (TRUE);
+}
+
+/** OK for PDF **/
+void PDF_LineStyle (KapaGraphWidget *graph, Gobjects *object, IOBuffer *buffer) {
+
+  static char short_dash[] = "4 4";
+  static char long_dash[] = "8 8";
+  static char dot_dash[] = "2 4 4 4";
+  static char dot[] = "2 3";
+  
+  PDF_SetLineWeight (buffer, object->lweight);
+  // PrintIOBuffer (buffer, "%d setlinecap %d setlinejoin\n", CAPSTYLE, JOINSTYLE);
+
+  switch (object->ltype) {
+    case KAPA_LINE_DOT:
+      PrintIOBuffer (buffer, "[%s] 0 d\n", dot);
+      break;
+    case KAPA_LINE_DASH_SHORT:
+      PrintIOBuffer (buffer, "[%s] 0 d\n", short_dash);
+      break;
+    case KAPA_LINE_DASH_LONG: 
+      PrintIOBuffer (buffer, "[%s] 0 d\n", long_dash);
+      break;
+    case KAPA_LINE_DOT_DASH:
+      PrintIOBuffer (buffer, "[%s] 0 d\n", dot_dash);
+      break;
+    case KAPA_LINE_SOLID: // no need to call 'd' as solid is the default
+    default:
+      break;
+  }
+    
+  if (object->color >= 0) {
+    PDF_SetKapaColor (buffer, object->color);
+  }
+}
+
+/** OK for PDF **/
+int PDF_ObjectsN (KapaGraphWidget *graph, Gobjects *object, IOBuffer *buffer) {
+  
+  PDF_LineStyle (graph, object, buffer);
+  PDF_AlphaSet (object, buffer);
+
+  switch (object->style) {
+    case KAPA_PLOT_CONNECT: 
+      PDF_Connect (graph, object, buffer);
+      break;
+    case KAPA_PLOT_HISTOGRAM: 
+      PDF_Histogram (graph, object, buffer);
+      break;
+    case KAPA_PLOT_BARS_SOLID:
+      PDF_Bars (graph, object, buffer, KAPA_PLOT_BARS_SOLID);
+      break;
+    case KAPA_PLOT_BARS_OUTLINE:
+      PDF_Bars (graph, object, buffer, KAPA_PLOT_BARS_OUTLINE);
+      break;
+    case KAPA_PLOT_BARS_OUTFILL:
+      PDF_Bars (graph, object, buffer, KAPA_PLOT_BARS_OUTFILL);
+      break;
+    case KAPA_PLOT_POINTS: 
+    default:
+      PDF_Points (graph, object, buffer);
+      break;
+  }
+
+  if (object->etype & 0x01) {
+    PDF_YErrors (graph, object, buffer);
+  }
+  if (object->etype & 0x02) {
+    PDF_XErrors (graph, object, buffer);
+  }
+
+  // this closes the graphic state generated by PDF_AlphaSet above
+  PrintIOBuffer (buffer, "Q\n");
+
+  return (TRUE);
+}
+
+/** OK for PDF **/
+void PDF_Connect (KapaGraphWidget *graph, Gobjects *object, IOBuffer *buffer) {
+  
+  int i;
+  float *x, *y;
+  double mxi, mxj, myi, myj, bxi, bxj, byi, byj, bx, by;
+  double sx0, sy0, sx1, sy1;
+  double X0, X1, Y0, Y1;
+
+  mxi = graph[0].axis[0].dfx / (object[0].x1 - object[0].x0);
+  mxj = graph[0].axis[1].dfx / (object[0].y1 - object[0].y0);
+  myi = graph[0].axis[0].dfy / (object[0].x1 - object[0].x0);
+  myj = graph[0].axis[1].dfy / (object[0].y1 - object[0].y0); 
+  
+  bxi  =  graph[0].axis[0].fx - object[0].x0*graph[0].axis[0].dfx/(object[0].x1 - object[0].x0);
+  bxj  =  -object[0].y0*graph[0].axis[1].dfx/(object[0].y1 - object[0].y0);
+  byi  =  -object[0].x0*graph[0].axis[0].dfy/(object[0].x1 - object[0].x0);
+  byj  =  graph[0].axis[1].fy - object[0].y0*graph[0].axis[1].dfy/(object[0].y1 - object[0].y0); 
+  
+  bx = bxi + bxj;
+  by = byi + byj;
+  
+  X0 = graph[0].axis[0].fx;
+  X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+  Y0 = graph[0].axis[1].fy;
+  Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+
+  x = object[0].x; y = object[0].y;
+  for (i = 0; (i < object[0].Npts) && !(finite(x[i]) && finite(y[i])); i++);
+  if (i >= object[0].Npts) return;
+  sx0 = x[i]*mxi + y[i]*mxj + bx;
+  sy0 = x[i]*myi + y[i]*myj + by;
+  
+  for (i++; i < object[0].Npts; i++) {
+    if (!(finite(x[i]) && finite(y[i]))) continue;
+    sx1 = x[i]*mxi + y[i]*mxj + bx;
+    sy1 = x[i]*myi + y[i]*myj + by;
+    PDF_ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1, buffer);
+    /* DrawLine (sx0, sy0, sx1, sy1); */
+    sx0 = sx1; sy0 = sy1;
+  }
+}
+
+/** OK for PDF **/
+void PDF_ClipLine (double x0, double y0, double x1, double y1, double X0, double Y1, double X1, double Y0, IOBuffer *buffer) {
+
+  /* skip line segement if both points are beyond box */
+  if ((x0 <= X0) && (x1 <= X0)) return;
+  if ((x0 >= X1) && (x1 >= X1)) return;
+  if ((y0 <= Y0) && (y1 <= Y0)) return;
+  if ((y0 >= Y1) && (y1 >= Y1)) return;
+
+  /* replace x0,y0 if outside box */
+  if ((x0 < X0) && (x1 >= X0)) {
+    y0 = y0 + (X0 - x0)*(y1 - y0)/(x1 - x0);
+    x0 = X0;
+  }
+  if ((x0 > X1) && (x1 <= X1)) {
+    y0 = y0 + (X1 - x0)*(y1 - y0)/(x1 - x0);
+    x0 = X1;
+  }
+  if ((y0 < Y0) && (y1 >= Y0)) {
+    x0 = x0 + (Y0 - y0)*(x1 - x0)/(y1 - y0);
+    y0 = Y0;
+  }
+  if ((y0 > Y1) && (y1 <= Y1)) {
+    x0 = x0 + (Y1 - y0)*(x1 - x0)/(y1 - y0);
+    y0 = Y1;
+  }
+
+  /* skip line segement if both points are beyond box */
+  if ((x0 <= X0) && (x1 <= X0)) return;
+  if ((x0 >= X1) && (x1 >= X1)) return;
+  if ((y0 <= Y0) && (y1 <= Y0)) return;
+  if ((y0 >= Y1) && (y1 >= Y1)) return;
+
+  /* replace x1,y1 if outside box */
+  if ((x1 < X0) && (x0 >= X0)) {
+    y1 = y0 + (X0 - x0)*(y1 - y0)/(x1 - x0);
+    x1 = X0;
+  }
+  if ((x1 > X1) && (x0 <= X1)) {
+    y1 = y0 + (X1 - x0)*(y1 - y0)/(x1 - x0);
+    x1 = X1;
+  }
+  if ((y1 < Y0) && (y0 >= Y0)) {
+    x1 = x0 + (Y0 - y0)*(x1 - x0)/(y1 - y0);
+    y1 = Y0;
+  }
+  if ((y1 > Y1) && (y0 <= Y1)) {
+    x1 = x0 + (Y1 - y0)*(x1 - x0)/(y1 - y0);
+    y1 = Y1;
+  }
+  DrawLine (x0, y0, x1, y1);
+}
+
+/** OK for PDF *****/
+void PDF_Histogram (KapaGraphWidget *graph, Gobjects *object, IOBuffer *buffer) {
+
+  int i;
+  float *x, *y;
+  double mxi, mxj, myi, myj, bxi, bxj, byi, byj, bx, by;
+  double sx0, sy0, sx1, sy1, sxa, sya, sxo, syo;
+  double X0, X1, Y0, Y1;
+
+  mxi = graph[0].axis[0].dfx / (object[0].x1 - object[0].x0);
+  mxj = graph[0].axis[1].dfx / (object[0].y1 - object[0].y0);
+  myi = graph[0].axis[0].dfy / (object[0].x1 - object[0].x0);
+  myj = graph[0].axis[1].dfy / (object[0].y1 - object[0].y0); 
+  
+  bxi  =  graph[0].axis[0].fx - object[0].x0*graph[0].axis[0].dfx/(object[0].x1 - object[0].x0);
+  bxj  =  -object[0].y0*graph[0].axis[1].dfx/(object[0].y1 - object[0].y0);
+  byi  =  -object[0].x0*graph[0].axis[0].dfy/(object[0].x1 - object[0].x0);
+  byj  =  graph[0].axis[1].fy - object[0].y0*graph[0].axis[1].dfy/(object[0].y1 - object[0].y0); 
+  
+  bx = bxi + bxj;
+  by = byi + byj;
+  
+  X0 = graph[0].axis[0].fx;
+  X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+  Y0 = graph[0].axis[1].fy;
+  Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+
+  /* find the first valid datapoint */
+  x = object[0].x; y = object[0].y;
+  for (i = 0; (i < object[0].Npts) && !(finite(x[i]) && finite(y[i])); i++);
+  if (i >= object[0].Npts) return;
+
+  /* first valid data point */
+  sx0 = x[i]*mxi + y[i]*mxj + bx;
+  sy0 = x[i]*myi + y[i]*myj + by;
+  sx0 = MIN (MAX (sx0, X0), X1);
+  sy0 = MAX (MIN (sy0, Y0), Y1);
+  
+  /* find the second valid datapoint */
+  for (i++; (i < object[0].Npts) && !(finite(x[i]) && finite(y[i])); i++);
+  if (i >= object[0].Npts) return;
+
+  /* second valid data point */
+  sx1 = x[i]*mxi + y[i]*mxj + bx;
+  sy1 = x[i]*myi + y[i]*myj + by;
+  sx1 = MIN (MAX (sx1, X0), X1);
+  sy1 = MAX (MIN (sy1, Y0), Y1);
+  
+  /* connect first point to second point */
+  sxa = MIN (MAX (sx0 - 0.5*(sx1 - sx0), X0), X1);
+  sya = MAX (sy0, Y0);
+  DrawLine (sx0, sy0, sxa, sy0);
+  DrawLine (sxa, sy0, sxa, sya);
+  
+  /* draw segment equal distance behind first point and down to x-axis */
+  sxa = MIN (MAX (0.5*(sx0 + sx1), X0), X1);
+  DrawLine (sx0, sy0, sxa, sy0);
+  DrawLine (sxa, sy0, sxa, sy1);
+  DrawLine (sxa, sy1, sx1, sy1);
+  sx0 = sx1;
+  sy0 = sy1;
+  
+  /* continue with rest of points */
+  sxo = syo = 0;
+  for (i++; i < object[0].Npts; i++) {
+    if (!(finite(x[i]) && finite(y[i]))) continue;
+    sx1 = x[i]*mxi + y[i]*mxj + bx;
+    sy1 = x[i]*myi + y[i]*myj + by;
+    sx1 = MIN (MAX (sx1, X0), X1);
+    sy1 = MAX (MIN (sy1, Y0), Y1);
+    sxa = MIN (MAX (0.5*(sx0 + sx1), X0), X1);
+    DrawLine (sx0, sy0, sxa, sy0);
+    DrawLine (sxa, sy0, sxa, sy1);
+    DrawLine (sxa, sy1, sx1, sy1);
+    sxo = sx0; syo = sy0;
+    sx0 = sx1; sy0 = sy1;
+  }
+  
+  /* draw segment equal distance after last point and down to x-axis */
+  sxa = MIN (MAX (sx1 + 0.5*(sx1 - sxo), X0), X1);
+  sya = MAX (sy1, Y0);
+  DrawLine (sx1, sy1, sxa, sy1);
+  DrawLine (sxa, sy1, sxa, sya);
+}
+
+// uses object->color
+# define HISTOGRAM_SOLID(X_VALUE, Y_VALUE, DX_VAL) {			\
+  /* histogram bar corners */						\
+  double sxmin = (X_VALUE) - 0.5*(DX_VAL);				\
+  double sxmax = (X_VALUE) + 0.5*(DX_VAL);				\
+  double symin = Xaxis;							\
+  double symax = (Y_VALUE);						\
+  /* saturated values for corner coords: */				\
+  sxmin = MIN (MAX (sxmin, X0), X1);					\
+  sxmax = MIN (MAX (sxmax, X0), X1);					\
+  symin = MAX (MIN (symin, Y0), Y1);					\
+  symax = MAX (MIN (symax, Y0), Y1);					\
+  double dy = fabs(symax - symin);					\
+  double ylow = MAX(symin, symax);					\
+  FillRectangle (sxmin, ylow, (DX_VAL), dy); }
+
+// uses object->color
+# define HISTOGRAM_OUTLINE(X_VALUE, Y_VALUE, DX_VAL) {			\
+  /* histogram bar corners */						\
+  double sxmin = (X_VALUE) - 0.5*(DX_VAL);				\
+  double sxmax = (X_VALUE) + 0.5*(DX_VAL);				\
+  double symin = Xaxis;							\
+  double symax = (Y_VALUE);						\
+  /* saturated values for corner coords: */				\
+  sxmin = MIN (MAX (sxmin, X0), X1);					\
+  sxmax = MIN (MAX (sxmax, X0), X1);					\
+  symin = MAX (MIN (symin, Y0), Y1);					\
+  symax = MAX (MIN (symax, Y0), Y1);					\
+  double dy = fabs(symax - symin);					\
+  double ylow = MAX(symin, symax);					\
+  DrawRectangle (sxmin, ylow, (DX_VAL), dy); }
+
+# define HISTOGRAM_OUTFILL(X_VALUE, Y_VALUE, DX_VAL) {			\
+  /* histogram bar corners */						\
+  double sxmin = (X_VALUE) - 0.5*(DX_VAL);				\
+  double sxmax = (X_VALUE) + 0.5*(DX_VAL);				\
+  double symin = Xaxis;							\
+  double symax = (Y_VALUE);						\
+  /* saturated values for corner coords: */				\
+  sxmin = MIN (MAX (sxmin, X0), X1);					\
+  sxmax = MIN (MAX (sxmax, X0), X1);					\
+  symin = MAX (MIN (symin, Y0), Y1);					\
+  symax = MAX (MIN (symax, Y0), Y1);					\
+  double dy = fabs(symax - symin);					\
+  double ylow = MAX(symin, symax);					\
+  FillRectangle (sxmin, ylow, (DX_VAL), dy);				\
+  PrintIOBuffer (buffer, "0.00 0.00 0.00 rg 0.00 0.00 0.00 RG\n");	\
+  DrawRectangle (sxmin, ylow, (DX_VAL), dy);				\
+  PDF_SetKapaColor (buffer, object->color); }
+
+/** OK for PDF **/
+void PDF_Bars (KapaGraphWidget *graph, Gobjects *object, IOBuffer *buffer, int mode) {
+
+  double mxi = graph[0].axis[0].dfx / (object[0].x1 - object[0].x0); // slope of the x-axis in x-pixels
+  double mxj = graph[0].axis[1].dfx / (object[0].y1 - object[0].y0); // slope of the x-axis in y-pixels (always 0 for now)
+  double myi = graph[0].axis[0].dfy / (object[0].x1 - object[0].x0); // slope of the x-axis in x-pixels (always 0 for now)
+  double myj = graph[0].axis[1].dfy / (object[0].y1 - object[0].y0); // slope of the x-axis in x-pixels
+  
+  // intercepts of axes
+  double bxi  =  graph[0].axis[0].fx - object[0].x0*graph[0].axis[0].dfx/(object[0].x1 - object[0].x0);
+  double bxj  =  -object[0].y0*graph[0].axis[1].dfx/(object[0].y1 - object[0].y0);
+  double byi  =  -object[0].x0*graph[0].axis[0].dfy/(object[0].x1 - object[0].x0);
+  double byj  =  graph[0].axis[1].fy - object[0].y0*graph[0].axis[1].dfy/(object[0].y1 - object[0].y0);
+  
+  double bx = bxi + bxj;
+  double by = byi + byj;
+  
+  // corner coords
+  double X0 = graph[0].axis[0].fx;
+  double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+  double Y0 = graph[0].axis[1].fy;
+  double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+  // NOTE: Y0 > Y1 (dfy is negative)
+
+  /* find the first valid datapoint */
+  float *x = object[0].x;
+  float *y = object[0].y;
+  
+  /* we are drawing bars which are filled rectangles of height y[i] and width 0.5*dx
+     one point at a time
+
+     I need to know the distance to the next and prev points to calculate dx
+     for the first point, dx is x[1] - x[0]
+     for the last point, dx is x[-1] - x[-2] (x[-1] is the last point)
+     for the rest, dx is 0.5*(x[i+1] - x[i-1])
+    
+     rather than working out complex on-the-fly logic, I want to find the first and last
+     valid point in an initial pass, then calculate the above for the remainder.
+     TBD: make an index vector of only valid points?
+  */
+
+  int Ngood = 0;
+  ALLOCATE_PTR (goodPoint, int, object[0].Npts);
+
+  // x = ??, y = 0: this assumes the xaxis is parallel to the plot window (myi = 0)
+  // note: Y0 > Y1 : y runs from large on bottom to small on top
+  float Xaxis = by;
+  Xaxis = MAX (Y1, MIN (Xaxis, Y0));
+
+  for (int i = 0; i < object[0].Npts; i++) {
+    if (!(finite(x[i]) && finite(y[i]))) continue;
+
+    // coordinate on the screen of the point:
+    double sx1r = x[i]*mxi + y[i]*mxj + bx;
+
+    if (sx1r < X0) {
+      // point to the left, skip it
+      continue;
+    }
+    if (sx1r > X1) {
+      // point to the right, skip it
+      continue;
+    }
+
+    goodPoint[Ngood] = i;
+    Ngood ++;
+  }
+    
+  if (Ngood == 0) {
+    free (goodPoint);
+    return;
+  }
+
+  // if we only have 1 point, draw bar half the width of the screen
+  // this works fine, but the auto limits for 1 value are somewhat silly
+  if (Ngood == 1) {
+    // coordinate on the screen of the point:
+    int n = goodPoint[0];
+    double sx1r = x[n]*mxi + y[n]*mxj + bx;
+    double sy1r = x[n]*myi + y[n]*myj + by;
+
+    float dx = 0.5*object->size*(X1 - X0);
+    
+    switch (mode) {
+      case KAPA_PLOT_BARS_SOLID:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTLINE:
+	HISTOGRAM_OUTLINE(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTFILL:
+	HISTOGRAM_OUTFILL(sx1r, sy1r, dx);
+	break;
+      default:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+    }
+
+    free (goodPoint);
+    return;
+  }
+
+  // first point:
+  {
+    int n;
+    n = goodPoint[1];
+    double sx1r = x[n]*mxi + y[n]*mxj + bx;
+
+    n = goodPoint[0];
+    double sx0r = x[n]*mxi + y[n]*mxj + bx;
+    double sy0r = x[n]*myi + y[n]*myj + by;
+
+    double dx = 0.5*object->size*(sx1r - sx0r);
+    
+    switch (mode) {
+      case KAPA_PLOT_BARS_SOLID:
+	HISTOGRAM_SOLID(sx0r, sy0r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTLINE:
+	HISTOGRAM_OUTLINE(sx0r, sy0r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTFILL:
+	HISTOGRAM_OUTFILL(sx0r, sy0r, dx);
+	break;
+      default:
+	HISTOGRAM_SOLID(sx0r, sy0r, dx);
+	break;
+    }
+  }
+
+  for (int i = 1; i < Ngood - 1; i++) {
+
+    int n;
+    n = goodPoint[i + 1];
+    double sx2r = x[n]*mxi + y[n]*mxj + bx;
+
+    n = goodPoint[i - 1];
+    double sx0r = x[n]*mxi + y[n]*mxj + bx;
+
+    // below we have 2 factors of 0.5 (we want half of the average spacing)
+    double dx = 0.5*0.5*object->size*(sx2r - sx0r);
+
+    n = goodPoint[i];
+    double sx1r = x[n]*mxi + y[n]*mxj + bx;
+    double sy1r = x[n]*myi + y[n]*myj + by;
+
+    switch (mode) {
+      case KAPA_PLOT_BARS_SOLID:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTLINE:
+	HISTOGRAM_OUTLINE(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTFILL:
+	HISTOGRAM_OUTFILL(sx1r, sy1r, dx);
+	break;
+      default:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+    }
+  }
+  
+  // last point:
+  {
+    int n;
+    n = goodPoint[Ngood - 1];
+    double sx1r = x[n]*mxi + y[n]*mxj + bx;
+    double sy1r = x[n]*myi + y[n]*myj + by;
+
+    n = goodPoint[Ngood - 2];
+    double sx0r = x[n]*mxi + y[n]*mxj + bx;
+
+    double dx = 0.5*object->size*(sx1r - sx0r);
+
+    switch (mode) {
+      case KAPA_PLOT_BARS_SOLID:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTLINE:
+	HISTOGRAM_OUTLINE(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTFILL:
+	HISTOGRAM_OUTFILL(sx1r, sy1r, dx);
+	break;
+      default:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+    }
+  }
+  free (goodPoint);
+  return;
+}
+
+/** OK for PDF *****/
+void PDF_Points (KapaGraphWidget *graph, Gobjects *object, IOBuffer *buffer) {
+ 
+  int i;
+  float *x, *y, *z;
+  double mxi, mxj, myi, myj, bxi, bxj, byi, byj, bx, by;
+  double sx, sy, sx1, sy1, sx2, sy2, ds, dz, D;
+  float *pixel1, *pixel2, *pixel3;
+
+  mxi = graph[0].axis[0].dfx / (object[0].x1 - object[0].x0);
+  mxj = graph[0].axis[1].dfx / (object[0].y1 - object[0].y0);
+  myi = graph[0].axis[0].dfy / (object[0].x1 - object[0].x0);
+  myj = graph[0].axis[1].dfy / (object[0].y1 - object[0].y0);  
+ 
+  bxi  =  graph[0].axis[0].fx - object[0].x0*graph[0].axis[0].dfx/(object[0].x1 - object[0].x0);
+  bxj  =  -object[0].y0*graph[0].axis[1].dfx/(object[0].y1 - object[0].y0);
+  byi  =  -object[0].x0*graph[0].axis[0].dfy/(object[0].x1 - object[0].x0);
+  byj  =  graph[0].axis[1].fy - object[0].y0*graph[0].axis[1].dfy/(object[0].y1 - object[0].y0);  
+
+  bx = bxi + bxj;
+  by = byi + byj;
+  
+  // scaled colors use the colormap defined for the graphic
+  ALLOCATE (pixel1, float, graphic[0].Npixels);
+  ALLOCATE (pixel2, float, graphic[0].Npixels);
+  ALLOCATE (pixel3, float, graphic[0].Npixels);
+
+  /** cmap[i].pixel must be defined even if X is not used **/
+  for (i = 0; i < graphic[0].Npixels; i++) { /* set up pixel array */
+    pixel1[i] = graphic[0].cmap[i].red / (float) 0xffff;
+    pixel2[i] = graphic[0].cmap[i].green / (float) 0xffff;
+    pixel3[i] = graphic[0].cmap[i].blue / (float) 0xffff;
+  }
+
+  /**** point sizes are scaled by object.size, colors by object.color ***/
+  int scaleSize = (object[0].size < 0);
+  int scaleColor = (object[0].color < 0);
+
+  ds = 0.5 * (graphic->dx + graphic->dy) * 0.003 * object[0].size;
+  dz = 0.5 * (graphic->dx + graphic->dy) * 0.010;
+  x = object[0].x; y = object[0].y; z = object[0].z;
+
+  switch (object[0].ptype) {
+    case KAPA_POINT_BOX_OPEN:	/* open box */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawRectangle (sx - D, sy - D, 2*D, 2*D);
+	}
+      }
+      break;
+    case KAPA_POINT_CROSS: /* cross */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy, sx + D, sy);
+	  DrawLine (sx, sy - D, sx, sy + D);
+	}
+      }
+      break;
+    case KAPA_POINT_X:	/* x */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx + D, sy - D, sx - D, sy + D);
+	  DrawLine (sx - D, sy - D, sx + D, sy + D);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_SOLID:	/* filled triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillTriangle (sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_SOLID_DOWN:	/* open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillTriangle (sx - D, sy + 0.58*D, sx + D, sy + 0.58*D, sx, sy - 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_OPEN:	/* open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy - 0.58*D, sx + D, sy - 0.58*D);
+	  DrawLine (sx + D, sy - 0.58*D, sx,     sy + 1.15*D);
+	  DrawLine (sx,     sy + 1.15*D, sx - D, sy - 0.58*D);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_OPEN_DOWN:	/* upside-down open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy + 0.58*D, sx + D, sy + 0.58*D);
+	  DrawLine (sx + D, sy + 0.58*D, sx,     sy - 1.15*D);
+	  DrawLine (sx,     sy - 1.15*D, sx - D, sy + 0.58*D);
+	}
+      }
+      break;
+    case KAPA_POINT_Y:	/* Y */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx, sy, sx - D, sy + 0.58*D);
+	  DrawLine (sx, sy, sx + D, sy + 0.58*D);
+	  DrawLine (sx, sy, sx,          sy - 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_Y_DOWN:	/* upside-down Y */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx, sy, sx - D, sy - 0.58*D);
+	  DrawLine (sx, sy, sx + D, sy - 0.58*D);
+	  DrawLine (sx, sy, sx,     sy + 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_CIRCLE_OPEN: /* 0 */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawCircle (sx, sy, D);
+	}
+      }
+      break;
+    case KAPA_POINT_CIRCLE_SOLID: /* filled 0 */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillCircle (sx, sy, D);
+	}
+      }
+      break;
+    case KAPA_POINT_PENTAGON:	/* pentagon */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx + 0.00*D, sy + 1.00*D, sx + 0.95*D, sy + 0.31*D);
+	  DrawLine (sx + 0.95*D, sy + 0.31*D, sx + 0.58*D, sy - 0.81*D);
+	  DrawLine (sx + 0.58*D, sy - 0.81*D, sx - 0.58*D, sy - 0.81*D);
+	  DrawLine (sx - 0.58*D, sy - 0.81*D, sx - 0.95*D, sy + 0.31*D);
+	  DrawLine (sx - 0.95*D, sy + 0.31*D, sx + 0.00*D, sy + 1.00*D);
+	}
+      }
+      break;
+    case KAPA_POINT_HEXAGON:	/* hexagon */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx -      D, sy,               sx - 0.50*D, sy + 0.87*D);
+	  DrawLine (sx - 0.50*D, sy + 0.87*D, sx + 0.50*D, sy + 0.87*D);
+	  DrawLine (sx + 0.50*D, sy + 0.87*D, sx +      D, sy);
+
+	  DrawLine (sx +      D, sy,               sx + 0.50*D, sy - 0.87*D);
+	  DrawLine (sx + 0.50*D, sy - 0.87*D, sx - 0.50*D, sy - 0.87*D);
+	  DrawLine (sx - 0.50*D, sy - 0.87*D, sx -      D, sy);
+	}
+      }
+      break;
+    case KAPA_POINT_PAIR_CONNECT: { /* connect pairs of points */
+      double X0 = graph[0].axis[0].fx;
+      double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+      double Y0 = graph[0].axis[1].fy;
+      double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+
+      for (i = 0; i + 1 < object[0].Npts; i+=2) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx1 = x[i]*mxi + y[i]*mxj + bx;
+	sy1 = x[i]*myi + y[i]*myj + by;
+	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx;
+	sy2 = x[i+1]*myi + y[i+1]*myj + by;
+	PDF_ClipLine (sx1, sy1, sx2, sy2, X0, Y0, X1, Y1, buffer);
+      }
+      break;
+    }
+    case KAPA_POINT_BOX_SOLID:	/* filled box */
+    default:
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    PDF_SetScaledColor (buffer, pixel1, pixel2, pixel3, z[i], graphic->Npixels);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillRectangle (sx - D, sy - D, 2*D, 2*D);
+	}
+      }
+      break;
+  }
+  free (pixel1);
+  free (pixel2);
+  free (pixel3);
+}
+    
+/** OK in PDF *****/
+void PDF_XErrors (KapaGraphWidget *graph, Gobjects *object, IOBuffer *buffer) {
+  
+  int i, bar, dz, ds, D;
+  float *x, *y, *z, *dxm, *dxp;
+  double mxi, mxj, myi, myj, bxi, bxj, byi, byj, bx, by;
+  double sx0, sy0, sx1, sy1, sz, sx10, sx11;
+
+  int scaleSize = (object[0].size < 0);
+
+  mxi = graph[0].axis[0].dfx / (object[0].x1 - object[0].x0);
+  mxj = graph[0].axis[1].dfx / (object[0].y1 - object[0].y0);
+  myi = graph[0].axis[0].dfy / (object[0].x1 - object[0].x0);
+  myj = graph[0].axis[1].dfy / (object[0].y1 - object[0].y0);
+  
+  bxi  =  graph[0].axis[0].fx - object[0].x0*graph[0].axis[0].dfx/(object[0].x1 - object[0].x0);
+  bxj  =  -object[0].y0*graph[0].axis[1].dfx/(object[0].y1 - object[0].y0);
+  byi  =  -object[0].x0*graph[0].axis[0].dfy/(object[0].x1 - object[0].x0);
+  byj  =  graph[0].axis[1].fy - object[0].y0*graph[0].axis[1].dfy/(object[0].y1 - object[0].y0);
+  
+  bx = bxi + bxj;
+  by = byi + byj;
+  
+  ds = 0.5 * (graphic->dx + graphic->dy) * 0.003 * object[0].size;
+  dz = 0.5 * (graphic->dx + graphic->dy) * 0.010;
+
+  x = object[0].x; y = object[0].y; dxp = object[0].dxp; dxm = object[0].dxm; z = object[0].z;
+  bar = object[0].ebar; sz = object[0].size*graph[0].axis[1].dfy*0.03;
+   
+  double X0 = graph[0].axis[0].fx;
+  double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+  double Y0 = graph[0].axis[1].fy;
+  double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+
+  /// XXX NOTE : D should be modified by (mxi,myi) for tilted axes dx = D*(mxi/mx), dy = D*(myi/mx)
+
+  for (i = 0; i < object[0].Npts; i++) {
+    // for open circles, only go to the outer radius
+    D = 0;
+    if (object[0].ptype ==  7) { D = scaleSize ? dz*z[i] : ds; }
+    if (object[0].ptype ==  1) { D = scaleSize ? dz*z[i] : ds; }
+    if (object[0].ptype ==  5) { D = scaleSize ? 0.66*dz*z[i] : 0.66*ds; }
+    if (object[0].ptype == 15) { D = scaleSize ? 0.66*dz*z[i] : 0.66*ds; }
+    if (!(finite(x[i]) && finite(y[i]) && finite(dxp[i]))) goto skip_dxp;
+    if (D > fabs(dxp[i]*mxi)) goto skip_dxp;
+    sx0 = x[i]*mxi + y[i]*mxj + bx + D;
+    sy0 = x[i]*myi + y[i]*myj + by;
+    sx1 = sx0 + dxp[i]*mxi - D;
+    sy1 = sy0 + dxp[i]*myi;
+    if (((sx0 > graph[0].axis[0].fx) && (sx0 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	 (sy0 < graph[0].axis[1].fy) && (sy0 > graph[0].axis[1].fy + graph[0].axis[1].dfy)) ||
+	((sx1 > graph[0].axis[0].fx) && (sx1 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
+      {
+	PDF_ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1, buffer);
+	if (bar) {
+	  sx10 = sy1 - sz;
+	  sx11 = sy1 + sz;
+	  PDF_ClipLine (sx1, sx10, sx1, sx11, X0, Y0, X1, Y1, buffer);
+	}
+      }
+  skip_dxp:
+    if (!(finite(x[i]) && finite(y[i]) && finite(dxm[i]))) continue;
+    if (D > fabs(dxm[i]*mxi)) continue;
+    sx0 = x[i]*mxi + y[i]*mxj + bx - D;
+    sy0 = x[i]*myi + y[i]*myj + by;
+    sx1 = sx0 - dxm[i]*mxi + D;
+    sy1 = sy0 - dxm[i]*myi;
+    if (((sx0 > graph[0].axis[0].fx) && (sx0 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	 (sy0 < graph[0].axis[1].fy) && (sy0 > graph[0].axis[1].fy + graph[0].axis[1].dfy)) ||
+	((sx1 > graph[0].axis[0].fx) && (sx1 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
+      {
+	PDF_ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1, buffer);
+	if (bar) {
+	  sx10 = sy1 - sz;
+	  sx11 = sy1 + sz;
+	  PDF_ClipLine (sx1, sx10, sx1, sx11, X0, Y0, X1, Y1, buffer);
+	}
+      }
+  }
+}
+
+    
+/** OK in PDF *****/
+void PDF_YErrors (KapaGraphWidget *graph, Gobjects *object, IOBuffer *buffer) {
+  
+  int i, bar, dz, ds, D;
+  float *x, *y, *z, *dym, *dyp;
+  double mxi, mxj, myi, myj, bxi, bxj, byi, byj, bx, by;
+  double sx0, sy0, sx1, sy1, sz, sx10, sx11;
+  
+  int scaleSize = (object[0].size < 0);
+
+  mxi = graph[0].axis[0].dfx / (object[0].x1 - object[0].x0);
+  mxj = graph[0].axis[1].dfx / (object[0].y1 - object[0].y0);
+  myi = graph[0].axis[0].dfy / (object[0].x1 - object[0].x0);
+  myj = graph[0].axis[1].dfy / (object[0].y1 - object[0].y0);
+  
+  bxi  =  graph[0].axis[0].fx - object[0].x0*graph[0].axis[0].dfx/(object[0].x1 - object[0].x0);
+  bxj  =  -object[0].y0*graph[0].axis[1].dfx/(object[0].y1 - object[0].y0);
+  byi  =  -object[0].x0*graph[0].axis[0].dfy/(object[0].x1 - object[0].x0);
+  byj  =  graph[0].axis[1].fy - object[0].y0*graph[0].axis[1].dfy/(object[0].y1 - object[0].y0);
+  
+  bx = bxi + bxj;
+  by = byi + byj;
+  
+  ds = 0.5 * (graphic->dx + graphic->dy) * 0.003 * object[0].size;
+  dz = 0.5 * (graphic->dx + graphic->dy) * 0.010;
+
+  x = object[0].x; y = object[0].y; dyp = object[0].dyp; dym = object[0].dym; z = object[0].z;
+  bar = object[0].ebar; sz = object[0].size*graph[0].axis[0].dfx*0.03;
+  
+  double X0 = graph[0].axis[0].fx;
+  double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+  double Y0 = graph[0].axis[1].fy;
+  double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+
+  /// XXX NOTE : D should be modified by (mxi,myi) for tilted axes dx = D*(mxi/mx), dy = D*(myi/mx)
+
+  for (i = 0; i < object[0].Npts; i++) {
+    // for open circles, only go to the outer radius
+    D = 0;
+    if (object[0].ptype ==  7) { D = scaleSize ? dz*z[i] : ds; }
+    if (object[0].ptype ==  1) { D = scaleSize ? dz*z[i] : ds; }
+    if (object[0].ptype ==  5) { D = scaleSize ? 1.15*dz*z[i] : 1.15*ds; }
+    if (object[0].ptype == 15) { D = scaleSize ? 0.58*dz*z[i] : 0.58*ds; }
+    if (!(finite(x[i]) && finite(y[i]) && finite(dyp[i]))) goto skip_dyp;
+    if (D > fabs(dyp[i]*myj)) goto skip_dyp;
+    sx0 = x[i]*mxi + y[i]*mxj + bx;
+    sy0 = x[i]*myi + y[i]*myj + by - D;
+    sx1 = sx0 + dyp[i]*mxj;
+    sy1 = sy0 + dyp[i]*myj + D;
+    if (((sx0 > graph[0].axis[0].fx) && (sx0 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	 (sy0 < graph[0].axis[1].fy) && (sy0 > graph[0].axis[1].fy + graph[0].axis[1].dfy)) ||
+	((sx1 > graph[0].axis[0].fx) && (sx1 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
+      {
+	PDF_ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1, buffer);
+	if (bar) {
+	  sx10 = sx1 - sz;
+	  sx11 = sx1 + sz;
+	  PDF_ClipLine (sx10, sy1, sx11, sy1, X0, Y0, X1, Y1, buffer);
+	}
+      }
+  skip_dyp:
+    if (!(finite(x[i]) && finite(y[i]) && finite(dym[i]))) continue;
+    if (object[0].ptype ==  5) { D = scaleSize ? 0.58*dz*z[i] : 0.58*ds; }
+    if (object[0].ptype == 15) { D = scaleSize ? 1.15*dz*z[i] : 1.15*ds; }
+    if (D > fabs(dym[i]*myj)) continue;
+    sx0 = x[i]*mxi + y[i]*mxj + bx;
+    sy0 = x[i]*myi + y[i]*myj + by + D;
+    sx1 = sx0 - dym[i]*mxj;
+    sy1 = sy0 - dym[i]*myj - D;
+    if (((sx0 > graph[0].axis[0].fx) && (sx0 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	 (sy0 < graph[0].axis[1].fy) && (sy0 > graph[0].axis[1].fy + graph[0].axis[1].dfy)) ||
+	((sx1 > graph[0].axis[0].fx) && (sx1 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
+      {
+	PDF_ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1, buffer);
+	if (bar) {
+	  sx10 = sx1 - sz;
+	  sx11 = sx1 + sz;
+	  PDF_ClipLine (sx10, sy1, sx11, sy1, X0, Y0, X1, Y1, buffer);
+	}
+      }
+  }
+}
Index: trunk/Ohana/src/kapa2/src/PDF_Overlay.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDF_Overlay.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDF_Overlay.c	(revision 41320)
@@ -0,0 +1,102 @@
+# include "Ximage.h"
+
+# define DrawLine(X1,Y1,X2,Y2) (PrintIOBuffer (buffer, " %6.1f %6.1f m %6.1f %6.1f l S\n", (X1), (Y1), (X2), (Y2)))
+
+static char name[4][16] = {"red", "green", "blue", "yellow"};
+
+void PDF_Overlay (KapaImageWidget *image, int N, IOBuffer *buffer, int extra) {
+
+  int i;
+  double X, Y, dX, dY;
+  int Xmin, Ymin, Xmax, Ymax;
+  double expand, pX, pY;
+  bDrawColor color;
+ 
+  /* translate color to bDrawColors : image[0].overlay[N].color */
+  color = KapaColorByName (name[N]);
+  PDF_SetKapaColor (buffer, color);
+  
+  expand = 1.0;
+  if (image[0].picture.expand > 0) {
+    expand = image[0].picture.expand;
+  }
+  if (image[0].picture.expand < 0) {
+    expand = 1.0 / fabs((double)image[0].picture.expand);
+  }
+
+  Xmin = 0;
+  Ymin = 0;
+  Xmax = image[0].picture.dx;
+  Ymax = image[0].picture.dy;
+
+  for (i = 0; i < image[0].overlay[N].Nobjects; i++) {
+
+    Image_to_Screen (&X, &Y, image[0].overlay[N].objects[i].x, image[0].overlay[N].objects[i].y, &image[0].picture);
+    dX = image[0].overlay[N].objects[i].dx * expand;
+    dY = image[0].overlay[N].objects[i].dy * expand;
+    if (image[0].picture.flipx) dX *= -1;
+    if (image[0].picture.flipy) dY *= -1;
+
+    // PS coord system is flipped relative to screen
+    Y = Ymax - Y;
+
+    pX = (image[0].picture.flipx) ? -1.0 : +1.0;
+    pY = (image[0].picture.flipy) ? -1.0 : +1.0;
+
+    switch (image[0].overlay[N].objects[i].type) {
+      case KII_OVERLAY_LINE:
+	if (((X < Xmin) && (X + dX < Xmin)) || ((X > Xmax) && (X + dX > Xmax)) ||
+	    ((Y < Ymin) && (Y + dY < Ymin)) || ((Y > Ymax) && (Y + dY > Ymax))) {
+	  break;
+	}
+	DrawLine (X + extra, Y + extra, (X+dX + extra), (Y-dY + extra));
+	break;
+      case KII_OVERLAY_TEXT:
+	if (((X < Xmin) && (X + dX < Xmin)) || ((X > Xmax) && (X + dX > Xmax)) ||
+	    ((Y < Ymin) && (Y + dY < Ymin)) || ((Y > Ymax) && (Y + dY > Ymax))) {
+	  break;
+	}
+	PrintIOBuffer (buffer, "/Fh 18 Tf %6.1f %6.1f m (%s) Tj\n", X + extra, Y + extra, image[0].overlay[N].objects[i].text); 
+	break;
+      case KII_OVERLAY_BOX:
+	if (((X - 0.5*dX < Xmin) && (X + 0.5*dX < Xmin)) || ((X - 0.5*dX > Xmax) && (X + 0.5*dX > Xmax)) ||
+	    ((Y - 0.5*dY < Ymin) && (Y + 0.5*dY < Ymin)) || ((Y - 0.5*dY > Ymax) && (Y + 0.5*dY > Ymax))) {
+	  break;
+	}
+	PrintIOBuffer (buffer, " %6.1f %6.1f %6.1f %6.1f re S\n", (X - 0.5*dX - extra), (Y - 0.5*dY - extra), (dX + 2*extra), (dY + 2*extra));
+	break;
+      case KII_OVERLAY_CIRCLE:
+	if (((X - dX < Xmin) && (X + dX < Xmin)) || ((X - dX > Xmax) && (X + dX > Xmax)) ||
+	    ((Y - dY < Ymin) && (Y + dY < Ymin)) || ((Y - dY > Ymax) && (Y + dY > Ymax))) {
+	  break;
+	}
+	// is this a true circle, or is it an ellipse?
+	if (fabs(dX - dY) < 0.01) {
+	  PDF_DrawCircle (buffer, X, Y, fabs(dX + extra), FALSE);
+	} else {
+	  // moderately-stupid rotated ellipse drawing:
+	  // ANGLE is distance ccw from the x-axis to the major axis
+	  double x0, y0, x1, y1, t;
+	  double angle = image[0].overlay[N].objects[i].angle * RAD_DEG;
+	  double cs = cos(angle);
+	  double sn = sin(angle);
+	  x0 = X + pX*dX*cs;
+	  y0 = Y - pY*dX*sn;
+	  // XXX dt should be based on the size of the ellipse...
+	  // 0.10 -> 60 segments on the ellipse
+	  # define DT 0.1
+	  for (t = DT; t < 2*M_PI + DT; t+=DT) {
+	    x1 = X + pX*dX*cos(t)*cs + pX*dY*sin(t)*sn;
+	    y1 = Y - pY*dX*cos(t)*sn + pY*dY*sin(t)*cs;
+	    DrawLine (x0 + extra, y0 + extra, x1 + extra, y1 + extra);
+	    x0 = x1;
+	    y0 = y1;
+	  }
+	}
+	break;
+      default:
+	fprintf (stderr, "skipping unknown object\n");
+	break;
+    }
+  }
+}
Index: trunk/Ohana/src/kapa2/src/PDF_Pixmap.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDF_Pixmap.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDF_Pixmap.c	(revision 41320)
@@ -0,0 +1,142 @@
+# include "Ximage.h"
+
+# define WHITE_R 255
+# define WHITE_G 255
+# define WHITE_B 255
+
+int WhiteIOBuffer (IOBuffer *buffer);
+
+void PDF_Pixmap (Graphic *graphic, KapaImageWidget *image, IOBuffer *buffer) {
+
+  int i, j, ii, jj;
+  int i_start, i_end, j_start, j_end;
+  int I_start, J_start;
+  int dx, dy, DX, inDX, inDY;
+  int expand_in, expand_out;
+  double Ix, Iy;
+  unsigned short *in_pix, *in_pix_ref;
+  unsigned char *pixel1, *pixel2, *pixel3;
+
+  if (image == NULL) return;
+
+  ALLOCATE (pixel1, unsigned char, graphic[0].Npixels);
+  ALLOCATE (pixel2, unsigned char, graphic[0].Npixels);
+  ALLOCATE (pixel3, unsigned char, graphic[0].Npixels);
+
+  /** cmap[i].pixel must be defined even if X is not used **/
+  for (i = 0; i < graphic[0].Npixels; i++) { /* set up pixel array */
+    pixel1[i] = graphic[0].cmap[i].red >> 8;
+    pixel2[i] = graphic[0].cmap[i].green >> 8;
+    pixel3[i] = graphic[0].cmap[i].blue >> 8;
+  }
+
+  assert ((image[0].picture.expand >= 1) || (image[0].picture.expand <= -2));
+  expand_in = expand_out = 1.0;
+  if (image[0].picture.expand > 0) {
+    expand_out = image[0].picture.expand;
+    expand_in  = 1;
+  }
+  if (image[0].picture.expand < 0) {
+    expand_out = 1;
+    expand_in  = -image[0].picture.expand;
+  }
+
+  dx = image[0].picture.dx;
+  dy = image[0].picture.dy;
+  DX = image[0].image[0].matrix.Naxis[0];
+
+  // i_start, j_start are the closest lit screen pixel to 0,0
+  // I_start, J_start are the image pixel corresponding to i_start, j_start
+  Picture_Lower (&i_start, &j_start, &I_start, &J_start, &image[0].image[0].matrix, &image[0].picture);
+
+  // i_end, j_end are the closest lit screen pixel to dx, dy
+  // I_end, J_end are the image pixel corresponding to i_end, j_end
+  Picture_Upper (&i_end, &j_end, i_start, j_start, &image[0].image[0].matrix, &image[0].picture);
+
+  assert (i_start <= i_end);
+  assert (j_start <= j_end);
+
+  Ix = image[0].picture.flipx ? I_start - 1 : I_start;
+  Iy = image[0].picture.flipy ? J_start - 1 : J_start;
+
+  inDX = image[0].picture.flipx ? -1 : +1;
+  inDY = image[0].picture.flipy ? -1 : +1;
+
+  in_pix_ref  = &image[0].pixmap[DX*(int)MAX(Iy,0) + (int)MAX(Ix,0)];
+
+  /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
+
+  // add in occasional return chars
+
+  /**** fill in bottom area ****/
+  for (j = 0; j < j_start; j++) {
+    for (i = 0; i < dx; i++) {
+      WhiteIOBuffer (buffer);
+    }
+  }
+  
+  // probably could do this all smarter with scale operations in PS...
+
+  /*** fill in the image data region ***/
+  for (j = j_start; j < j_end; j+= expand_out, in_pix_ref += inDY*expand_in*DX) {
+    
+    // repeat the section below 'expand_out' times
+    for (jj = 0; jj < expand_out; jj++) {
+
+      /* create one output image line */
+      in_pix = in_pix_ref;
+
+      /**** fill in area to the left of the picture ****/
+      for (i = 0; i < i_start; i++) {
+	WhiteIOBuffer (buffer);
+      }
+    
+      /*** fill in the picture region ***/
+      for (i = i_start; i < i_end; i+=expand_out, in_pix += inDX*expand_in) {
+	for (ii = 0; ii < expand_out; ii++) {
+	  char tmpdata[4];
+	  tmpdata[0] = pixel1[*in_pix];
+	  tmpdata[1] = pixel2[*in_pix];
+	  tmpdata[2] = pixel3[*in_pix];
+	  WriteToIOBuffer (buffer, tmpdata, 3);
+	}
+      }
+    
+      /**** fill in area to the right of the picture ****/
+      for (i = i_end; i < dx; i++) {
+	WhiteIOBuffer (buffer);
+      }
+    }
+  }
+
+  /**** fill in top area ****/
+  for (j = j_end; j < dy; j++) {
+    for (i = 0; i < dx; i++) { 
+      WhiteIOBuffer (buffer);
+    }
+  }
+
+  free (pixel1);
+  free (pixel2);
+  free (pixel3);
+
+  return;
+}
+
+/* Set current pixel to white */
+int WhiteIOBuffer (IOBuffer *buffer) {
+
+  // extend the buffer if needed
+  if (buffer[0].Nbuffer + 4 >= buffer[0].Nalloc) {
+    buffer[0].Nalloc = buffer[0].Nbuffer + 64;
+    REALLOCATE (buffer[0].buffer, char, buffer[0].Nalloc);
+  }
+
+  buffer[0].buffer[buffer[0].Nbuffer + 0] = WHITE_R;
+  buffer[0].buffer[buffer[0].Nbuffer + 1] = WHITE_G;
+  buffer[0].buffer[buffer[0].Nbuffer + 2] = WHITE_B;
+  buffer[0].Nbuffer += 3;
+
+  return (TRUE);
+}
+  
Index: trunk/Ohana/src/kapa2/src/PDF_PrintUtils.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDF_PrintUtils.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDF_PrintUtils.c	(revision 41320)
@@ -0,0 +1,423 @@
+# include "Ximage.h"
+# include <zlib.h>
+
+# define BASETYPE unsigned int
+
+int PDF_ASCIIHexEncode (IOBuffer *output, IOBuffer *input);
+int PDF_ASCII85Encode (IOBuffer *output, IOBuffer *input);
+int PDF_BufferDeflate (IOBuffer *output, IOBuffer *input);
+static int base85_encode(char *out, size_t max, const BASETYPE *data, size_t count);
+
+PDF_FILE *PDF_Open (char *filename) {
+  FILE *f = fopen (filename, "w");
+  if (f == NULL) {
+    fprintf (stderr, "can't open output file %s\n", filename);
+    return NULL;  /* true because otherwise it quits kapa! */
+  }
+
+  ALLOCATE_PTR (obj, PDF_FILE, 1);
+  
+  obj->f = f;
+  obj->Nsegment =  0;
+  obj->NSEGMENT = 16;
+  ALLOCATE (obj->offset, int, obj->NSEGMENT);
+  ALLOCATE (obj->objnum, int, obj->NSEGMENT);
+
+  obj->Nstream =  0;
+  obj->NSTREAM = 16;
+  ALLOCATE (obj->streamObjnum, int, obj->NSEGMENT);
+
+  obj->Nimage =  0;
+  obj->NIMAGE = 16;
+  ALLOCATE (obj->imageObjnum, int, obj->NSEGMENT);
+  return obj;
+}
+
+// nObject : 0 -> extend current object, >0 -> create a new object
+int PDF_Print (PDF_FILE *obj, int nObject, char *format, ...) {
+
+  va_list argp;  
+
+  int N = obj->Nsegment;
+
+  // record the start of the current object
+  if (nObject > 0) {
+    obj->offset[N] = ftell(obj->f);
+    obj->objnum[N] = nObject;
+    obj->Nsegment ++;
+    if (obj->Nsegment >= obj->NSEGMENT) {
+      obj->NSEGMENT += 16;
+      REALLOCATE (obj->offset, int, obj->NSEGMENT);
+      REALLOCATE (obj->objnum, int, obj->NSEGMENT);
+    }
+  }
+
+  // do the formattted print
+  va_start (argp, format);
+  int status = vfprintf (obj->f, format, argp);
+  va_end (argp);
+  return status;
+}
+
+int PDF_Close (PDF_FILE *obj) {
+  
+  // Image list
+  // Images are names /Image0 - /ImageNNN
+  PDF_Print (obj, 4, "4 0 obj <<\n");
+  for (int i = 0; i < obj->Nimage; i++) {
+    PDF_Print (obj, 0, "/Image%d %d 0 R\n", i, obj->imageObjnum[i]);
+  }
+  PDF_Print (obj, 0, ">> endobj\n");
+
+  // Content Stream list:
+  PDF_Print (obj, 5, "5 0 obj [\n");
+  for (int i = 0; i < obj->Nstream; i++) {
+    PDF_Print (obj, 0, " %d 0 R\n", obj->streamObjnum[i]);
+  }
+  PDF_Print (obj, 0, "] endobj\n");
+
+  PDF_AlphaDump (obj);
+
+  // Cross-Ref Section
+  int XrefStart = ftell(obj->f);
+
+  // for the moment, fixed number of objects in table:
+  // Nsegment counts the number of real segments (N > 0)
+  fprintf (obj->f, "xref 0 %d\n", obj->Nsegment + 1);
+  fprintf (obj->f, "%010d 65535 f \n", 0); // the zero entry is special
+
+  // I need to sort the segment list by objectN:
+  isortpair (obj->objnum, obj->offset, obj->Nsegment);
+  
+  for (int i = 0; i < obj->Nsegment; i++) {
+    fprintf (obj->f, "%010d 00000 n \n", obj->offset[i]);
+  }
+  fprintf (obj->f, "trailer << /Size %d /Root 1 0 R >>\n", obj->Nsegment + 1);
+  fprintf (obj->f, "startxref %d\n", XrefStart);
+  fprintf (obj->f, "%%EOF\n");
+
+  fclose  (obj->f);
+  free (obj->offset);
+  free (obj->objnum);
+  free (obj);
+  return TRUE;
+}
+
+// generate the buffer for the first stream and set the user-space scale & offset
+int PDF_CreateStream (IOBuffer *buffer, float scale, int Xoff, int Yoff) {
+
+  InitIOBuffer (buffer, 1024);
+  
+  PrintIOBuffer (buffer, "%6.2f 0.0 0.0 %6.2f %d %d cm\n", scale, scale, Xoff, Yoff);
+
+  return TRUE;
+}
+
+// This code needs to generate a stream
+int PDF_WriteStream (PDF_FILE *obj, IOBuffer *buffer) {
+
+  if (!buffer->Nbuffer) return FALSE;
+
+  // I need the segment object number for this stream
+
+  // last object number:
+  int Nlast = obj->Nsegment - 1;
+  assert (Nlast > 0);
+
+  // the object number for this stream is the number for the last stream plus 1
+  int objnum = obj->objnum[Nlast] + 1;
+
+  obj->streamObjnum[obj->Nstream] = objnum;
+  obj->Nstream ++;
+  if (obj->Nstream >= obj->NSTREAM) {
+    obj->NSTREAM += 16;
+    REALLOCATE (obj->streamObjnum, int, obj->NSTREAM);
+  }
+
+  // test compression of the stream:
+  if (1) {
+    // Deflate buffer.buffer
+    IOBuffer compressed;
+    PDF_BufferDeflate (&compressed, buffer);
+
+    if (0) {
+      IOBuffer iTest, oTest;
+      InitIOBuffer (&iTest, 8);
+      strcpy (iTest.buffer, "Lion");
+      iTest.Nbuffer = strlen(iTest.buffer);
+      fprintf (stderr, "%s\n", iTest.buffer);
+      PDF_ASCII85Encode (&oTest, &iTest);
+      fprintf (stderr, "%s\n", oTest.buffer);
+    }
+
+    if (0) { 
+      char quote[] = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";
+      fprintf (stderr, "%d : %s\n", (int) strlen(quote), quote);
+      IOBuffer iTest, oTest;
+      InitIOBuffer (&iTest, strlen(quote) + 1);
+      strcpy (iTest.buffer, quote);
+      iTest.Nbuffer = strlen(iTest.buffer);
+      PDF_ASCII85Encode (&oTest, &iTest);
+      fprintf (stderr, "%s\n", oTest.buffer);
+      return FALSE;
+    }
+
+    // ASCIIHex encode
+    IOBuffer encode;
+    // XXX PDF_ASCIIHexEncode (&encode, buffer);
+    // PDF_ASCIIHexEncode (&encode, &compressed);
+    PDF_ASCII85Encode (&encode, &compressed);
+
+    // Content Stream
+    PDF_Print (obj, objnum, "%d 0 obj << /Length %d /Filter [/ASCII85Decode /FlateDecode] >> stream\n", objnum, encode.Nbuffer);
+    // PDF_Print (obj, objnum, "%d 0 obj << /Length %d /Filter [/ASCIIHexDecode /FlateDecode] >> stream\n", objnum, encode.Nbuffer);
+    // XXX PDF_Print (obj, objnum, "%d 0 obj << /Length %d /Filter [/ASCIIHexDecode] >> stream\n", objnum, encode.Nbuffer);
+    fwrite (encode.buffer, 1, encode.Nbuffer, obj->f);
+  } else {
+    // Content Stream
+    PDF_Print (obj, objnum, "%d 0 obj << /Length %d >> stream\n", objnum, buffer->Nbuffer);
+
+    // write stream here
+    // XXX check return to make sure all went to disk
+    fwrite (buffer->buffer, 1, buffer->Nbuffer, obj->f);
+  }
+
+  fprintf (obj->f, "endstream endobj\n");
+
+  FlushIOBuffer (buffer);
+  return TRUE;
+}
+
+// This code needs to generate a stream
+int PDF_WriteImage (PDF_FILE *obj, IOBuffer *buffer, int dX, int dY) {
+
+  if (!buffer) return FALSE;
+  // if (!buffer->Nbuffer) return FALSE;
+
+  // I need the segment object number for this stream
+
+  // last object number:
+  int Nlast = obj->Nsegment - 1;
+  assert (Nlast > 0);
+
+  // the object number for this stream is the number for the last stream plus 1
+  int objnum = obj->objnum[Nlast] + 1;
+
+  obj->imageObjnum[obj->Nimage] = objnum;
+  obj->Nimage ++;
+  if (obj->Nimage >= obj->NIMAGE) {
+    obj->NIMAGE += 16;
+    REALLOCATE (obj->imageObjnum, int, obj->NIMAGE);
+  }
+
+  // Deflate buffer.buffer
+  IOBuffer compressed;
+  PDF_BufferDeflate (&compressed, buffer);
+
+  // ASCII85 encode
+  IOBuffer encode;
+  PDF_ASCII85Encode (&encode, &compressed);
+
+  // Image Dictionary
+  PDF_Print (obj, objnum, "%d 0 obj <<\n", objnum);
+  PDF_Print (obj, 0, " /Type /XObject /Subtype /Image\n");
+  PDF_Print (obj, 0, " /ColorSpace /DeviceRGB /BitsPerComponent 8\n");
+  PDF_Print (obj, 0, " /Width %d /Height %d\n", dX, dY);
+  PDF_Print (obj, 0, " /Length %d /Filter [/ASCII85Decode /FlateDecode] >> stream\n", encode.Nbuffer);
+ 
+  // PDF_Print (obj, 0, " /Length %d /Filter /ASCIIHexDecode >> stream\n", buffer->Nbuffer);
+
+  // write image data here
+  // XXX check return to make sure all went to disk
+  fwrite (encode.buffer, 1, encode.Nbuffer, obj->f);
+
+  PDF_Print (obj, 0, "\n  endstream endobj\n");
+
+  FlushIOBuffer (buffer);
+  return TRUE;
+}
+
+# define EXTRA_VERBOSE 0
+
+# define ESCAPE(RET) { fprintf (stderr, "gzip error in %s @ %s:%d\n", __func__, __FILE__, __LINE__); return (RET); }
+
+// allocate output 
+int PDF_BufferDeflate (IOBuffer *output, IOBuffer *input) {
+
+  Bytef *source = (Bytef *)input->buffer;
+  uLong sourceLen = input->Nbuffer;
+
+  // allocate an output buffer allowing for minimum expansion:
+  InitIOBuffer (output, input->Nbuffer * 1.01 + 16);
+
+  Bytef *dest = (Bytef *)output->buffer;
+  uLongf destLen = output->Nalloc;
+
+  z_stream stream;
+  int err;
+  
+  stream.next_in = (Bytef*)source;
+  stream.avail_in = (uInt)sourceLen;
+
+  /* Check for source > 64K on 16-bit machine: */
+  if ((uLong)stream.avail_in != sourceLen) ESCAPE (Z_BUF_ERROR);
+
+  stream.next_out = dest;
+  stream.avail_out = (uInt) destLen; // allocated space
+  if ((uLong)stream.avail_out != destLen) ESCAPE (Z_BUF_ERROR);
+
+  stream.zalloc = Z_NULL;
+  stream.zfree  = Z_NULL;
+  stream.opaque = Z_NULL;
+
+  if (EXTRA_VERBOSE) {
+    fprintf (stderr, "inp cmp: ");
+    unsigned long int i;
+    for (i = 0; i < sourceLen; i++) {
+      fprintf (stderr, "0x%02hhx ", source[i]);
+    }
+    fprintf (stderr, "\n");
+  }
+
+  // the '1' is the compression level: make this a user argument
+  // NOTE: cfitsio uses a fixed value of 1
+  // I am using deflateInit2 because cfitsio expects gzip, not just zlib
+  // windowBits = 31 = (15 + 16) = (2^15 window bits) + (create a gzip stream)
+  err = deflateInit(&stream, Z_BEST_COMPRESSION);
+  if (0) fprintf (stderr, "inp buffers cmp 0: %d => %d => %d\n", stream.avail_in, stream.avail_out, (int) stream.total_out);
+
+  if (err != Z_OK) ESCAPE(err);
+
+  // XXX this is written to do the compression in a single pass.  it could be re-done to have 
+  // the compression occur in a series of steps
+  err = deflate(&stream, Z_FINISH);
+  if (err != Z_STREAM_END) {
+    err = deflateEnd(&stream);
+    ESCAPE (Z_BUF_ERROR);
+  }
+
+  if (EXTRA_VERBOSE) {
+    fprintf (stderr, "out cmp: ");
+    unsigned long int i;
+    for (i = 0; i < stream.total_out; i++) {
+      fprintf (stderr, "0x%02hhx ", dest[i]);
+    }
+    fprintf (stderr, "\n");
+  }
+
+  assert (stream.total_out <= destLen);
+
+  output->Nbuffer = stream.total_out;
+  
+  err = deflateEnd(&stream);
+  return err;
+}
+
+int PDF_ASCIIHexEncode (IOBuffer *output, IOBuffer *input) {
+
+  InitIOBuffer (output, 2*input->Nbuffer);
+  
+  for (int i = 0; i < input->Nbuffer; i++) {
+    PrintIOBuffer (output, "%02x", (unsigned char) input->buffer[i]);
+  }
+  return TRUE;
+}
+
+int PDF_ASCII85Encode (IOBuffer *output, IOBuffer *input) {
+
+  int Nint = (int)ceilf(input->Nbuffer / 4.0);
+  int Nout = 5*Nint;
+
+  InitIOBuffer (output, Nout);
+  
+  // the conversion code requires big-endian order; I should probably re-write it to use little-endian?
+  ALLOCATE_PTR (buffer, BASETYPE, Nint);
+  for (int i = 0; i < Nint; i++) {
+    char *tmpbuf = (char *) &buffer[i];
+    tmpbuf[0] = input->buffer[4*i + 3];
+    tmpbuf[1] = input->buffer[4*i + 2];
+    tmpbuf[2] = input->buffer[4*i + 1];
+    tmpbuf[3] = input->buffer[4*i + 0];
+  }
+  base85_encode (output->buffer, output->Nalloc, (BASETYPE *) buffer, Nint);
+  output->Nbuffer = Nout;
+
+  return TRUE;
+}
+
+// EAM: The base85 conversion below is from http://orangetide.com/code/base85.c
+// I have stripped down to just the Adobe portion
+// Where the original author refers to 'ascii85', he means the adobe version
+
+/* base85.c : encode numbers using two different techniques for Base-85 
+ * PUBLIC DOMAIN - Jon Mayo - September 10, 2008 */
+
+/* define this to use PDF/adobe Ascii85 encoding
+ * default is to use an encoding derived from RFC1924, except 32-bits at a time instead of 128-bits
+ * yes, I realize that RFC1924 is a joke RFC
+ */
+#define NR(x) (sizeof(x)/sizeof*(x))
+#define BASE85_DIGITS	5	 /* log85 (2^32) is 4.9926740807112 */
+
+static const unsigned char base85[85] =  "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu";
+static         signed char decode_table[UCHAR_MAX];
+
+static int base85_init_done = 0;
+
+/* create a look up table suitable for convering characters to base85 digits */
+static void base85_init(void) {
+  unsigned char ch;
+
+  if (base85_init_done) return;
+  base85_init_done = 1;
+  
+  assert((sizeof base85 == 85) && (base85[84] != 0)); /* make sure the array is exactly the right size */
+
+  for (ch = 0; ch < UCHAR_MAX; ch++) {
+    decode_table[ch] = -1;
+  }
+
+  for(ch = 0; ch < 85; ch++) {
+    decode_table[base85[ch]] = ch;
+  }
+}
+
+/* convert a list of 32-bit values into a base85 string.
+ * if you wish to encode 8-bit values, load them into 32-bit values in Big Endian order
+ * example:
+ *   input: "Lion"
+ *   ascii85: 9PJE_
+ *   base85: !aflO
+ */
+
+static int base85_encode(char *out, size_t max, const BASETYPE *data, size_t count) {
+
+  size_t i;
+  BASETYPE n;
+
+  base85_init();
+
+  while(count) {
+    if(max<1) return 0; /* failure */
+    n=*data++;
+    count--;
+    /* Ascii85 (adobe) */
+    if(n==0) {
+      *out++='z'; /* this is a special zero character */
+      max--;
+    } else {
+      if(max<5) return 0; /* no room */
+      for(i=BASE85_DIGITS;i--;) {
+	out[i]=base85[n%85];
+	n/=85;
+      }
+      max-=5;
+      out+=5;
+    }
+  }
+  *out=0;
+  return 1; /* success */
+}
+
+// base85_init();
+// if (!base85_encode (output, Nout, (BASETYPE *) quote, 1)) { fprintf (stderr, "failure\n"); }
Index: trunk/Ohana/src/kapa2/src/PDF_Textlines.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDF_Textlines.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDF_Textlines.c	(revision 41320)
@@ -0,0 +1,39 @@
+# include "Ximage.h"
+  
+void PDF_Textlines (KapaGraphWidget *graph, IOBuffer *buffer) {
+
+  int i, x, y, size;
+  double angle;
+  char *fontname;
+  Graphic *graphic;
+
+  graphic = GetGraphic();
+
+  fontname = GetRotFont (&size);
+  for (i = 0; i < graph[0].Ntextline; i++) {
+    if (strcmp (graph[0].textline[i].text, "")) {
+      angle = graph[0].textline[i].angle;
+      x = graph[0].textline[i].x;
+      y = graphic->dy - graph[0].textline[i].y;
+      if (graph[0].textline[i].color >= 0) {
+	PDF_SetKapaColor (buffer, graph[0].textline[i].color);
+      }
+      SetRotFont (graph[0].textline[i].font, graph[0].textline[i].size);
+      PDFRotText (buffer, x, y, graph[0].textline[i].text, graph[0].textline[i].justify, angle);
+    }
+  }
+  SetRotFont (fontname, size);
+}
+
+  /* pos values
+            
+ 4____2___5 
+  |       | 
+  |       | 
+ 1|   8   |3
+  |       |
+  |       |
+  ---------
+  6   0   7
+
+  */
Index: trunk/Ohana/src/kapa2/src/PDFit.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PDFit.c	(revision 41320)
+++ trunk/Ohana/src/kapa2/src/PDFit.c	(revision 41320)
@@ -0,0 +1,141 @@
+# include "Ximage.h"
+# define XOFFSET 0
+# define YOFFSET 0
+
+int PDFcommand (int sock) {
+
+  int status, scaleMode, pageMode;
+  char filename[1024], pagename[1024];
+
+  /* expect a line telling the number of bytes and a filename */
+  KiiScanMessage (sock, "%s %s %d %d", filename, pagename, &scaleMode, &pageMode);
+  status = PDFit (filename, pagename, scaleMode, pageMode);
+  return (status);
+}
+
+int PDFit (char *filename, char *pagename, int scaleMode, int pageMode) {
+
+  double scale;
+  IOBuffer buffer;
+
+  Graphic *graphic = GetGraphic();
+
+  // PDF files can be extended, but require effort to re-rewrite the cross-ref table
+  // Disable this for now
+  if (pageMode != KAPA_PS_NEWPLOT) {
+    fprintf (stderr, "cannot extend PDF files yet\n");
+    return (TRUE);  /* true because otherwise it quits kapa! */    
+  }
+
+  /* two scaling options: expand to fit page / keep absolute size */ 
+  if (scaleMode) {
+    scale = MIN (fabs(500.0 / graphic->dx), fabs (700.0 / graphic->dy));
+  } else {
+    scale = 72.0 / 96.0; /* ratio of screen pixels to points */
+  }
+
+  PDF_FILE *obj = PDF_Open (filename);
+
+  // we are using a very minimal file structure:
+      
+  // Header
+  PDF_Print (obj, 0, "%%PDF-1.4\n");
+  PDF_Print (obj, 0, "%%%c%c%c%c\n", 0xff, 0xfe, 0xfd, 0xfc);
+
+  // Root : File Catalog:
+  PDF_Print (obj, 1, "1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj\n");
+
+  // Pages
+  PDF_Print (obj, 2, "2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj\n");
+
+  // Page Container:
+  PDF_Print (obj, 3, "3 0 obj << /Type /Page /Parent 2 0 R\n");
+  PDF_Print (obj, 0, " /MediaBox [%d %d %.0f %.0f]\n", 
+	   XOFFSET, YOFFSET,
+	   XOFFSET + scale*graphic->dx,
+	   YOFFSET + scale*graphic->dy);
+
+  PDF_Print (obj, 0, " /Resources <<\n");
+  PDF_Print (obj, 0, "   /Font <<\n");
+  PDF_Print (obj, 0, "     /Ft  7 0 R\n");
+  PDF_Print (obj, 0, "     /Fh  8 0 R\n");
+  PDF_Print (obj, 0, "     /Fc  9 0 R\n");
+  PDF_Print (obj, 0, "     /Fs 10 0 R\n");
+  PDF_Print (obj, 0, "   >>\n");
+  PDF_Print (obj, 0, "   /XObject 4 0 R\n");
+  PDF_Print (obj, 0, "   /ExtGState 6 0 R\n");
+  PDF_Print (obj, 0, " >>\n");
+  PDF_Print (obj, 0, " /Contents 5 0 R >> endobj\n"); 
+
+  // /XObject points to a deferred object which lists the images (if any) (must use object 4)
+  // /Contents points to a deferred object which lists all content streams (must use object 5)
+  // /ExtGState points to a deferred object which lists all opacity levels (must use object 6)
+
+  // Font Dictionaries
+  PDF_Print (obj,  7, " 7 0 obj << /Type /Font /Subtype /Type1 /Name /Ft /BaseFont /Times-Roman >>\n");
+  PDF_Print (obj,  8, " 8 0 obj << /Type /Font /Subtype /Type1 /Name /Fh /BaseFont /Helvetica >>\n");
+  PDF_Print (obj,  9, " 9 0 obj << /Type /Font /Subtype /Type1 /Name /Fc /BaseFont /Courier >>\n");
+  PDF_Print (obj, 10, "10 0 obj << /Type /Font /Subtype /Type1 /Name /Fs /BaseFont /Symbol >>\n");
+
+  PDF_AlphaInit();
+
+  // NOTE: The PDF_WriteStream and PDF_WriteImage functions use the next available object,
+  // but deferred objects have to have a fixed value.  Reserve them before the last object above
+
+  // create stream here (include scale operations)
+  PDF_CreateStream (&buffer, scale, XOFFSET, YOFFSET);
+
+  // create streams for each of the sections (one for image, one for graph)
+  int Nsection = GetNumberOfSections ();
+  for (int i = 0; i < Nsection; i++) {
+    Section *section = GetSectionByNumber (i);
+    if (section->image) {
+      PDF_Image (obj, section->image, &buffer);
+      // flushes buffer when done
+    }
+    if (section->graph) {
+      PDF_Frame (section->graph, &buffer); 
+      PDF_Objects (section->graph, &buffer);
+      PDF_Labels (section->graph, &buffer);
+      PDF_Textlines (section->graph, &buffer);
+      PDF_WriteStream (obj, &buffer);
+    }
+  }
+  PDF_WriteStream (obj, &buffer);
+  FreeIOBuffer (&buffer);
+
+  PDF_Close (obj); // frees the PDF_PrintObject
+  return (TRUE);
+}
+
+/* 
+
+PDF creation notes:
+
+* numbers are all either float or int in decimal
+* ascii strings are in ()
+* hex data strings are in <>
+  * always represents a sequence of bytes (if an odd number are used, LAST nibble is 0)
+
+cross-reference table:
+
+xref
+Nstart Nobj
+0000000000 65535 f \n <- this line 
+nnnnnnnnnn ggggg n \n
+ nnnnnnnnnn - byte offset to start of obejct (zero padded) 
+ ggggg - generation number (can be zero for Kapa outputs if we are not re-writing PDFs)
+
+trailer section:
+
+trailer\n
+<< /Size NNN\n    <- number of entries in the cross-ref table above
+   /Root 1 0 R\n  <- REQUIRED (catalog dictionary for PDF doc)
+   /Info 2 0 R\n  <- OPTIONAL (information dictionary)
+   /ID [<3DD227F735946325424B0AD32F7FE72D><3DD227F735946325424B0AD32F7FE72D>]
+>>
+startxref
+2724 <- start byte of xref
+%%EOF
+
+*/
