aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/cdl/imd.c
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /vendor/x11iraf/cdl/imd.c
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'vendor/x11iraf/cdl/imd.c')
-rw-r--r--vendor/x11iraf/cdl/imd.c2095
1 files changed, 2095 insertions, 0 deletions
diff --git a/vendor/x11iraf/cdl/imd.c b/vendor/x11iraf/cdl/imd.c
new file mode 100644
index 00000000..e1630ac3
--- /dev/null
+++ b/vendor/x11iraf/cdl/imd.c
@@ -0,0 +1,2095 @@
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <stdio.h>
+#define CDL_LIBRARY_SOURCE
+#include "cdl.h"
+
+
+/*
+ * IMAGE DISPLAY -- The image display interface is responsible for actually
+ * displaying an image to the server, for reading back a raster from the
+ * server, and cursor positioning. This is a mid-level interface for
+ * handling the steps necessary for image display operations without dealing
+ * directly with the details of communicating with the server.
+ *
+ * imd = imd_open (imtdev)
+ * imd_displayImage (imd, pix, nx, ny, frame, fbconfig, comp_wcs)
+ * imd_readCursor (imd, sample, &x, &y, &wcs, &key)
+ * imd_[set|get]WCS (imd, name, title, a, b, c, d, tx, ty, z1, z2, zt)
+ * imd_[set|get]Mapping (imd, region, sx,sy,snx,sny, dx,dy,dnx,dny, ref)
+ * imd_close (imd)
+ *
+ * Low Level Procedures
+ * --------------------
+ * imd_writeImage (imd, pix, nx, ny, lx, ly)
+ * imd_readImage (imd, &pix, &nx, &ny)
+ * imd_readFrameBuffer (imd, &pix, &nx, &ny)
+ * imd_setFrame (imd, frame)
+ * imd_setFBConfig (imd, configno)
+ * imd_getFBConfig (imd, &configno, &width, &height, &nframes))
+ * imd_setName (imd, name)
+ * imd_setTitle (imd, title)
+ * imd_setCursor (imd, x, y, wcs)
+ * imd_clearFrame (imd)
+ * imd_writeSubRaster (imd, lx, ly, nx, ny, pix)
+ * imd_readSubRaster (imd, lx, ly, nx, ny, &pix)
+ *
+ * We leave it to the higher level procedures to handle Z-scale trans-
+ * formations, spatial scaling, and high level image I/O. All display pixels
+ * are assumed to be scaled to 8-bits already.
+ */
+
+/* Function prototypes */
+#ifdef __STDC__
+#include <stddef.h>
+#include <stdlib.h>
+#endif
+
+#define SZ_BLOCK 16384
+
+/* Types of coordinate and greyscale transformations. */
+#define W_UNITARY 0 /* values map without change */
+#define W_LINEAR 1 /* linear mapping */
+#define W_LOG 2 /* logarithmic mapping */
+#define W_USER 3 /* user transformation */
+
+/* Connection types. */
+#define UNIX 10
+#define INET 11
+#define FIFO 12
+
+/* Default Values. */
+#define DEF_FBCONFIG 1 /* default frame buffer config */
+#define DEF_OSDEV_1 "unix:/tmp/.IMT%d"
+#define DEF_OSDEV_2 "fifo:/dev/imt1i:/dev/imt1o"
+
+/* Frame buffer configuration file definitions. */
+#define FBCONFIG_1 ".imtoolrc"
+#define FBCONFIG_2 "/usr/local/lib/imtoolrc"
+#define FBCONFIG_ENV1 "imtoolrc"
+#define FBCONFIG_ENV2 "IMTOOLRC"
+#define DEF_FRAME_WIDTH 512
+#define DEF_FRAME_HEIGHT 512
+
+
+int imd_debug = 0; /* deug flag */
+char buf[SZ_LINE]; /* temp buffer */
+
+
+#ifdef ANSI_FUNC
+
+static int imd_writeLine(IMDPtr imd, uchar *pix, int nbytes, int x, int y);
+static int imd_readLine(IMDPtr imd, uchar *pix, int nbytes, int x, int y);
+static int imd_writeRawBuf(IMDPtr imd, uchar *pix, int nbytes, int x, int y, int nx, int ny);
+static int imd_readRawBuf(IMDPtr imd, uchar *pix, int nbytes, int x, int y, int nx, int ny);
+static IMDPtr imd_initialize(int fdin, int fdout, int domain);
+static int imd_parseImtdev(char *imtdev, char *unixaddr, unsigned short *host_port, unsigned long *host_addr, char *ififo, char *ofifo);
+static int imd_loadImtoolrc(IMDPtr imd);
+static int imd_getstr(char **ipp, char *obuf, int maxch);
+static void imd_minmax(uchar *pix, int nbytes, int *pmin, int *pmax);
+static int imd_wcsVersion (IMDPtr imd);
+
+#else
+
+static IMDPtr imd_initialize();
+static int imd_writeLine(), imd_readLine();
+static int imd_writeRawBuf(), imd_readRawBuf();
+static int imd_parseImtdev(), imd_loadImtoolrc(), imd_getstr();
+static int imd_writeLine(), imd_readLine(), imd_wcsVersion();
+static void imd_minmax();
+
+#endif
+
+#ifndef __STDC__
+ char *getenv();
+#endif
+
+
+
+/* IMD_OPEN -- Open a connection to the display server. The caller may
+ * either specify a connection at device open time, or the procedure will
+ * attempt to first connect on a unix socket or fifo pipe if that fails.
+ * The syntax for the imtdev argument is as follows:
+ *
+ * <domain> : <address>
+ *
+ * where <domain> is one of "inet" (internet tcp/ip socket), "unix" (unix
+ * domain socket) or "fifo" (named pipe). The form of the address depends
+ * upon the domain, as illustrated in the examples below.
+ *
+ * inet:5137 Server connection to port 5137 on the local
+ * host. For a client, a connection to the
+ * given port on the local host.
+ *
+ * inet:5137:foo.bar.edu Client connection to port 5137 on internet
+ * host foo.bar.edu. The dotted form of address
+ * may also be used.
+ *
+ * unix:/tmp/.IMT212 Unix domain socket with the given pathname
+ * IPC method, local host only.
+ *
+ * fifo:/dev/imt1i:/dev/imt1o FIFO or named pipe with the given pathname.
+ * IPC method, local host only. Two pathnames
+ * are required, one for input and one for
+ * output, since FIFOs are not bidirectional.
+ * For a client the first fifo listed will be
+ * the client's input fifo; for a server the
+ * first fifo will be the server's output fifo.
+ * This allows the same address to be used for
+ * both the client and the server, as for the
+ * other domains.
+ *
+ * The address field may contain up to two "%d" fields. If present, the
+ * user's UID will be substituted (e.g. "unix:/tmp/.IMT%d"). The default
+ * connection if no imtdev is specified is "unix:/tmp/.IMT%d", failing that,
+ * a connection is attempted on the /dev/imt1[io] named fifo pipes.
+ */
+
+#ifdef ANSI_FUNC
+
+IMDPtr
+imd_open (
+ char *imtdev /* connection type */
+)
+#else
+
+IMDPtr
+imd_open (imtdev)
+char *imtdev; /* connection type */
+#endif
+{
+ IMDPtr imd;
+ int domain, fd, fdin, fdout, free_imtdev=0, model;
+ unsigned short host_port;
+ unsigned long host_addr;
+ char unixaddr[SZ_NAME];
+ char input_fifo[SZ_NAME], output_fifo[SZ_NAME];
+
+
+ if (imtdev == NULL) {
+ struct sockaddr_un sockaddr;
+
+ /* Try first to connect on a unix socket. */
+ if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ imtdev = DEF_OSDEV_2;
+ if (imd_debug)
+ printf ("Can't get unix socket...\n");
+ goto retry;
+ }
+
+ /* Compose network address. */
+ bzero ((char *)&sockaddr, sizeof(sockaddr));
+ sockaddr.sun_family = AF_UNIX;
+ sprintf (sockaddr.sun_path, "/tmp/.IMT%d", (int)getuid());
+
+ if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))<0){
+ close (fd);
+ imtdev = DEF_OSDEV_2;
+ if (imd_debug)
+ printf ("Can't connect to socket '%s'\n",sockaddr.sun_path);
+ goto retry; /* no connection */
+ } else {
+ imtdev = (char *) calloc (SZ_IMTDEV, sizeof(char));
+ free_imtdev++;
+ strcpy (imtdev, sockaddr.sun_path);
+ fdin = fdout = fd;
+ }
+ model = DEF_MODEL;
+
+ } else {
+retry: domain = imd_parseImtdev (imtdev, unixaddr, &host_port, &host_addr,
+ input_fifo, output_fifo, &model);
+
+ switch (domain) {
+ case FIFO:
+ /* Open the fifos. */
+ if ((fdin = open (input_fifo, O_RDONLY|O_NDELAY)) != ERR)
+ fcntl (fdin, F_SETFL, O_RDONLY);
+ if ((fdout = open (output_fifo, O_WRONLY|O_NDELAY)) != ERR)
+ fcntl (fdout, F_SETFL, O_WRONLY);
+
+ /* Clean up if there is an error. */
+ if (fdin < 0 || fdout < 0) {
+ (void) close (fdin);
+ (void) close (fdout);
+ if (imd_debug)
+ printf ("Can't connect to fifo '%s'\n",input_fifo);
+ goto err;
+ }
+ break;
+
+ case UNIX:
+ { struct sockaddr_un sockaddr;
+
+ /* Try first to connect on a unix socket. */
+ if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ if (imd_debug)
+ printf ("Can't get unix socket...\n");
+ goto err;
+ }
+
+ /* Compose network address. */
+ bzero ((char *)&sockaddr, sizeof(sockaddr));
+ sockaddr.sun_family = AF_UNIX;
+ strcpy (sockaddr.sun_path, unixaddr);
+
+ if (connect(fd, (struct sockaddr *)&sockaddr,
+ sizeof(sockaddr))<0){
+ close (fd);
+ if (imd_debug)
+ printf ("Can't connect to socket '%s'\n",
+ sockaddr.sun_path);
+ goto err; /* no connection */
+ } else
+ fdin = fdout = fd;
+ }
+ break;
+
+ case INET:
+ { struct sockaddr_in sockaddr;
+
+ /* Get socket. */
+ if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ if (imd_debug)
+ printf ("Can't get inet socket...\n");
+ goto err;
+ }
+
+ /* Compose network address. */
+ bzero ((char *)&sockaddr, sizeof(sockaddr));
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_port = host_port;
+ bcopy ((char *)&host_addr, (char *)&sockaddr.sin_addr,
+ sizeof(host_addr));
+
+ /* Connect to server. */
+ if (connect (fd, (struct sockaddr *)&sockaddr,
+ sizeof(sockaddr)) < 0) {
+ close (fd);
+ if (imd_debug)
+ printf ("Can't connect to socket '%s'\n",
+ (char *)sockaddr.sin_addr.s_addr);
+ goto err;
+ } else
+ fdin = fdout = fd;
+ }
+ break;
+
+ default:
+ goto err;
+ }
+ }
+
+ /* Allocate and initialize imd structure. */
+ imd = imd_initialize (fdin, fdout, domain, model);
+
+
+ if (imd_debug)
+ fprintf (stderr, "Connection established on '%s'\n", imtdev);
+ if (free_imtdev)
+ free ((char *)imtdev);
+ return (imd);
+
+err:
+ fprintf (stderr, "Cannot open server connection on '%s'.\n", imtdev);
+ if (free_imtdev)
+ free ((char *)imtdev);
+ return NULL;
+}
+
+
+/* IMD_DISPLAYIMAGE -- Display an image to the server, setting the WCS and
+ * frame as needed. This is a high-level procedure used to make image
+ * display easy. It is assumed that the pixel array has already been scaled
+ * to 8-bits.
+ */
+
+int
+imd_displayImage (imd, pix, nx, ny, frame, fbconfig, comp_wcs)
+IMDPtr imd; /* package pointer */
+uchar *pix; /* pixels to display */
+int nx, ny; /* dimensions */
+int frame; /* frame to display */
+int fbconfig; /* fb config number */
+int comp_wcs; /* compute a WCS */
+{
+ register uchar *ip = pix;
+ register uchar *bp, *pp;
+ register int i, nnx = nx, nny = ny;
+ int status, use_subras = 0;
+ int pmin, pmax, x_off = 0, y_off = 0, lx, ly;
+ int fbwidth = imd->fbtab[fbconfig-1]->width;
+ int fbheight = imd->fbtab[fbconfig-1]->height;
+ int imd_writeImage();
+
+ if (imd_debug)
+ printf ("[imd_displayImage] frame=%d fb=%d->[%d,%d] %dx%d bytes\n",
+ frame, fbconfig, fbwidth, fbheight, nx, ny);
+
+ imd_setFrame (imd, frame); /* select frame */
+ imd_clearFrame (imd); /* erase frame */
+ imd_setFBConfig (imd, fbconfig); /* set fbconfig */
+
+ /* Check to see if the image to be displayed is larger than the
+ * current frame buffer. If so we'll need to pull out a subraster
+ * the size of the FB for display.
+ */
+ if (nx > fbwidth || ny > fbheight) {
+ nnx = min(nx, fbwidth); /* get new dimensions */
+ nny = min(ny, fbheight);
+ bp = ip = (uchar *) calloc (nnx * nny, sizeof (uchar));
+ use_subras++;
+
+ /* Pull out the subraster for display */
+ x_off = (nx>fbwidth ? ((nx - fbwidth) / 2 - 1) : 0);
+ y_off = (ny>fbheight ? ((ny - fbheight) / 2 - 1) : 0);
+ pp = pix + (y_off * nx) + x_off;
+ for (i=0; i < nny; i++) {
+ bcopy (pp, bp, nnx);
+ pp += nx;
+ bp += nnx;
+ }
+ }
+
+ if (imd_debug)
+ printf("[imd_displayImage] nnx=%d nny=%d xo=%d yo=%d\n",
+ nnx, nny, x_off, y_off);
+
+ /* Center the placement in user coords.
+ */
+ lx = (fbwidth / 2) - (nnx / 2);
+ ly = fbheight - ((fbheight / 2) + (nny / 2));
+
+ /* Compute a WCS for this image if it's not already defined. */
+ if (comp_wcs) {
+ imd->a = 1.0;
+ imd->b = 0.0;
+ imd->c = 0.0;
+ imd->d = -1.0;
+ imd->tx = (float) (nnx / 2) - (fbwidth / 2) + 1 + (float) x_off;
+ imd->ty = (float) (fbheight / 2) + (nny / 2) + (float) y_off;
+
+ if (imd->z1 == INDEF || imd->z2 == INDEF) {
+ imd_minmax (pix, nnx*nny, &pmin, &pmax);
+ imd->z1 = (imd->z1 == INDEF) ? (float) pmin : imd->z1;
+ imd->z2 = (imd->z2 == INDEF) ? (float) pmax : imd->z2;
+ }
+ imd->ztrans = W_LINEAR;
+
+ /* Initialize the mapping. */
+ imd->sx = 1.0;
+ imd->sy = 1.0;
+ imd->snx = nnx;
+ imd->sny = nny;
+ imd->dx = lx;
+ imd->dy = ly;
+ imd->dnx = nnx;
+ imd->dny = nny;
+ imd->iis_valid = 1;
+
+ if (imd_setWCS (imd, imd->name, imd->title, imd->a, imd->b, imd->c,
+ imd->d, imd->tx, imd->ty, imd->z1, imd->z2, imd->ztrans))
+ return (ERR);
+ }
+
+ /* Finally, display the image.
+ */
+ status = imd_writeImage (imd, ip, nnx, nny, lx, ly);
+
+ if (use_subras)
+ free ((char *)ip);
+ return (status);
+}
+
+
+/* IMD_READCURSOR -- Read the current cursor position. If sample is defined
+ * logical cursor position will be sampled and returned immediately, otherwise
+ * the server will block until a key is hit and we return that value as well.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_readCursor (
+ IMDPtr imd, /* package pointer */
+ int sample, /* wait for keystroke? */
+ float *x,
+ float *y, /* position */
+ int *wcs, /* WCS */
+ char *key /* keystroke */
+)
+#else
+
+int
+imd_readCursor (imd, sample, x, y, wcs, key)
+IMDPtr imd; /* package pointer */
+int sample; /* wait for keystroke? */
+float *x, *y; /* position */
+int *wcs; /* WCS */
+char *key; /* keystroke */
+#endif
+{
+ if (imd_debug)
+ printf ("[imd_readCursor]\n");
+
+ return (com_readCursor(imd->datain, imd->dataout,
+ sample, x, y, wcs, key));
+}
+
+
+/* IMD_SETWCS -- Set the WCS of the screen. The WCS is passed in a string
+ * defined as:
+ * Image_Name_String\n a b c d tx ty z1 z2 zt
+ * where:
+ * X' = a*X + c*Y + tx
+ * Y' = b*X + d*Y + ty
+ *
+ * z1 is the minimum pixel value, z2 is the maximum pixel value, zt
+ * defines the type of transformation to use.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_setWCS (
+ IMDPtr imd, /* package pointer */
+ char *name, /* name string */
+ char *title, /* title string */
+ float a,
+ float b,
+ float c,
+ float d, /* WCS values */
+ float tx,
+ float ty, /* translation */
+ float z1,
+ float z2, /* zscale values */
+ int zt /* transformation type */
+)
+#else
+
+int
+imd_setWCS (imd, name, title, a, b, c, d, tx, ty, z1, z2, zt)
+IMDPtr imd; /* package pointer */
+char *name; /* name string */
+char *title; /* title string */
+float a, b, c, d; /* WCS values */
+float tx, ty; /* translation */
+float z1, z2; /* zscale values */
+int zt; /* transformation type */
+#endif
+{
+ int nbytes = 0, status = 0, version = imd->iis_version;
+ char old_wcs[SZ_OLD_WCSBUF], mapping[SZ_OLD_WCSBUF];
+ char wcstext[SZ_WCSBUF];
+
+
+ /* Format the string to set world coordinate parameters. */
+ (void) sprintf (old_wcs, "%s%s%s\n%g %g %g %g %g %g %g %g %d\n",
+ (*name ? name : " "), (title ? " - " : " "), (*title ? title : " "),
+ a, b, c, d, tx, ty, z1, z2, zt);
+
+ if (imd->iis_version > 0 && imd->iis_valid) {
+ char *path_prefix, *node, *path;
+#ifdef SOLARIS
+ char *getcwd();
+#else
+ char *getwd();
+#endif
+
+ path_prefix = (char *) calloc (1025, sizeof(char));
+ path = (char *) calloc (512, sizeof(char));
+ node = (char *) calloc (512, sizeof(char));
+
+
+ /* Get a node!path prefix for the data file. */
+ gethostname (node, SZ_FNAME);
+
+#ifdef SOLARIS
+ (void) getcwd (path, 511);
+#else
+ (void) getwd (path);
+#endif
+ if (*name == '/')
+ (void) sprintf (path_prefix, "%s!%s", node, name);
+ else
+ (void) sprintf (path_prefix, "%s!%s/%s", node, path, name);
+
+ (void) sprintf (mapping, "%s %g %g %d %d %d %d %d %d\n%s\n",
+ (*imd->region ? imd->region : "image"),
+ imd->sx, imd->sy, imd->snx, imd->sny,
+ imd->dx, imd->dy, imd->dnx, imd->dny,
+ (*imd->ref ? imd->ref : path_prefix));
+
+ (void) sprintf (wcstext, "%s%s", old_wcs, mapping);
+
+ free ((char *)path_prefix);
+ free ((char *)path);
+ free ((char *)node);
+
+ } else
+ (void) strcpy (wcstext, old_wcs);
+
+
+ if (imd_debug) { printf ("[imd_setWCS] wcs='%s'\n", wcstext); }
+
+ /* Send the WCS buffer. */
+ nbytes = strlen (wcstext) + 1;
+ status = com_writeWCS (imd->dataout, wcstext, nbytes, version);
+
+ /* Invalidate the mapping once it's been sent. */
+ imd->iis_valid = 0;
+
+ return (status);
+}
+
+
+#ifdef USE_OLD_GETWCS
+
+/* IMD_OLDGETWCS -- Get the current display frame WCS information.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_getWCS (
+ IMDPtr imd, /* package pointer */
+ int wcs, /* WCS number to get */
+ char *name, /* name string */
+ char *title, /* title string */
+ float *a,
+ float *b,
+ float *c,
+ float *d, /* WCS values */
+ float *tx,
+ float *ty, /* translation */
+ float *z1,
+ float *z2, /* zscale values */
+ int *zt /* transformation type */
+)
+#else
+
+int
+imd_getWCS (imd, wcs, name, title, a, b, c, d, tx, ty, z1, z2, zt)
+IMDPtr imd; /* package pointer */
+int wcs; /* WCS number to get */
+char *name; /* name string */
+char *title; /* title string */
+float *a, *b, *c, *d; /* WCS values */
+float *tx, *ty; /* translation */
+float *z1, *z2; /* zscale values */
+int *zt; /* transformation type */
+#endif
+{
+ int datain = imd->datain;
+ int dataout = imd->dataout;
+ int nbytes = 0, version = imd->iis_version;
+ int tokens, status = 0;
+ char wcs_info[SZ_WCSBUF];
+
+
+ /* Read the WCS from the server. */
+ if (com_readWCS (datain, dataout, wcs_info, &nbytes, wcs, version))
+ return (ERR);
+
+ /* Parse the return buffer. */
+ name[0] = title[0] = '\0';
+ if (version == 0) {
+ tokens = sscanf (wcs_info, "%[^\n]\n%g%g%g%g%g%g%g%g%d",
+ buf, a, b, c, d, tx, ty, z1, z2, zt);
+ if (tokens == EOF) {
+ /* Had no WCS info, can't even get name, but no error. */
+ *a = *b = *c = *d = *tx = *ty = *z1 = *z2 = *zt = 0;
+
+ } else if (tokens < 10) {
+ /* partial read, something must be wrong. */
+ return (ERR);
+ }
+ sscanf (buf, "%s - %s", name, title);
+ }
+
+ if (imd_debug) {
+ printf ("[imd_getWCS] wcs=%d wcsbuf='%s'\n", wcs, wcsbuf);
+ }
+
+ return (OK);
+}
+#endif
+
+
+/* IMD_GETWCS -- Get the current display frame WCS information.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_getWCS (
+ IMDPtr imd, /* package pointer */
+ int wcs, /* WCS number to get */
+ char *name, /* name string */
+ char *title, /* title string */
+ float *a,
+ float *b,
+ float *c,
+ float *d, /* WCS values */
+ float *tx,
+ float *ty, /* translation */
+ float *z1,
+ float *z2, /* zscale values */
+ int *zt /* transformation type */
+)
+#else
+
+int
+imd_getWCS (imd, wcs, name, title, a, b, c, d, tx, ty, z1, z2, zt)
+IMDPtr imd; /* package pointer */
+int wcs; /* WCS number to get */
+char *name; /* name string */
+char *title; /* title string */
+float *a, *b, *c, *d; /* WCS values */
+float *tx, *ty; /* translation */
+float *z1, *z2; /* zscale values */
+int *zt; /* transformation type */
+#endif
+{
+ int fbwidth = imd->fbtab[imd->fbconfig-1]->width;
+ int fbheight = imd->fbtab[imd->fbconfig-1]->height;
+ int datain = imd->datain;
+ int dataout = imd->dataout;
+ int nbytes = 0, version = imd->iis_version;
+ int tokens, status = 0;
+ char wcsbuf[SZ_WCSBUF];
+
+
+ /* Read the WCS from the server. */
+ if (com_readWCS (datain, dataout, wcsbuf, &nbytes, wcs, version))
+ return (ERR);
+
+ if (imd_debug) {
+ printf ("[imd_getWCS] wcs=%d wcsbuf='%s'\n", wcs, wcsbuf);
+ }
+
+ /* Attempt to read the WCS and set up a unitary transformation
+ * if the information cannot be read.
+ */
+ if (sscanf (wcsbuf, "%[^\n]\n%f%f%f%f%f%f%f%f%d",
+ buf, a, b, c, d, tx, ty, z1, z2, zt) < 7) {
+
+ strcpy (title, "[NO WCS]\n");
+ *a = *d = 1;
+ *b = *c = 0;
+ *tx = *ty = 0;
+ *zt = 0;
+ } else {
+ if (name == NULL)
+ name = imd->name;
+ if (title == NULL)
+ title = imd->title;
+ sscanf (buf, "%s - %s", name, title);
+ }
+
+ /* Now try to read the mapping if we're expecting one, otherwise
+ * set up a default mapping of the entire frame buffer.
+ */
+ if (imd->iis_version > 0) {
+ register int i, j;
+
+ /* Skip over the first two lines of WCS data. */
+ strcpy (buf, wcsbuf);
+ for (i=0, j=0; j < 2 && buf[i]; i++)
+ if (buf[i] == '\n') j++;
+
+ /* Attempt to read the mapping. */
+ imd->ref[0] = '\0';
+ imd->region[0] = '\0';
+ if (sscanf (&buf[i], "%s%f%f%d%d%d%d%d%d\n%s\n",
+ imd->region, &imd->sx, &imd->sy, &imd->snx, &imd->sny,
+ &imd->dx, &imd->dy, &imd->dnx, &imd->dny, imd->ref) < 10) {
+
+ /* Error in the read, set a default. */
+ strcpy (imd->region, "none");
+ strcpy (imd->ref, "none");
+ imd->sx = 1.0;
+ imd->sy = 1.0;
+ imd->snx = fbwidth;
+ imd->sny = fbheight;
+ imd->dx = 1;
+ imd->dy = 1;
+ imd->dnx = fbwidth;
+ imd->dny = fbheight;
+
+ imd->iis_valid = 0;
+ return (ERR);
+ } else
+ imd->iis_valid = 1;
+ }
+
+ return (OK);
+}
+
+
+/* IMD_SETMAPPING -- Set the mapping information to be sent with the next
+ * imd_setWcs() call.
+ */
+#ifdef ANSI_FUNC
+
+int
+imd_setMapping (
+ IMDPtr imd, /* package ptr */
+ char *region, /* region name */
+ float sx, /* source rect */
+ float sy,
+ int snx, /* source extent */
+ int sny,
+ int dx, /* dest rect */
+ int dy,
+ int dnx, /* dest extent */
+ int dny,
+ char *ref /* reference name */
+)
+#else
+
+int
+imd_setMapping (imd, region, sx,sy,snx,sny, dx,dy,dnx,dny, ref)
+IMDPtr imd; /* package ptr */
+char *region; /* region name */
+float sx, sy; /* source rect */
+int snx, sny; /* source extent */
+int dx, dy; /* dest rect */
+int dnx, dny; /* dest extent */
+char *ref; /* reference name */
+#endif
+{
+ if (imd_debug) {
+ printf ("[imd_setMapping] region='%s' ref='%s'\n",
+ ( region ? region : ""), (ref ? ref : ""));
+ printf ("\tsrc = %g,%g%d,%d dest = %d,%d,%d,%d\n",
+ sx, sy, snx, sny, dx, dy, dnx, dny);
+ }
+
+ strcpy (imd->region, (region ? region : ""));
+ strcpy (imd->ref, (ref ? ref : ""));
+ imd->sx = sx;
+ imd->sy = sy;
+ imd->snx = snx;
+ imd->sny = sny;
+ imd->dx = dx;
+ imd->dy = dy;
+ imd->dnx = dnx;
+ imd->dny = dny;
+
+ return ((imd->iis_valid = 1));
+}
+
+
+/* IMD_GETMAPPING -- Get the mapping information returned with the last
+ * imd_getWcs() call.
+ */
+#ifdef ANSI_FUNC
+int
+imd_getMapping (
+ IMDPtr imd, /* package ptr */
+ char *region, /* region name */
+ float *sx, /* source rect */
+ float *sy,
+ int *snx, /* source extent */
+ int *sny,
+ int *dx, /* dest rect */
+ int *dy,
+ int *dnx, /* dest extent */
+ int *dny,
+ char *ref /* reference name */
+)
+
+#else
+int
+imd_getMapping (imd, region, sx,sy,snx,sny, dx,dy,dnx,dny, ref)
+IMDPtr imd; /* package ptr */
+char *region; /* region name */
+float *sx, *sy; /* source rect */
+int *snx, *sny; /* source extent */
+int *dx, *dy; /* dest rect */
+int *dnx, *dny; /* dest extent */
+char *ref; /* reference name */
+#endif
+{
+ if (imd->iis_valid) {
+ strcpy (region, imd->region);
+ *sx = imd->sx;
+ *sy = imd->sy;
+ *snx = imd->snx;
+ *sny = imd->sny;
+ *dx = imd->dx;
+ *dy = imd->dy;
+ *dnx = imd->dnx;
+ *dny = imd->dny;
+ strcpy (ref, imd->ref);
+ }
+
+ if (imd_debug) {
+ printf ("[imd_getMapping] valid=%d region='%s' ref='%s'\n",
+ imd->iis_valid, (region ? region : ""), (ref ? ref : ""));
+ printf ("\tsrc = %g,%g,%d,%d dest = %d,%d,%d,%d\n",
+ *sx, *sy, *snx, *sny, *dx, *dy, *dnx, *dny);
+ }
+
+ return (imd->iis_valid);
+}
+
+
+/* IMD_CLOSE -- Close the connection to the display server.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_close (
+ IMDPtr imd /* package pointer */
+)
+#else
+
+int
+imd_close (imd)
+IMDPtr imd; /* package pointer */
+#endif
+{
+ if (imd_debug)
+ printf ("[imd_close]\n");
+
+ if (imd) {
+ register int i;
+
+ /* Close the connection. */
+ if (imd->datain)
+ close (imd->datain);
+ if (imd->dataout)
+ close (imd->dataout);
+
+ /* Free the frame buffer configuration table. */
+ for (i=0; i < MAX_FBCONFIG; i++)
+ free ((char *)imd->fbtab[i]);
+
+ /* Free the pointers in the imd structure. */
+ free (imd->title);
+ free (imd->name);
+ free (imd->region);
+ free (imd->ref);
+ free (imd);
+ }
+
+ return (OK);
+}
+
+
+/* --------------------
+ * Low-Level Procedures
+ * --------------------*/
+
+/* IMD_WRITEIMAGE -- Display a raw pixel array to the server given the array
+ * dimensions, and a location. We use this instead of imd_writeSubRaster()
+ * since we can assume the frame is blank and we wish to avoid the overhead
+ * having to read back the frame buffer. The image corner position is given
+ * in user coords where the [0,0] origin is in the LL of the display window,
+ * we convert this to frame buffer coords where the origin is in the UL.
+ */
+
+int
+imd_writeImage (imd, pix, nx, ny, llx, lly)
+IMDPtr imd; /* package pointer */
+uchar *pix; /* pixels to display */
+int nx, ny; /* dimensions */
+int llx, lly; /* LL corner of image */
+{
+ register int i, j, k, y, nbytes, nl = ny, imline;
+ register int nnx = nx, nny = ny, block_has_data = 0;
+ register uchar *ip = pix;
+ register uchar *bp, *block, *ep;
+ register int lx, ly, nblocks, lines_per_block, fbline;
+ int x_off = 0, y_off = 0;
+ int fbwidth = imd->fbtab[imd->fbconfig-1]->width;
+ int fbheight = imd->fbtab[imd->fbconfig-1]->height;
+
+
+ /* Check to see if the image to be displayed is larger than the
+ * current frame buffer.
+ */
+ if (nx > fbwidth || ny > fbheight) {
+ nnx = min(nx, fbwidth); /* get new dimensions */
+ nny = min(ny, fbheight);
+ x_off = (nx>fbwidth ? ((nx - fbwidth) / 2 - 1) : 0);
+ y_off = (ny>fbheight ? ((ny - fbheight) / 2 - 1) : 0);
+ }
+
+ /* Now see whether the image extends over the boundaries of the
+ * frame buffer in any direction. If so we'll set up to write
+ * only those pixels on the frame buffer.
+ */
+ if (llx < 0) { /* image is left of frame */
+ x_off = -llx;
+ nnx = nx + llx;
+ }
+ if (lly < 0) { /* image is below frame */
+ y_off = -lly;
+ nny = ny + lly;
+ }
+ if ((llx + nx) > fbwidth) /* image overflows frame to right */
+ nnx = fbwidth - llx;
+ if ((lly + ny) > fbheight) /* image overflows frame at top */
+ nny = fbheight - lly;
+ ip = pix + (y_off * nx) + x_off;
+
+ /* Convert corner position to frame buffer coords. */
+ lx = max (0, llx);
+ ly = min (fbheight - 1, fbheight - lly - 1);
+
+ /* Compute the corner points in user units. */
+ imd->xs = llx;
+ imd->xe = llx + nnx - 1;
+ imd->ys = lly;
+ imd->ye = lly + nny - 1;
+
+ if (imd_debug) {
+ printf("[imd_writeImage] %dx%d bytes at [%d,%d] of [%d,%d]\n",
+ nx, ny, lx, ly, fbwidth, fbheight);
+ printf("[imd_writeImage] Xends = [%d,%d] Yends = [%d,%d]\n",
+ imd->xs, imd->xe, imd->ys, imd->ye);
+ printf("[imd_writeImage] nnx=%d nny=%d llx=%d lly=%d xo=%d yo=%d\n",
+ nnx, nny, llx, lly, x_off, y_off);
+ imd_debug = 1;
+ }
+
+ /* Display image. */
+ lines_per_block = (int) (SZ_BLOCK / fbwidth);
+ nblocks = (int) (fbheight / lines_per_block);
+ nbytes = fbwidth * lines_per_block;
+ block = (uchar *) calloc (nbytes, sizeof (uchar));
+
+ if (imd_debug) {
+ printf ("height=%d nblocks=%d lines/block=%d\n",
+ fbheight, nblocks, lines_per_block);
+ }
+
+ /* For each of the blocks we're sending.... */
+ fbline = fbheight - 1;
+ imline = ly;
+ ep = ip + nx * ny;
+ for (i=0, y = fbheight - lines_per_block; i < nblocks; i++) {
+ bp = block + (lines_per_block - 1) * fbwidth;
+ block_has_data = 0;
+
+ if (nnx != fbwidth || nny != fbheight)
+ /* Clear the block array */
+ for (k=0; k < nbytes; k++)
+ block[k] = 0;
+
+ /* Map image pixels to the data block. */
+ for (j=0; j < lines_per_block && nl >= 0; j++) {
+ if (fbline == imline && ip < ep) {
+ block_has_data = 1;
+ bcopy (ip, bp+lx, nnx);
+ ip += nx;
+ imline--;
+ nl--;
+ }
+ bp -= fbwidth;
+ fbline--;
+ }
+
+ if (block_has_data)
+ if (imd_writeLine(imd, block, nbytes, 0, y))
+ return (ERR);
+ y -= lines_per_block;
+ }
+
+ /* Now take care of any remaining pixels in the frame buffer. */
+ nbytes = (fbwidth * fbheight) - (nblocks * nbytes);
+ if (nbytes && nl >= 0) {
+ lines_per_block = nbytes / fbwidth;
+ bp = block + (lines_per_block - 1) * fbwidth;
+
+ if (nnx != fbwidth || nny != fbheight) {
+ /* Clear the block array */
+ for (k=0; k < nbytes; k++)
+ block[k] = 0;
+ }
+
+ /* Map image pixels to the data block. */
+ if (nl >= 0) {
+ for (j=0; j < lines_per_block && nl >= 0; j++) {
+ if (fbline == imline) {
+ bcopy (ip, bp+lx, nnx);
+ ip += nx;
+ imline--;
+ nl--;
+ }
+ bp -= fbwidth;
+ fbline--;
+ }
+ if (imd_writeLine(imd, block, nbytes, 0, 0))
+ return (ERR);
+ }
+ }
+
+ free ((char *)block);
+ return (OK);
+}
+
+
+/* IMD_READIMAGE -- Read the currently displayed image and return a pointer to
+ * the array and it's dimensions. Since we know where the image was written
+ * in the frame buffer this is really just a large subregion read.
+ */
+
+int
+imd_readImage (imd, pix, nx, ny)
+IMDPtr imd; /* package pointer */
+uchar *pix; /* image pixels (output)*/
+int *nx, *ny; /* dimensions (output) */
+{
+ *nx = (imd->xe - imd->xs + 1);
+ *ny = (imd->ye - imd->ys + 1);
+
+ if (imd_debug)
+ printf ("[imd_readImage] nx=%d ny=%d at [%d,%d]\n",
+ *nx, *ny, imd->xs, imd->ys);
+
+ /* Read the image region buffer. */
+ if (!pix)
+ pix = (uchar *) malloc ((*nx) * (*ny));
+ return (imd_readSubRaster(imd, imd->xs, imd->ys, *nx, *ny, pix));
+}
+
+
+/* IMD_READFRAMEBUFFER -- Read the contents of the entire frame buffer and
+ * return a pointer to the array and it's dimensions.
+ */
+
+int
+imd_readFrameBuffer (imd, pix, nx, ny)
+IMDPtr imd; /* package pointer */
+uchar *pix; /* image pixels (output)*/
+int *nx, *ny; /* dimensions (output) */
+{
+ if (imd_debug)
+ printf ("[imd_readFrameBuffer]\n");
+
+ *nx = imd->fbtab[imd->fbconfig-1]->width;
+ *ny = imd->fbtab[imd->fbconfig-1]->height;
+
+ if (imd_debug)
+ printf ("[imd_readFrameBuffer] nx=%d ny=%d at [%d,%d]\n",
+ *nx, *ny, 0, 0);
+
+ /* Read the frame buffer. */
+ if (!pix)
+ pix = (uchar *) malloc ((*nx) * (*ny));
+ return (imd_readSubRaster(imd, 0, 0, *nx, *ny, pix));
+}
+
+
+/* IMD_SETFRAME -- Set the current display frame.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_setFrame (
+ IMDPtr imd, /* package pointer */
+ int frame /* frame number */
+)
+#else
+
+int
+imd_setFrame (imd, frame)
+IMDPtr imd; /* package pointer */
+int frame; /* frame number */
+#endif
+{
+ if (imd_debug)
+ printf ("[imd_setFrame] frame = %d\n", frame);
+
+ imd->frame = frame;
+ return (com_setFrame (imd->dataout, imd->frame));
+}
+
+
+/* IMD_SETFBCONFIG -- Select the frame buffer configuration.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_setFBConfig (
+ IMDPtr imd, /* package pointer */
+ int configno /* frame config number */
+)
+#else
+
+int
+imd_setFBConfig (imd, configno)
+IMDPtr imd; /* package pointer */
+int configno; /* frame config number */
+#endif
+{
+ if (imd_debug)
+ printf ("[imd_setFBConfig] config = %d\n", configno);
+
+ imd->fbconfig = configno;
+ return (com_setFBConfig (imd->dataout, imd->fbconfig));
+}
+
+
+/* IMD_GETFBCONFIG -- Get the current frame buffer config info used by the
+ * the interface.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_getFBConfig (
+ IMDPtr imd, /* package pointer */
+ int *configno, /* frame config number */
+ int *width,
+ int *height, /* frame buffer size */
+ int *nframes /* number of frames */
+)
+#else
+
+int
+imd_getFBConfig (imd, configno, width, height, nframes)
+IMDPtr imd; /* package pointer */
+int *configno; /* frame config number */
+int *width, *height; /* frame buffer size */
+int *nframes; /* number of frames */
+#endif
+{
+ *configno = imd->fbconfig;
+ *width = imd->fbtab[imd->fbconfig-1]->width;
+ *height = imd->fbtab[imd->fbconfig-1]->height;
+ *nframes = imd->fbtab[imd->fbconfig-1]->nframes;
+ if (imd_debug)
+ printf ("[imd_getFBConfig] config=%d w=%d h=%d nf=%d\n",
+ *configno, *width, *height, *nframes);
+
+ return (com_setFBConfig (imd->dataout, imd->fbconfig));
+}
+
+
+/* IMD_SETNAME -- Set the current image name (for the WCS string);
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_setName (
+ IMDPtr imd, /* package pointer */
+ char *name /* image name */
+)
+#else
+
+int
+imd_setName (imd, name)
+IMDPtr imd; /* package pointer */
+char *name; /* image name */
+#endif
+{
+ if (imd_debug)
+ printf ("[imd_setName] Name = %s\n", name);
+
+ strcpy (imd->name, name);
+ return (OK);
+}
+
+
+/* IMD_SETTITLE -- Set the current image title (for the WCS string)
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_setTitle (
+ IMDPtr imd, /* package pointer */
+ char *title /* image title */
+)
+#else
+
+int
+imd_setTitle (imd, title)
+IMDPtr imd; /* package pointer */
+char *title; /* image title */
+#endif
+{
+ if (imd_debug)
+ printf ("[imd_setTitle] title = %s\n", title);
+
+ strcpy (imd->title, title);
+ return (OK);
+}
+
+
+/* IMD_SETCURSOR -- Set the image cursor position.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_setCursor (
+ IMDPtr imd, /* package pointer */
+ int x,
+ int y, /* position */
+ int wcs /* cursor wcs */
+)
+#else
+
+int
+imd_setCursor (imd, x, y, wcs)
+IMDPtr imd; /* package pointer */
+int x, y; /* position */
+int wcs; /* cursor wcs */
+#endif
+{
+ if (imd_debug)
+ printf ("[imd_setCursor] position = [%d,%d]\n", x, y);
+
+ /* need to convert to frame coords? */
+
+ return (com_setCursor(imd->dataout, x, y, wcs));
+}
+
+
+/* IMD_CLEARFRAME -- Clear the current display frame.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_clearFrame (
+ IMDPtr imd /* package pointer */
+)
+#else
+
+int
+imd_clearFrame (imd)
+IMDPtr imd; /* package pointer */
+#endif
+{
+ if (imd_debug)
+ printf ("[imd_eraseFrame]\n");
+
+ return (com_eraseFrame(imd->dataout));
+}
+
+
+/* IMD_READSUBRASTER -- Read a rectangular region of the frame buffer.
+ */
+
+int
+imd_readSubRaster (imd, llx, lly, nx, ny, pix)
+IMDPtr imd; /* package pointer */
+int llx, lly; /* region corner */
+int nx, ny; /* dimensions */
+uchar *pix; /* image pixels (output)*/
+{
+ register int i, j, nl, y, nbytes, lx, ly;
+ register uchar *ip = NULL, *bp = NULL, *block = NULL;
+ register int nblocks, lines_per_block;
+ register int nnx = nx, nny = ny, x_off = 0, y_off = 0;
+ int fbwidth = imd->fbtab[imd->fbconfig-1]->width;
+ int fbheight = imd->fbtab[imd->fbconfig-1]->height;
+
+
+ /* Make sure we've got a reasonable request. */
+ if (nx > fbwidth || ny > fbheight) {
+ fprintf (stderr,
+ "Error: attempt to read raster larger than display.\n");
+ return (ERR);
+ }
+
+ /* Now see whether the raster extends over the boundaries of the
+ * frame buffer in any direction. If so we'll clip the raster to
+ * write only those pixels on the frame buffer.
+ */
+
+ if (-llx > imd->xs) { /* raster overflows bottom */
+ x_off = -llx + imd->xs;
+ nnx = nx - x_off;
+ }
+ if (-lly > imd->ys) { /* raster overflows left */
+ y_off = -lly + imd->ys;
+ nny = ny - y_off;
+ }
+ if ((llx + nx) > fbwidth) { /* raster overflows right */
+ nnx = fbwidth - llx;
+ }
+ if ((lly + ny) > fbheight) { /* raster overflows top */
+ nny = fbheight - lly;
+ /*y_off = ny - nny;*/
+ }
+
+ /* Allocate the pointer if needed. Clear the output array if we're
+ * clipping to guarantee zero values.
+ */
+ if (!pix)
+ pix = (uchar *) calloc (nx * ny, sizeof (uchar));
+
+ /* Convert corner position to frame buffer coords. */
+ lx = max (0, llx + imd->xs);
+ ly = min (fbheight - 1, fbheight - (lly + imd->ys) - 0);
+
+ if (imd_debug) {
+ printf ("[imd_readSubRas] %d bytes at [%d,%d] orig [%d,%d]\n",
+ nx*ny, lx, ly, llx, lly);
+ printf ("[imd_readSubRas] img corner at [%d,%d] -> [%d,%d]\n",
+ imd->xs, imd->ys, imd->xe, imd->ye);
+ }
+
+ /* Figure out how many reads we'll need. */
+ if (imd->model == MOD_NORMAL) {
+ lines_per_block = min (nny, (int)(SZ_BLOCK / fbwidth));
+ nbytes = fbwidth * lines_per_block;
+ } else {
+ lines_per_block = min (nny, (int)(SZ_BLOCK / nx));
+ nbytes = nx * lines_per_block;
+ }
+ nblocks = (int) (nny / lines_per_block);
+ block = (uchar *) calloc (nbytes, sizeof (uchar));
+
+ if (imd_debug) {
+ printf("[imd_readSubRas] ny=%d nblks=%d lin/bl=%d nbytes=%d\n",
+ ny, nblocks, lines_per_block, nbytes);
+ printf("[imd_readSubRas] nnx=%d nny=%d llx=%d lly=%d xo=%d yo=%d\n",
+ nnx, nny, llx, lly, x_off, y_off);
+ }
+
+
+ /* Loop over each of the blocks needed to get the region. */
+ nl = nny;
+ ip = pix + (y_off * nx) + x_off;
+ y = ly - lines_per_block + 1;
+ for (i=0; i < nblocks; i++, y -= lines_per_block) {
+ if (imd_readLine(imd, block, nbytes, 0, y))
+ return (ERR);
+
+ /* Pull the requested pixels from the block. */
+ bp = block + (lines_per_block - 1) * fbwidth;
+ for (j=0; j < lines_per_block && nl; j++) {
+ /*bcopy (bp+lx+x_off-1, ip, nnx);*/
+ bcopy (bp+lx, ip, nnx);
+ bp -= fbwidth;
+ ip += nx;
+ nl--;
+ }
+ }
+
+ /* Take care of the remaining pixels. */
+ if (nl) {
+ nbytes = nl * fbwidth;
+ y += lines_per_block - nl + 1;
+
+ /* Read the last block. */
+ if (imd_readLine(imd, block, nbytes, 0, y))
+ return (ERR);
+
+ /* Pull the requested pixels from the block. */
+ bp = block + (nl - 1) * fbwidth;
+ for (j=0; j < nl; j++) {
+ /*bcopy (bp+lx+x_off-1, ip, nx);*/
+ bcopy (bp+lx, ip, nnx);
+ bp -= fbwidth;
+ ip += nx;
+ }
+ }
+
+ free ((char *)block);
+ return (OK);
+}
+
+
+/* IMD_WRITESUBRASTER -- Write a rectangular region of the frame buffer.
+ */
+
+int
+imd_writeSubRaster (imd, llx, lly, nx, ny, pix)
+IMDPtr imd; /* package pointer */
+int llx, lly; /* region corner */
+int nx, ny; /* dimensions */
+uchar *pix; /* subraster pixels */
+{
+ register int i, j, nl, y, nbytes, lx, ly;
+ register uchar *ip = NULL, *bp = NULL, *block = NULL;
+ register int nblocks, lines_per_block;
+ register int nnx = nx, nny = ny, x_off = 0, y_off = 0;
+ int fbwidth = imd->fbtab[imd->fbconfig-1]->width;
+ int fbheight = imd->fbtab[imd->fbconfig-1]->height;
+
+
+ /* Make sure at least part of the raster is on the frame buffer,
+ * otherwise it's an error.
+ */
+ if (llx > fbwidth || lly > fbheight || (llx+nx) < 0 || (lly+ny) < 0) {
+ fprintf (stderr, "Error: attempt to write raster out of bounds.\n");
+ return (ERR);
+ }
+
+ /* Now see whether the raster extends over the boundaries of the
+ * frame buffer in any direction. If so we'll clip the raster to
+ * write only those pixels on the frame buffer.
+ */
+ if (-llx > imd->xs) { /* raster overflows bottom */
+ x_off = -llx + imd->xs;
+ nnx = nx - x_off;
+ }
+ if (-lly > imd->ys) { /* raster overflows left */
+ y_off = -lly + imd->ys;
+ nny = ny - y_off;
+ }
+ if ((llx + nx) > fbwidth) /* raster overflows right */
+ nnx = fbwidth - llx;
+ if ((lly + ny) > fbheight) /* raster overflows top */
+ nny = fbheight - lly;
+
+ /* Check to see if the image to be displayed is larger than the
+ * current frame buffer.
+ */
+ if (nx > fbwidth || ny > fbheight) {
+ nnx = min(nx, fbwidth); /* get new dimensions */
+ nny = min(ny, fbheight);
+ x_off = (nx>fbwidth ? ((nx - fbwidth) / 2 - 1) : 0);
+ y_off = (ny>fbheight ? ((ny - fbheight) / 2 - 1) : 0);
+ }
+
+ ip = pix + (y_off * nx) + x_off;
+
+ /* Convert corner position to frame buffer coords. */
+ lx = max (0, llx + imd->xs);
+ ly = min (fbheight - 1, fbheight - (lly + imd->ys) - 0);
+
+ if (imd_debug)
+ printf ("[imd_writeSubRaster] %d bytes at [%d,%d] of [%d,%d]\n",
+ nx*ny, lx, ly, fbwidth, fbheight);
+
+ /* Figure out how many reads we'll need. */
+ if (imd->model == MOD_NORMAL) {
+ lines_per_block = min (nny, (int)(SZ_BLOCK / fbwidth));
+ nbytes = fbwidth * lines_per_block;
+ } else {
+ lines_per_block = min (nny, (int)(SZ_BLOCK / nx));
+ nbytes = nx * lines_per_block;
+ }
+ nblocks = (int) (nny / lines_per_block);
+ block = (uchar *) calloc (nbytes, sizeof (uchar));
+
+ if (imd_debug) {
+ printf ("\tnnx=%d nny=%d llx=%d lly=%d xo=%d yo=%d xs=%d ys=%d\n",
+ nnx, nny, llx, lly, x_off, y_off, imd->xs, imd->ys);
+ printf ("\tny=%d nblocks=%d lines/block=%d nbytes=%d\n",
+ ny, nblocks, lines_per_block, nbytes);
+ }
+
+ /* Loop over each of the blocks needed to get the region. */
+ nl = nny;
+ y = ly - lines_per_block + 1;
+ for (i=0; i < nblocks; i++, y -= lines_per_block) {
+
+ if (imd->model == MOD_NORMAL) {
+
+ /* Read a block of data containing the subraster but only if
+ * we need to.
+ */
+ if (nnx != fbwidth)
+ if (imd_readLine(imd, block, nbytes, 0, y))
+ return (ERR);
+
+ /* Copy the subraster pixels to the block just read. */
+ bp = block + (lines_per_block - 1) * fbwidth;
+ for (j=0; j < lines_per_block && nl; j++) {
+ bcopy (ip, bp+lx, nnx);
+ bp -= fbwidth;
+ ip += nx;
+ nl--;
+ }
+
+ /* Write the edited block back to the server. */
+ if (imd_writeLine(imd, block, nbytes, 0, y))
+ return (ERR);
+
+ } else {
+ /* Copy the subraster pixels to the block just read. */
+ bp = block + (lines_per_block - 1) * nx;
+ for (j=0; j < lines_per_block && nl; j++) {
+ bcopy (ip, bp, nnx);
+ bp -= nx;
+ ip += nx;
+ nl--;
+ }
+
+ /* Write the edited block back to the server. */
+ nbytes = lines_per_block * ny;
+ if (imd_writeRawBuf(imd, block, nbytes, lx, y,
+ nx, lines_per_block))
+ return (ERR);
+ }
+ }
+
+ /* Take care of the remaining pixels. */
+ if (nl) {
+ nbytes = nl * fbwidth;
+
+ /* Read the last block. */
+ y += lines_per_block - nl;
+
+
+ if (imd->model == MOD_NORMAL) {
+ if (nnx != fbwidth)
+ if (imd_readLine(imd, block, nbytes, 0, y))
+ return (ERR);
+
+ /* Copy the subraster pixels to the block just read. */
+ bp = block + (nl - 1) * fbwidth;
+ for (j=0; j < nl; j++) {
+ bcopy (ip, bp+lx, nnx);
+ bp -= fbwidth;
+ ip += nx;
+ }
+
+ /* Write the edited block back to the server. */
+ if (imd_writeLine(imd, block, nbytes, 0, y))
+ return (ERR);
+
+ } else {
+ /* Copy the subraster pixels to the block just read. */
+ bp = block + (nl - 1) * nx;
+ for (j=0; j < nl; j++) {
+ bcopy (ip, bp, nnx);
+ bp -= nx;
+ ip += nx;
+ }
+
+ /* Write the edited block back to the server. */
+ nbytes = nl * ny;
+ if (imd_writeRawBuf(imd, block, nbytes, lx, y, nx, nl))
+ return (ERR);
+ }
+ }
+
+ free ((char *)block);
+ return (OK);
+}
+
+
+/* IMD_SETDEBUG -- Set the state of the debug flag.
+ */
+
+#ifdef ANSI_FUNC
+
+int
+imd_setDebug (int state)
+#else
+
+int
+imd_setDebug (state)
+int state;
+#endif
+{
+ imd_debug = state;
+ return (OK);
+}
+
+
+
+/* ------------------
+ * PRIVATE PROCEDURES
+ * ------------------*/
+
+/* IMD_WRITELINE -- Send the command to write a block of pixels to the
+ * server. This is a low-level routine called to either write a single
+ * line of data, or when the number of bytes exceeds the frame buffer width
+ * it can be used to send a complete "block" in the image display.
+ */
+
+static int
+imd_writeLine (imd, pix, nbytes, x, y)
+IMDPtr imd; /* package pointer */
+uchar *pix; /* pixel array */
+int nbytes; /* npix to write */
+int x, y; /* coords for start */
+{
+ register short sx=x, sy=y;
+
+ if (imd_debug > 1)
+ printf ("[imd_writeLine] %d bytes at [%d,%d]\n", nbytes, x, y);
+
+ return (com_writeData(imd->dataout, sx, sy, pix, nbytes));
+}
+
+
+/* IMD_READLINE -- Send the command to read a sequential block of pixels
+ * from the server.
+ */
+
+static int
+imd_readLine (imd, pix, nbytes, x, y)
+IMDPtr imd; /* package pointer */
+uchar *pix; /* pixel array */
+int nbytes; /* npix to write */
+int x, y; /* coords for start */
+{
+ register short sx=x, sy=y;
+
+ if (imd_debug)
+ printf ("[imd_readLine] %d bytes at [%d,%d]\n", nbytes, x, y);
+
+ return (com_readData(imd->datain, imd->dataout, sx, sy, pix, &nbytes));
+}
+
+
+/* IMD_WRITERAWBUF -- Send the command to write a block of pixels to the
+ * server. This is a low-level routine called to either write a single
+ * line of data, or when the number of bytes exceeds the frame buffer width
+ * it can be used to send a complete "block" in the image display.
+ */
+
+static int
+imd_writeRawBuf (imd, pix, nbytes, x, y, nx, ny)
+IMDPtr imd; /* package pointer */
+uchar *pix; /* pixel array */
+int nbytes; /* npix to write */
+int x, y; /* coords for start */
+int nx, ny; /* dimensions of buf */
+{
+ register short sx=x, sy=y;
+
+ if (imd_debug > 1)
+ printf ("[imd_writeRawBuf] %d bytes at [%d,%d][%d,%d]\n",
+ nbytes, x, y, nx, ny);
+
+ return (com_writeSubraster(imd->dataout, sx, sy, pix, nx, ny));
+}
+
+
+/* IMD_READRAWBUF -- Send the command to write a block of pixels to the
+ * server. This is a low-level routine called to either write a single
+ * line of data, or when the number of bytes exceeds the frame buffer width
+ * it can be used to send a complete "block" in the image display.
+ */
+
+static int
+imd_readRawBuf (imd, pix, nbytes, x, y, nx, ny)
+IMDPtr imd; /* package pointer */
+uchar *pix; /* pixel array */
+int nbytes; /* npix to read */
+int x, y; /* coords for start */
+int nx, ny; /* dimensions of buf */
+{
+ register short sx=x, sy=y;
+
+ if (imd_debug > 1)
+ printf ("[imd_readRawBuf] %d bytes at [%d,%d][%d,%d]\n",
+ nbytes, x, y, nx, ny);
+
+ return (com_readSubraster(imd->dataout, sx, sy, pix, nx, ny));
+}
+
+
+/* IMD_INITIALIZE -- Allocate and initialize the imd package structure.
+ */
+
+#ifdef ANSI_FUNC
+
+static IMDPtr
+imd_initialize (
+ int fdin,
+ int fdout, /* device descriptors */
+ int domain, /* connection type */
+ int model /* subraster model */
+)
+#else
+
+static IMDPtr
+imd_initialize (fdin, fdout, domain, model)
+int fdin, fdout; /* device descriptors */
+int domain; /* connection type */
+int model; /* subraster model */
+#endif
+{
+ IMDPtr imd;
+
+ /* Allocate and initialize imd structure. */
+ imd = (struct IMD *) calloc (1, sizeof (struct IMD));
+
+ imd->datain = fdin;
+ imd->dataout = fdout;
+ imd->domain = domain;
+ imd->ztrans = W_LINEAR;
+ imd->frame = 1;
+ imd->fbconfig = 1;
+
+ /* Initialize a WCS, set the defaults for 512x512 framebuffer. */
+ imd->a = 1.0;
+ imd->b = 0.0;
+ imd->c = 0.0;
+ imd->d = -1.0;
+ imd->tx = 1.0;
+ imd->ty = 512.0;
+ imd->z1 = 0.0;
+ imd->z2 = 255.0;
+
+ /* Initialize the mapping. */
+ imd->sx = 1.0;
+ imd->sy = 1.0;
+ imd->snx = 512;
+ imd->sny = 512;
+ imd->dx = 0;
+ imd->dy = 0;
+ imd->dnx = 511;
+ imd->dny = 511;
+ imd->iis_valid = 0;
+
+ /* Allocate the structure pointers. */
+ imd->name = (char *) calloc (SZ_NAME, sizeof(char));
+ imd->title = (char *) calloc (SZ_NAME, sizeof(char));
+ imd->region = (char *) calloc (SZ_NAME, sizeof(char));
+ imd->ref = (char *) calloc (SZ_NAME, sizeof(char));
+
+ /* Get the server IIS version number. */
+ imd->iis_version = imd_wcsVersion (imd);
+
+printf ("init: model = %d\n", model);
+ if (imd->iis_version > 10) {
+ /* Server supports fast subraster writes.
+ */
+ if (model == MOD_NORMAL)
+ imd->model = MOD_FAST;
+ } else {
+ if (model == MOD_FAST)
+ imd->model = MOD_NORMAL;
+ }
+printf ("\n\niis_version=%d model=%d -> %d\n", imd->iis_version, model,
+imd->model);
+
+ /* Load the frame buffer configuration file. */
+ imd_loadImtoolrc (imd);
+
+ return (imd);
+}
+
+
+/* IMD_PARSEIMTDEV -- Parse an IMTDEV device string, returning the domain
+ * type as the function value and loading the path/host information as
+ * needed.
+ */
+
+#ifdef ANSI_FUNC
+
+static int
+imd_parseImtdev (
+ char *imtdev, /* device string */
+ char *unixaddr, /* unix socket path */
+ unsigned short *host_port, /* inet port number */
+ unsigned long *host_addr, /* inet host address */
+ char *ififo, /* fifo paths */
+ char *ofifo,
+ int *model /* subraster display model */
+)
+#else
+
+static int
+imd_parseImtdev (imtdev, unixaddr, host_port, host_addr, ififo, ofifo, model)
+char *imtdev; /* device string */
+char *unixaddr; /* unix socket path */
+unsigned short *host_port; /* inet port number */
+unsigned long *host_addr; /* inet host address */
+char *ififo, *ofifo; /* fifo paths */
+int *model; /* subraster display model */
+#endif
+{
+ char *ip, *dp;
+ char osfn[SZ_LINE*2];
+
+
+ if (imtdev == NULL)
+ return ERR;
+ else {
+ /* Extract any subraster display model option from the IMTDEV
+ ** string. This will be the word "fast:" or "normal:" prefixed
+ ** to the device string. A missing option will use the default
+ ** model, either way we'll update the device string before parsing
+ ** for the connection.
+ */
+ if (strncmp (imtdev, "fast:", 5) == 0) {
+ *model = MOD_FAST;
+ dp = &imtdev[5];
+ } else if (strncmp (imtdev, "normal:", 5) == 0) {
+ *model = MOD_NORMAL;
+ dp = &imtdev[7];
+ } else {
+ *model = DEF_MODEL;
+ dp = imtdev;
+ }
+printf ("parse: model = %d (def=%d)\n", *model, DEF_MODEL);
+
+
+ /* Expand any %d fields in the network address to the UID. */
+ sprintf (osfn, (char *)dp, getuid(), getuid());
+
+ if (strncmp (osfn, "fifo:", 5) == 0) {
+ /* FIFO (named pipe) connection. */
+ ip = osfn + 5;
+ if (!imd_getstr (&ip, ififo, SZ_NAME))
+ return ERR;
+ if (!imd_getstr (&ip, ofifo, SZ_NAME))
+ return ERR;
+
+ return FIFO;
+
+ } else if (strncmp (osfn, "inet:", 5) == 0) {
+
+ /* Internet connection. */
+ char port_str[SZ_NAME], host_str[SZ_NAME];
+ unsigned short port;
+ struct servent *sv;
+ struct hostent *hp;
+
+ /* Get port number. This may be specified either as a service
+ * name or as a decimal port number.
+ */
+ ip = osfn + 5;
+ if (imd_getstr (&ip, port_str, SZ_NAME) <= 0)
+ return ERR;
+ if (isdigit (port_str[0])) {
+ port = atoi (port_str);
+ *host_port = htons (port);
+ } else if ((sv = getservbyname(port_str,"tcp"))) {
+ *host_port = sv->s_port;
+ } else
+ return ERR;
+
+ /* Get host address. This may be specified either has a host
+ * name or as an Internet address in dot notation. If no host
+ * name is specified default to the local host.
+ */
+ if (imd_getstr (&ip, host_str, SZ_NAME) <= 0)
+ strcpy (host_str, "localhost");
+ if (isdigit (host_str[0])) {
+ *host_addr = inet_addr (host_str);
+ if ((int)*host_addr == -1)
+ return ERR;
+ } else if ((hp = gethostbyname(host_str))) {
+ bcopy (hp->h_addr, (char *)host_addr, sizeof(*host_addr));
+ } else
+ return ERR;
+
+ return INET;
+
+ } else if (strncmp (osfn, "unix:", 5) == 0) {
+ /* Unix domain socket connection. */
+ ip = osfn + 5;
+ if (!imd_getstr (&ip, unixaddr, SZ_NAME))
+ return ERR;
+
+ return UNIX;
+ }
+ }
+
+
+ return (ERR);
+}
+
+
+/* IMD_WCSVERSION -- Query the server for the support IIS WCS version.
+ */
+
+#ifdef ANSI_FUNC
+
+static int
+imd_wcsVersion (
+ IMDPtr imd /* package pointer */
+)
+#else
+
+static int
+imd_wcsVersion (imd)
+IMDPtr imd; /* package pointer */
+#endif
+{
+ /* Allow the user to disable the use of maps. */
+ if (getenv ("CDL_NOMAPS"))
+ return (0);
+ else
+ return (com_wcsVersion (imd->datain, imd->dataout));
+}
+
+
+/* IMD_LOADIMTOOLRC -- Load the frame buffer configuration table into a
+ * runtime table. An error is returned if the table cannot be found and
+ * a default frame buffer size of 512x512 with 2 frames is available (this
+ * is all the server will have abvailable anyway).
+ */
+
+#ifdef ANSI_FUNC
+
+static int
+imd_loadImtoolrc (
+ IMDPtr imd /* package pointer */
+)
+#else
+
+static int
+imd_loadImtoolrc (imd)
+IMDPtr imd; /* package pointer */
+#endif
+{
+ register char *ip;
+ register FILE *fp = NULL;
+ int config, nframes, width, height, i;
+ char *fname;
+
+
+ /* Initialize the config table. */
+ for (i=0; i < MAX_FBCONFIG; i++) {
+ imd->fbtab[i] = (FBTab *) calloc (sizeof(FBTab), sizeof(char));
+ imd->fbtab[i]->config = i;
+ imd->fbtab[i]->nframes = 2;
+ imd->fbtab[i]->width = DEF_FRAME_WIDTH;
+ imd->fbtab[i]->height = DEF_FRAME_HEIGHT;
+ }
+
+ /* Attempt to open the config file. */
+ if ((fname=getenv(FBCONFIG_ENV1)) || (fname=getenv(FBCONFIG_ENV2))) {
+ fp = fopen (fname, "r");
+ if (imd_debug)
+ printf ("Using IMTOOLRC='%s'...\n", fname);
+ }
+ if (!fp && (fname = getenv ("HOME"))) {
+ if (imd_debug)
+ printf ("$IMTOOLRC not found...\n");
+ sprintf (buf, "%s/%s", fname, FBCONFIG_1);
+ fp = fopen (fname = buf, "r");
+ if (fp && imd_debug)
+ printf ("Using $HOME/.imtoolrc...\n");
+ }
+ if (!fp) {
+ if (imd_debug)
+ printf ("$HOME/.imtoolrc not found...\n");
+ fp = fopen ((fname = FBCONFIG_2), "r");
+ if (fp && imd_debug)
+ printf ("Using /usr/local/lib/imtoolrc...\n");
+ }
+ if (!fp) {
+ fprintf (stderr,
+ "Warning: cannot find frame buffer configuration table.\n");
+ return (ERR);
+ }
+
+ /* Scan the frame buffer configuration file.
+ */
+ while (fgets (buf, SZ_LINE, fp) != NULL) {
+ /* Skip comment lines and blank lines. */
+ for (ip=buf; *ip == ' ' || *ip == '\t'; ip++)
+ ;
+ if (*ip == '\n' || *ip == '#')
+ continue;
+ if (!isdigit (*ip))
+ continue;
+ switch (sscanf (ip, "%d%d%d%d",&config,&nframes,&width,&height)) {
+ case 4:
+ break; /* normal case */
+ case 3:
+ height = width; /* default to square format */
+ break;
+ default:
+ fprintf (stderr, "Warning: bad config `%s'\n", ip);
+ continue;
+ }
+
+ nframes = max (1, nframes);
+ width = max (1, width);
+ height = max (1, height);
+
+ /* Since the frame buffer is stored in a memory pixrect
+ * (effectively), the line length should be an integral number
+ * of 16 bit words.
+ */
+ if (width & 1) {
+ fprintf (stderr, "Warning: fb config %d [%d-%dx%d] - ",
+ config, nframes, width, height);
+ fprintf (stderr, "frame width should be even, reset to %d\n",
+ --width);
+ }
+
+ imd->fbtab[config-1]->config = max(1,min(MAX_FBCONFIG, config));
+ imd->fbtab[config-1]->nframes = nframes;
+ imd->fbtab[config-1]->width = width;
+ imd->fbtab[config-1]->height = height;
+
+ if (imd_debug > 1)
+ printf ("%3d %2d %6d %6d\n", config, nframes, width, height);
+ }
+
+ fclose (fp);
+ return (OK);
+}
+
+
+/* IMD_GETSTR -- Internal routine to extract a colon delimited string from a
+ * network filename.
+ */
+#ifdef ANSI_FUNC
+
+static int
+imd_getstr (char **ipp, char *obuf, int maxch)
+#else
+
+static int
+imd_getstr (ipp, obuf, maxch)
+char **ipp;
+char *obuf;
+int maxch;
+#endif
+{
+ register char *ip = *ipp, *op = obuf;
+ register char *otop = obuf + maxch;
+ char *start;
+
+ while (isspace(*ip))
+ ip++;
+ for (start=ip; *ip; ip++) {
+ if (*ip == ':') {
+ ip++;
+ break;
+ } else if (op && op < otop)
+ *op++ = *ip;
+ }
+
+ if (op)
+ *op = '\0';
+ *ipp = ip;
+
+ return (ip - start);
+}
+
+
+/* IMD_MINMAX -- Compute the min/max values of an array.
+ */
+
+static void
+imd_minmax (pix, nbytes, pmin, pmax)
+uchar *pix;
+int nbytes;
+int *pmin, *pmax;
+{
+ register int i;
+
+ *pmin = *pmax = pix[0];
+ for (i=1; i<nbytes; i++) {
+ *pmin = min (*pmin, pix[i]);
+ *pmax = max (*pmax, pix[i]);
+ }
+}