[comp.sources.x] v10i082: xv - display and manipulate images, Part04/10

bradley@halibut.cis.upenn.edu (John Bradley) (11/28/90)

Submitted-by: bradley@halibut.cis.upenn.edu (John Bradley)
Posting-number: Volume 10, Issue 82
Archive-name: xv/part04

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./xvpbm.c`
then
echo "writting ./xvpbm.c"
cat > ./xvpbm.c << '\BARFOO\'
/*
 * xvpbm.c - load routine for 'pm' format pictures
 *
 * LoadPBM(fname, numcols)  -  loads a PBM, PGM, or PPM file
 * WritePBM(fp,pic,w,h,r,g,b,numcols,style,raw,cmt)
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"



/* comments on error handling:
   a truncated file is not considered a Major Error.  The file is loaded, the
   rest of the pic is filled with 0's.

   a file with garbage characters in it is an unloadable file.  All allocated
   stuff is tossed, and LoadPBM returns non-zero

   not being able to malloc is a Fatal Error.  The program is aborted. */


#define TRUNCSTR "File appears to be truncated."

static int garbage;
static long numgot, filesize;


static int loadpbm(), loadpgm(), loadppm();
static int getint(),  getbit(),  PBMerr();


/*******************************************/
int LoadPBM(fname,nc)
     char *fname;
     int   nc;
/*******************************************/
{
  FILE  *fp;
  int    c, c1;
  int    w, h, maxv, rv;

  garbage = maxv = 0;

  /* open the stream, if necesary */
  fp=fopen(fname,"r");
  if (!fp) return 1;
  
  /* figure out the file size (for Informational Purposes Only) */
  fseek(fp, 0L, 2);
  filesize = ftell(fp);
  fseek(fp, 0L, 0);

  /* read the first two bytes of the file to determine which format
     this file is.  "P1" = ascii bitmap, "P2" = ascii greymap,
     "P3" = ascii pixmap, "P4" = raw bitmap, "P5" = raw greymap,
     "P6" = raw pixmap */

  c = getc(fp);  c1 = getc(fp);
  if (c!='P' || c1<'1' || c1>'6') return(PBMerr("unknown format"));

  /* read in header information */
  w = getint(fp);  h = getint(fp);

  /* if we're not reading a bitmap, read the 'max value' */
  if ( !(c1=='1' || c1=='4')) {
    maxv = getint(fp);
    if (maxv < 1) garbage=1;    /* to avoid 'div by zero' probs */
  }


  if (garbage) {
    if (fp!=stdin) fclose(fp);
    return (PBMerr("Garbage characters in header."));
  }

  rv = 0;

  /* call the appropriate subroutine to handle format-specific stuff */
  if      (c1=='1' || c1=='4') rv = loadpbm(fp,w,h,       c1=='4' ? 1 : 0);
  else if (c1=='2' || c1=='5') rv = loadpgm(fp,w,h, maxv, c1=='5' ? 1 : 0);
  else if (c1=='3' || c1=='6') rv = loadppm(fp,w,h, maxv, c1=='6' ? 1 : 0, nc);

  if (fp!=stdin) fclose(fp);
  return(rv);
}  



/*******************************************/
static int loadpbm(fp, w, h, raw)
FILE *fp;
int   w,h,raw;
{
  byte *pix;
  int   i,j,bit;


  SetISTR(ISTR_FORMAT,"PBM, %s format.  (%ld bytes)", 
	  (raw) ? "raw" : "ascii", filesize);

  /* load up the XV global variables */
  pic = (byte *) calloc(w*h,1);
  if (!pic) FatalError("couldn't malloc 'pic'");

  pWIDE = w;  pHIGH = h;

  /* B/W bitmaps have a two entry colormap */
  r[0] = g[0] = b[0] = 255;   /* 0 = white */
  r[1] = g[1] = b[1] = 0;     /* 1 = black */

  if (!raw) {
    numgot = 0;
    for (i=0, pix=pic; i<h; i++)
      for (j=0; j<w; j++, pix++)
	*pix = getbit(fp);

    if (numgot != w*h) PBMerr(TRUNCSTR);
    if (garbage) {
      free(pic);
      return(PBMerr("Garbage characters in image data."));
    }
  }


  else {   /* read raw bits */
    int trunc = 0, k = 0;

    for (i=0, pix=pic; i<h; i++)
      for (j=0,bit=0; j<w; j++, pix++, bit++) {

	bit &= 7;
	if (!bit) {
	  k = getc(fp);
	  if (k==EOF) { trunc=1; k=0; }
	}

	*pix = (k&0x80) ? 1 : 0;
	k = k << 1;
      }

    if (trunc) PBMerr(TRUNCSTR);
  }

  return 0;
}


/*******************************************/
static int loadpgm(fp, w, h, maxv, raw)
FILE *fp;
int   w,h,maxv,raw;
{
  byte *pix;
  int   i,j,bitshift;

  SetISTR(ISTR_FORMAT,"PGM, %s format.  (%ld bytes)", 
	  (raw) ? "raw" : "ascii", filesize);

  /* load up the XV global variables */
  pic = (byte *) calloc(w*h,1);
  if (!pic) FatalError("couldn't malloc 'pic'");

  pWIDE = w;  pHIGH = h;

  /* if maxv>255, keep dropping bits until it's reasonable */
  bitshift = 0;
  while (maxv>255) { maxv = maxv>>1;  bitshift++; }

  /* fill in a greyscale colormap where maxv maps to 255 */
  for (i=0; i<=maxv; i++)
    r[i] = g[i] = b[i] = (i*255)/maxv;

  if (!raw) {
    numgot = 0;
    for (i=0, pix=pic; i<h; i++)
      for (j=0; j<w; j++, pix++)
	*pix = (getint(fp) >> bitshift);
  }

  else numgot = fread(pic, 1, w*h, fp);   /* read raw data */

  if (numgot != w*h) PBMerr(TRUNCSTR);

  if (garbage) {
    free(pic);
    return (PBMerr("Garbage characters in image data."));
  }

  return 0;
}


/*******************************************/
static int loadppm(fp, w, h, maxv, raw, nc)
FILE *fp;
int   w,h,maxv,raw,nc;
{
  byte *pix, *pic24, scale[256];
  int   i,j,bitshift;

  SetISTR(ISTR_FORMAT,"PPM, %s format.  (%ld bytes)", 
	  (raw) ? "raw" : "ascii", filesize);

  /* allocate 24-bit image */
  pic24 = (byte *) calloc(w*h*3,1);
  if (!pic24) FatalError("couldn't malloc 'pic24'");

  /* if maxv>255, keep dropping bits until it's reasonable */
  bitshift = 0;
  while (maxv>255) { maxv = maxv>>1;  bitshift++; }

  if (!raw) {
    numgot = 0;
    for (i=0, pix=pic24; i<h; i++)
      for (j=0; j<w*3; j++, pix++)
	*pix = (getint(fp) >> bitshift);
  }

  else numgot = fread(pic24, 1, w*h*3, fp);    /* read raw data */

  if (numgot != w*h*3) PBMerr(TRUNCSTR);

  if (garbage) {
    free(pic24);
    return(PBMerr("Garbage characters in image data."));
  }

  /* have to scale all RGB values up (Conv24to8 expects RGB values to
     range from 0-255 */

  if (maxv<255) { 
    for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv;

    for (i=0, pix=pic24; i<h; i++) 
      for (j=0; j<w*3; j++, pix++) 
	*pix = scale[*pix];
  }

  i = Conv24to8(pic24,w,h,nc);
  free(pic24);
  return i;
}



/*******************************************/
static int getint(fp)
FILE *fp;
{
  int c, i;

  /* skip forward to start of next number */
  c = getc(fp);
  while (1) {
    /* eat comments */
    if (c=='#') {   /* if we're at a comment, read to end of line */
      while (c != '\n' && c != EOF) c=getc(fp);
    }

    if (c==EOF) return 0;
    if (c>='0' && c<='9') break;   /* we've found what we were looking for */

    /* see if we are getting garbage (non-whitespace) */
    if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=',') garbage=1;

    c = getc(fp);
  }


  /* we're at the start of a number, continue until we hit a non-number */
  i = 0;
  while (1) {
    i = (i*10) + (c - '0');
    c = getc(fp);
    if (c==EOF) return i;
    if (c<'0' || c>'9') break;
  }

  numgot++;
  return i;
}



/*******************************************/
static int getbit(fp)
FILE *fp;
{
  int c;

  /* skip forward to start of next number */
  c = getc(fp);
  while (1) {
    /* eat comments */
    if (c=='#') {   /* if we're at a comment, read to end of line */
      while (c != '\n' && c != EOF) c=getc(fp);
    }

    if (c==EOF) return 0;
    if (c=='0' || c=='1') break;   /* we've found what we were looking for */

    /* see if we are getting garbage (non-whitespace) */
    if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=',') garbage=1;

    c = getc(fp);
  }


  numgot++;
  return(c-'0');
}


/*******************************************/
static int PBMerr(st)
char *st;
{
  SetISTR(ISTR_WARNING,st);
  return 1;
}





/*******************************************/
int WritePBM(fp,pic,w,h,rmap,gmap,bmap,numcols,colorstyle,raw)
FILE *fp;
byte *pic;
int   w,h;
byte *rmap, *gmap, *bmap;
int   numcols, colorstyle, raw;
{
  /* writes a PBM/PGM/PPM file to the already open stream
     if (raw), writes as RAW bytes, otherwise writes as ASCII 
     'colorstyle' single-handedly determines the type of file written
     if colorstyle==0, (Full Color) a PPM file is written
     if colorstyle==1, (Greyscale)  a PGM file is written
     if colorstyle==2, (B/W stipple) a PBM file is written */

  int   magic;
  byte *pix;
  int   i,j,len;

  /* calc the appropriate magic number for this file type */
  magic = 0;
  if      (colorstyle==0) magic = 3;
  else if (colorstyle==1) magic = 2;
  else if (colorstyle==2) magic = 1;

  if (raw && magic) magic+=3;

  if (!magic) return(PBMerr("WritePBM: unknown file format"));

  /* write the header info */
  fprintf(fp,"P%d\n",magic);
  fprintf(fp,"# created by 'xv %s'\n", namelist[curname]);
  fprintf(fp,"%d %d\n",w,h);
  if (colorstyle!=2) fprintf(fp,"255\n");

  if (ferror(fp)) return -1;

  /* write the image data */

  if (colorstyle==0) {                  /* 24bit RGB, 3 bytes per pixel */
    for (i=0, pix=pic, len=0; i<h; i++)
      for (j=0; j<w; j++,pix++) {
	if (raw) {
	  putc(r[*pix],fp);  
	  putc(g[*pix],fp);  
	  putc(b[*pix],fp);
	}
	else {
	  fprintf(fp,"%3d %3d %3d ",r[*pix], g[*pix], b[*pix]);
	  len+=12;
	  if (len>58) { fprintf(fp,"\n");  len=0; }
	}
      }
  }

  else if (colorstyle==1) {             /* 8-bit greyscale */
    byte rgb[256];
    for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
    for (i=0, pix=pic, len=0; i<w*h; i++,pix++) {
      if (raw) putc(rgb[*pix],fp);
      else {
	fprintf(fp,"%3d ",rgb[*pix]);
	len += 4;
	if (len>66) { fprintf(fp,"\n");  len=0; }
      }
    }
  }

  else if (colorstyle==2) {             /* 1-bit B/W stipple */
    int bit,k;
    for (i=0, pix=pic, len=0; i<h; i++) {
      for (j=0, bit=0, k=0; j<w; j++, pix++) {
	if (raw) {
	  k = (k << 1) | *pix;
	  bit++;
	  if (bit==8) {
	    fputc(~k,fp);
	    bit = k = 0;
	  }
	}
	else {
	  if (*pix) fprintf(fp,"0 ");
	       else fprintf(fp,"1 ");
	  len+=2;
	  if (len>68) { fprintf(fp,"\n"); len=0; }
	}
      } /* j */
      if (raw && bit) {
	k = k << (8-bit);
	fputc(~k,fp);
      }
    }
  }

  if (ferror(fp)) return -1;

  return 0;
}


	  
	  



\BARFOO\
else
  echo "will not over write ./xvpbm.c"
fi
if `test ! -s ./xvpm.c`
then
echo "writting ./xvpm.c"
cat > ./xvpm.c << '\BARFOO\'
/*
 * xvpm.c - load routine for 'pm' format pictures
 *
 * LoadPM(fname, numcols)  -  loads a PM pic, does 24to8 code if nec.
 * WritePM(fp, pic, w, h, r,g,b, numcols, style)
 * WriteRaw(fp, pic, w, h, r,g,b, numcols, style)
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"
#include "pm.h"

pmpic  thePic;

static int PMError();
static void flipl();

/*******************************************/
int LoadPM(fname,nc)
     char *fname;
     int   nc;
/*******************************************/
{
  FILE  *fp;
  int    isize,i,flipit,w,h,rv;

  rv = 0;
  thePic.pm_image = NULL;

  /* read in the PM picture */
  fp=fopen(fname,"r");
  if (!fp) return( PMError("unable to open file") );
  
  flipit = 0;
  fread(&thePic,PM_IOHDR_SIZE,1,fp);
  if (thePic.pm_id != PM_MAGICNO) {
    flipl( (byte *) &thePic.pm_id);
    if (thePic.pm_id == PM_MAGICNO) flipit = 1;
    else flipl( (byte *) &thePic.pm_id);
  }
  if (thePic.pm_id != PM_MAGICNO) return( PMError("not a PM file") );

  if (flipit) {
    flipl((byte *) &thePic.pm_np);      flipl((byte *) &thePic.pm_nrow);
    flipl((byte *) &thePic.pm_ncol);    flipl((byte *) &thePic.pm_nband);
    flipl((byte *) &thePic.pm_form);    flipl((byte *) &thePic.pm_cmtsize);
    }
          
  /* make sure that the input picture can be dealt with */
  if ( thePic.pm_nband!=1 || 
      (thePic.pm_form!=PM_I && thePic.pm_form!=PM_C) ||
      (thePic.pm_form==PM_I && thePic.pm_np>1) ||
      (thePic.pm_form==PM_C && (thePic.pm_np==2 || thePic.pm_np>4)) ) {
    fprintf(stderr,"PM picture not in a displayable format.\n");
    fprintf(stderr,"(ie, 1-plane PM_I, or 1-, 3-, or 4-plane PM_C)\n");
    return 1;
    }	

  w = thePic.pm_ncol;  h = thePic.pm_nrow;

  isize = pm_isize(&thePic);

  if (DEBUG) 
    fprintf(stderr,"%s: LoadPM() - loading a %dx%d %s pic, %d planes\n",
	    cmd, w, h, (thePic.pm_form==PM_I) ? "PM_I" : "PM_C", 
	    thePic.pm_np);

  SetISTR(ISTR_FORMAT,"PM, %s.  (%d plane %s)  (%d bytes)",
	  (thePic.pm_form==PM_I || thePic.pm_np>1) ? 
	     "24-bit color" : "8-bit greyscale",
	  thePic.pm_np, (thePic.pm_form==PM_I) ? "PM_I" : "PM_C",
	  isize + PM_IOHDR_SIZE + thePic.pm_cmtsize);

  /* allocate memory for picture and read it in */
  thePic.pm_image = (char *) malloc(isize);
  if (thePic.pm_image == NULL) 
    return( PMError("unable to malloc PM picture") );

  if (fread(thePic.pm_image, (unsigned) isize, 1, fp) != 1) 
    return( PMError("file read error") );
  if (fp!=stdin) fclose(fp);

  if (DEBUG) fprintf(stderr,"loadpm 1\n");

  /* convert PM picture to 'pic' (8 bit) format */
  if (thePic.pm_form == PM_I) {
    int  *intptr;
    byte *pic24, *picptr;

    if ((pic24 = (byte *) malloc(w*h*3))==NULL) 
      return( PMError("unable to malloc 24-bit picture") );
      
    intptr = (int *) thePic.pm_image;
    picptr = pic24;

    if (flipit) {    /* if flipit, integer is RRGGBBAA instead of AABBGGRR */
      for (i=w*h; i>0; i--, intptr++) {
	*picptr++ = (*intptr>>24) & 0xff;
	*picptr++ = (*intptr>>16) & 0xff;
	*picptr++ = (*intptr>>8)  & 0xff;
      }
    }
    else {
      for (i=w*h; i>0; i--, intptr++) {
	*picptr++ = (*intptr)     & 0xff;
	*picptr++ = (*intptr>>8)  & 0xff;
	*picptr++ = (*intptr>>16) & 0xff;
      }
    }

    if (DEBUG) fprintf(stderr,"loadpm 2\n");

    free(thePic.pm_image);
    rv=Conv24to8(pic24,w,h,nc);
    free(pic24);
  }


  else if (thePic.pm_form == PM_C && thePic.pm_np>1) {
    byte *pic24, *picptr, *rptr, *gptr, *bptr;

    if ((pic24 = (byte *) malloc(w*h*3))==NULL) 
      return( PMError("unable to malloc 24-bit picture") );

    rptr = (byte *) thePic.pm_image;
    gptr = rptr + w*h;
    bptr = rptr + w*h*2;
    picptr = pic24;
    for (i=w*h; i>0; i--) {
      *picptr++ = *rptr++;
      *picptr++ = *gptr++;
      *picptr++ = *bptr++;
    }
    free(thePic.pm_image);
    rv=Conv24to8(pic24,w,h,nc);
    free(pic24);
  }
  
  else if (thePic.pm_form == PM_C && thePic.pm_np==1) {
    /* don't have to convert, just point pic at thePic.pm_image */
    pic = (byte *) thePic.pm_image;
    pWIDE = w;  pHIGH = h;  
    for (i=0; i<256; i++) r[i]=g[i]=b[i]=i;  /* and build mono colortable */
    rv = 0;
  }

  return rv;
}


/*******************************************/
int WritePM(fp, pic, w, h, rmap, gmap, bmap, numcols, colorstyle)
FILE *fp;
byte *pic;
int   w,h;
byte *rmap, *gmap, *bmap;
int   numcols, colorstyle;
{
  /* writes a PM file to the already open stream
     'colorstyle' single-handedly determines the type of PM pic written
     if colorstyle==0, (Full Color) a 3-plane PM_C pic is written
     if colorstyle==1, (Greyscal) a 1-plane PM_C pic is written
     if colorstyle==0, (B/W stipple) a 1-plane PM_C pic is written */

  char  foo[256];
  int   i;
  byte *p;

  /* create 'comment' field */
  sprintf(foo,"created by 'xv %s'\n", namelist[curname]);

  /* fill in fields of a pmheader */
  thePic.pm_id = PM_MAGICNO;
  thePic.pm_np = (colorstyle==0) ? 3 : 1;
  thePic.pm_ncol = w;
  thePic.pm_nrow = h;
  thePic.pm_nband = 1;
  thePic.pm_form  = PM_C;
  thePic.pm_cmtsize = strlen(foo);

  if (fwrite(&thePic, PM_IOHDR_SIZE, 1, fp) != 1) return -1;

  /* write the picture data */
  if (colorstyle == 0) {         /* 24bit RGB, organized as 3 8bit planes */
    for (i=0,p=pic; i<w*h; i++, p++)
      putc(rmap[*p], fp);
    for (i=0,p=pic; i<w*h; i++, p++)
      putc(gmap[*p], fp);
    for (i=0,p=pic; i<w*h; i++, p++)
      putc(bmap[*p], fp);
  }

  else if (colorstyle == 1) {    /* GreyScale: 8 bits per pixel */
    byte rgb[256];
    for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
    for (i=0, p=pic; i<w*h; i++, p++)
      putc(rgb[*p],fp);
  }

  else /* (colorstyle == 2) */ { /* B/W stipple.  pic is 1's and 0's */
    for (i=0, p=pic; i<w*h; i++, p++)
      putc(*p ? 255 : 0,fp);
  }

  if (fputs(foo,fp)==EOF) return -1;

  return 0;
}


/*****************************/
static int PMError(st)
char *st;
{
  SetISTR(ISTR_WARNING,"LoadPM() - %s",cmd,st);
  Warning();
  if (thePic.pm_image != NULL) free(thePic.pm_image);
  return -1;
}


/*****************************/
static void flipl(p)
     byte *p;
{
  byte t; 
  t = p[0];  p[0]=p[3];  p[3] = t;
  t = p[1];  p[1]=p[2];  p[2] = t;
}



\BARFOO\
else
  echo "will not over write ./xvpm.c"
fi
if `test ! -s ./xvscrl.c`
then
echo "writting ./xvscrl.c"
cat > ./xvscrl.c << '\BARFOO\'
/* 
 * xvscrl.c - Scroll Bar handling functions
 *
 * callable functions:
 *
 *   SCCreate()   -  creates the Scroll Bar window.
 *   SCSetRange() -  sets min/max/current values of control
 *   SCSetVal()   -  sets value of control 
 *   SCRedraw()   -  redraws scroll bar
 *   SCTrack()    -  called when clicked.  Operates control 'til mouseup
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"
#include "bitmaps.h"


static Pixmap upPix,  downPix;   /* up/down arrows */
static Pixmap up1Pix, down1Pix;  /* up/down arrows (lit up) */
static Pixmap sgray;             /* gray stipple for lit scrollbar */
static int    pixmaps_built=0;   /* true if pixmaps created already */


/* scroll regions */
#define UPLINE 0
#define UPPAGE 1
#define DNLINE 2
#define DNPAGE 3
#define THUMB  4

#define SCRLWAIT 150   /* milliseconds to wait between scrolls */

/* local functions */
#ifdef __STDC__
static int  whereInScrl(SCRL *, int, int);
static void drawArrow(SCRL *, int);
#else
static int  whereInScrl();
static void drawArrow();
#endif


/***************************************************/
void SCCreate(sp, parent, x, y, vert, len, minv, maxv, curv, page, 
	          fg, bg, func)
SCRL         *sp;
Window        parent;
int           x,y,vert,len,minv,maxv,curv,page;
unsigned long fg,bg;
void          (*func)();
{


  if (!pixmaps_built) {
    upPix    = XCreatePixmapFromBitmapData(theDisp, parent, 
		up_bits, up_width, up_height, fg, bg, dispDEEP);
    downPix  = XCreatePixmapFromBitmapData(theDisp, parent, 
	        down_bits, down_width, down_height, fg, bg, dispDEEP);
    up1Pix   = XCreatePixmapFromBitmapData(theDisp, parent, 
                up1_bits, up1_width, up1_height, fg, bg, dispDEEP);
    down1Pix = XCreatePixmapFromBitmapData(theDisp, parent, 
	        down1_bits, down1_width, down1_height,fg,bg,dispDEEP);
    sgray    = XCreatePixmapFromBitmapData(theDisp, parent,
	        scrlgray_bits, scrlgray_width, scrlgray_height,fg,bg,dispDEEP);
  }

  sp->vert = vert;
  sp->len  = len;
  sp->fg   = fg;
  sp->bg   = bg;
  sp->uplit = sp->dnlit = 0;

  if (vert) 
    sp->win = XCreateSimpleWindow(theDisp, parent,x,y,up_width-2,len,1,fg,bg);
  else FatalError("don't know HOW to make horizontal scrollbar");

  if (!sp->win) FatalError("can't create scrollbar window");

  sp->tsize  =  up_width-2;      /* really only if vertical */
  sp->tmin   =  up_height-1;
  sp->tmax   =  len - (up_height-1) - sp->tsize;
  sp->drawobj = func;

  SCSetRange(sp, minv, maxv, curv, page);
  XSelectInput(theDisp, sp->win, ExposureMask | ButtonPressMask);
}


/***************************************************/
void SCSetRange(sp, minv, maxv, curv, page)
SCRL *sp;
int   minv, maxv, curv, page;
{
  if (maxv<minv) maxv=minv;
  sp->min = minv;    sp->max = maxv;    sp->page = page;
  sp->active =  (minv < maxv);

  /* adjust scroll bar background */
  if (sp->active) XSetWindowBackgroundPixmap(theDisp, sp->win, sgray);
             else XSetWindowBackground(theDisp, sp->win, sp->bg);

  SCSetVal(sp, curv);
}


/***************************************************/
void SCSetVal(sp, curv)
SCRL *sp;
int   curv;
{
  RANGE(curv, sp->min, sp->max);   /* make sure curv is in-range */
  sp->val = curv;

  if (sp->active) 
    sp->tpos = sp->tmin + ((sp->tmax - sp->tmin)*(curv - sp->min))
                        / (sp->max - sp->min);
  SCRedraw(sp);
  (sp->drawobj)();     /* redraw whatever the scrollbar controls */
  XFlush(theDisp);
}


/***************************************************/
void SCRedraw(sp)
SCRL *sp;
{
  XSetForeground(theDisp, theGC, sp->fg);
  XSetBackground(theDisp, theGC, sp->bg);

  XClearWindow(theDisp, sp->win);
  
  if (sp->vert) {    /* draw up/down arrows */
    drawArrow(sp,UPLINE);
    drawArrow(sp,DNLINE);

    if (sp->active) {   /* a thumb is necessary */
      XSetForeground(theDisp, theGC, sp->bg);
      XFillRectangle(theDisp, sp->win, theGC,
		     1, sp->tpos+1, sp->tsize-2, sp->tsize-2);
      XSetForeground(theDisp, theGC, sp->fg);
      XDrawRectangle(theDisp, sp->win, theGC,
		     0, sp->tpos, sp->tsize-1, sp->tsize-1);
    }
  }
}



/***************************************************/
static int whereInScrl(sp,x,y)
SCRL *sp;
int x,y;
{
  int v;

  /* returns region # that x,y is in.  Returns '-1' if none */

  v=0;
  if (sp->vert) {
    if (x<0 || x>up_width-2 || y<0 || y>sp->len) return -1;
    v = y;
  }

  /* once we know it's in scroll bar, only have to check 'v' versus len */
  if (v < sp->tmin)               return UPLINE;
  if (sp->active) {
    if (v <  sp->tpos)             return UPPAGE;
    if (v <  sp->tpos + sp->tsize) return THUMB;
    if (v <= sp->tmax + sp->tsize) return DNPAGE;
  }
  if (v > sp->tmax+sp->tsize)    return DNLINE;

  return -1;
}


/***************************************************/
static void drawArrow(sp,arr)
SCRL *sp;
int arr;
{
  /* only if vertical */
  if (arr == UPLINE) {
    if (sp->uplit) 
      XCopyArea(theDisp, up1Pix,  sp->win,theGC,0,0,up_width,up_height,-1,-1);
    else
      XCopyArea(theDisp, upPix,   sp->win,theGC,0,0,up_width,up_height,-1,-1);
  }

  else if (arr == DNLINE) {
    if (sp->dnlit) 
      XCopyArea(theDisp, down1Pix,sp->win,theGC,0,0,up_width,up_height,
		-1, sp->len-(up_height-1));
    else
      XCopyArea(theDisp, downPix, sp->win,theGC,0,0,up_width,up_height,
		-1, sp->len-(up_height-1));
  }

  XFlush(theDisp);
}


/***************************************************/
void SCTrack(sp,mx,my)
SCRL *sp;
int mx,my;
{
  Window       rW,cW;
  int          rx,ry, x,y, ipos, pos, lit, ty, tyoff, ty1;
  unsigned int mask;

  /* determine in which of the five regions of the scroll bar the mouse
     was clicked (upline, downline, uppage, downpage, thumb) */

  ty = tyoff = 0;

  XSetForeground(theDisp, theGC, sp->fg);
  XSetBackground(theDisp, theGC, sp->bg);

  /* light up appropriate bit of scroll bar */
  ipos = whereInScrl(sp,mx,my);
  lit = 1;

  switch (ipos) {
  case UPLINE:  sp->uplit = 1;
                if (sp->val > sp->min) SCSetVal(sp,sp->val-1);                
                Timer(SCRLWAIT);
                break;

  case DNLINE:  sp->dnlit = 1;
                if (sp->val < sp->max) SCSetVal(sp,sp->val+1);
                Timer(SCRLWAIT);
                break;

  case UPPAGE:  SCSetVal(sp,sp->val - sp->page);  break;
  case DNPAGE:  SCSetVal(sp,sp->val + sp->page);  break;
  case THUMB:   tyoff = sp->tpos - my;
                ty = sp->tpos;
                XSetState(theDisp, theGC, sp->fg, sp->bg, GXinvert, 
			  sp->fg ^ sp->bg);
                XDrawRectangle(theDisp,sp->win,theGC,
			       0, sp->tpos, sp->tsize-1, sp->tsize-1);
                break;
  }

  /* VERTICAL CODE ONLY */
  while (XQueryPointer(theDisp,sp->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
    if (!(mask & Button1Mask)) break;    /* button released */

    switch (ipos) {

    case THUMB:
      /* do thumb tracking */
      if (x<-16 || x>16+sp->tsize) {   /* outside tracking range */
	if (lit) {
	  lit = 0;
	  XDrawRectangle(theDisp,sp->win,theGC,0,ty,sp->tsize-1,sp->tsize-1);
	}
      }

      else {                           /* inside tracking range */
	if (!lit) {  /* not lit, just turn on */
	  lit = 1;
	  ty = y + tyoff;
	  RANGE(ty, sp->tmin, sp->tmax);
	  XDrawRectangle(theDisp,sp->win,theGC,0,ty,sp->tsize-1,sp->tsize-1);
	}
	else { /* already lit, more the thumb */
	  ty1 = y+tyoff;
	  RANGE(ty1, sp->tmin, sp->tmax);
	  if (ty != ty1) {    /* but only if mouse has moved */
	    XDrawRectangle(theDisp, sp->win, theGC, 
			   0,ty,sp->tsize-1,sp->tsize-1);
	    ty = ty1;
	    XDrawRectangle(theDisp, sp->win, theGC, 
			   0,ty,sp->tsize-1,sp->tsize-1);
	  }
	}
      }
      break;


    case UPLINE:
    case DNLINE:                     /* arrows */
      pos = whereInScrl(sp,x,y);
      if (pos == ipos) {
	if (!lit) { 
	  lit = 1; 
	  if (ipos == UPLINE) { sp->uplit = 1;  drawArrow(sp,UPLINE); }
	                 else { sp->dnlit = 1;  drawArrow(sp,DNLINE); }
	}

	else {
	  if (sp->val > sp->min && pos==UPLINE) {
	    SCSetVal(sp, sp->val-1);
	    Timer(SCRLWAIT);
	  }
	  else if (sp->val < sp->max && pos==DNLINE) {
	    SCSetVal(sp, sp->val+1);
	    Timer(SCRLWAIT);
	  }
	}
      }
      
      else {
	if (lit) { 
	  lit = 0; 
	  if (ipos == UPLINE) { sp->uplit = 0;  drawArrow(sp,UPLINE); }
	                 else { sp->dnlit = 0;  drawArrow(sp,DNLINE); }
	}
      }
      break;
      
    }
  }


  if (ipos == THUMB) {
    if (lit)    /* turn off */
      XDrawRectangle(theDisp,sp->win,theGC,0,ty,sp->tsize-1,sp->tsize-1);

    XSetState(theDisp, theGC, sp->fg, sp->bg, GXcopy, AllPlanes);

    if (lit && ty != sp->tpos) {    /* if thumb was moved, ROUND to new val */
      int dt, dv;
      dt = sp->tmax - sp->tmin;
      dv = sp->max  - sp->min;
      SCSetVal(sp, sp->min + (dv*(ty - sp->tmin)+dt/2) / dt);
    }
  }

  if (lit && ipos == UPLINE) { sp->uplit = 0; drawArrow(sp, UPLINE); }
  if (lit && ipos == DNLINE) { sp->dnlit = 0; drawArrow(sp, DNLINE); }
}




\BARFOO\
else
  echo "will not over write ./xvscrl.c"
fi
if `test ! -s ./xvxbm.c`
then
echo "writting ./xvxbm.c"
cat > ./xvxbm.c << '\BARFOO\'
/*
 * xvxbm.c - load routine for X11 Bitmap format pictures
 *
 * LoadXBM(fname)  -  loads an X11 Bitmap file\
 * WriteXBM(fp, pic, w, h)
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"



/*
 * File Format:
 *   (format identifier:  "#define" as first couple chars in file)
 *
 * looks for first line beginning with '#define'
 *   reads "#define identifier width"  (identifier is ignored)
 * looks for next line beginning with '#define'
 *   reads "#define identifier height" (identifier is ignored)
 * looks for next occurence of characters '0x'
 *   read next two chars as two hex digits
 *   move forward to next occurence of '0x'
 *   repeat
 */
 

static int XBMError();


/*******************************************/
int LoadXBM(fname,nc)
     char *fname;
     int   nc;
/*******************************************/
{
  FILE  *fp;
  int    c, c1;
  int    i, j, k, bit, w, h;
  byte  *pix;
  long   filesize;
  char   line[256];
  byte   hex[256];

  k = 0;

  fp=fopen(fname,"r");
  if (!fp) return 1;

  /* figure out the file size (for Informational Purposes Only) */
  fseek(fp, 0L, 2);
  filesize = ftell(fp);
  fseek(fp, 0L, 0);


  /* read width:  skip lines until we hit a #define */
  while (1) {
    if (!fgets(line,256,fp)) 
      return(XBMError("EOF reached in header info."));

    if (strncmp(line,"#define",7)==0) {
      if (sscanf(line,"#define %*s %d", &w) != 1) 
	return(XBMError("Unable to read 'width'"));
      else break;
    }
  }


  /* read height:  skip lines until we hit another #define */
  while (1) {
    if (!fgets(line,256,fp)) 
      return(XBMError("EOF reached in header info."));

    if (strncmp(line,"#define",7)==0) {
      if (sscanf(line,"#define %*s %d", &h) != 1) 
	return(XBMError("Unable to read 'height'"));
      else break;
    }
  }



  /* scan forward until we see the first '0x' */
  c = getc(fp);  c1 = getc(fp);
  while (c1!=EOF && !(c=='0' && c1=='x') ) { c = c1;  c1 = getc(fp); }

  if (c1==EOF) 
    return(XBMError("No bitmap data found"));


  /* load up the stuff XV expects us to load up */

  SetISTR(ISTR_FORMAT,"X11 Bitmap  (%ld bytes)", filesize);

  pic = (byte *) calloc(w*h,1);
  if (!pic) FatalError("couldn't malloc 'pic'");

  pWIDE = w;  pHIGH = h;

  /* B/W bitmaps have a two entry colormap */
  r[0] = g[0] = b[0] = 255;     /* 0 = white */
  r[1] = g[1] = b[1] = 0;       /* 1 = black */


  /* initialize the 'hex' array for zippy ASCII-hex -> int conversion */

  for (i=0; i<256; i++) hex[i]=0;
  for (i='0'; i<='9'; i++) hex[i] = i - '0';
  for (i='a'; i<='f'; i++) hex[i] = i + 10 - 'a';
  for (i='A'; i<='F'; i++) hex[i] = i + 10 - 'A';

  /* read/convert the image data */

  for (i=0, pix=pic; i<h; i++)
    for (j=0,bit=0; j<w; j++, pix++, bit = ++bit&7) {

      if (!bit) {
	/* get next byte from file.  we're already positioned at it */
	c = getc(fp);  c1 = getc(fp);
	if (c<0 || c1<0) { 
	  /* EOF: break out of loop */	  
	  c=c1='0'; i=h; j=w;
	  XBMError("The file would appear to be truncated.");
	}

	k = (hex[c] << 4) + hex[c1];

	/* advance to next '0x' */
	c = getc(fp);  c1 = getc(fp);
	while (c1!=EOF && !(c=='0' && c1=='x') ) { c = c1;  c1 = getc(fp); }
      }

      *pix = (k&1) ? 1 : 0;
      k = k >> 1;
    }

  fclose(fp);

  return 0;
}  



/*******************************************/
static int XBMError(st)
char *st;
{
  SetISTR(ISTR_WARNING,st);
  return 1;
}


/*******************************************/
int WriteXBM(fp, pic, w, h, fname)
FILE *fp;
byte *pic;
int   w,h;
char *fname;
{
  /* pic is expected to be an array of w*h bytes.  '0' is considered 'black'
     non-zero is considered white.  Some sort of stippling algorithm should've
     been called already to produce pic, otherwise the output won't be at all
     useful */

  int   i,j,k,bit,len,nbytes;
  byte *pix;
  char name[256], *foo;

  /* figure out a reasonable basename */
  strcpy(name,fname);
  foo = strchr(name,'.');
  if (foo) *foo='\0';                 /* truncated name at first '.' */

  fprintf(fp,"#define %s_width %d\n",name,w);  
  fprintf(fp,"#define %s_height %d\n",name,h);
  fprintf(fp,"static char %s_bits[] = {\n",name);

  fprintf(fp," ");

  nbytes = h * ((w+7)/8);   /* # of bytes to write */

  for (i=0, len=1, pix=pic; i<h; i++) {
    for (j=bit=k=0; j<w; j++,pix++) {
      k = (k>>1);
      if (*pix) k |= 0x80;
      bit++;
      if (bit==8) {
	fprintf(fp,"0x%02x",(byte) ~k);
	nbytes--;  len += 4;
	if (nbytes) { fprintf(fp,",");  len++; }
	if (len>72) { fprintf(fp,"\n ");  len=1; }
	bit = k = 0;
      }
    }

    if (bit) {
      k = k >> (8-bit);
      fprintf(fp,"0x%02x",(byte) ~k);
      nbytes--;  len += 4;
      if (nbytes) { fprintf(fp,",");  len++; }
      if (len>72) { fprintf(fp,"\n ");  len=1; }
    }
  }

  fprintf(fp,"};\n");

  if (ferror(fp)) return -1;
  return 0;
}
\BARFOO\
else
  echo "will not over write ./xvxbm.c"
fi
echo "Finished archive 4 of 10"
exit

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.
--
dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.