home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-12-09 | 54.5 KB | 2,096 lines |
- Path: wuarchive!cs.utexas.edu!sun-barr!newstop!exodus!appserv!halibut.cis.upenn.edu
- From: bradley@halibut.cis.upenn.edu (John Bradley)
- Newsgroups: comp.sources.x
- Subject: v10i084: xv - display and manipulate images, Part06/10
- Message-ID: <322@appserv.Eng.Sun.COM>
- Date: 27 Nov 90 20:08:27 GMT
- References: <csx-10i079:xv@uunet.UU.NET>
- Sender: news@exodus.Eng.Sun.COM
- Lines: 2079
- Approved: argv@sun.com
-
- Submitted-by: bradley@halibut.cis.upenn.edu (John Bradley)
- Posting-number: Volume 10, Issue 84
- Archive-name: xv/part06
-
- #!/bin/sh
- # to extract, remove the header and type "sh filename"
- if `test ! -s ./xvfish.c`
- then
- echo "writting ./xvfish.c"
- cat > ./xvfish.c << '\BARFOO\'
- /*
- * xvfish.c - the required-by-law 'fish' portion of 'xv'
- *
- * StartFish();
- * StopFish();
- */
-
- /*
- * 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.
- */
-
-
- #define DELAY 200000L /* delay between fish increments, in microseconds */
- #define NEEDSTIME
-
- #include "xv.h"
-
- /* size of fish */
- #define fwide 32
- #define fhigh 16
-
-
- static char lfish_bits[] = {
- 0x00, 0xc0, 0x07, 0x00, 0x00, 0xb0, 0x06, 0x00, 0x80, 0x7f, 0x03, 0xe0,
- 0x60, 0x82, 0x03, 0xb0, 0x18, 0x00, 0x0c, 0x68, 0x64, 0x02, 0xf0, 0x37,
- 0x62, 0x00, 0x00, 0x28, 0x01, 0xaa, 0xaa, 0x36, 0x46, 0x00, 0x00, 0x28,
- 0x38, 0x03, 0xc0, 0x5f, 0xb0, 0x28, 0x30, 0xb0, 0xc0, 0x39, 0x0e, 0xe0,
- 0x00, 0xee, 0x01, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00,
- 0x00, 0xc0, 0x00, 0x00};
-
- static char rfish_bits[] = {
- 0x00, 0xe0, 0x03, 0x00, 0x00, 0x60, 0x0d, 0x00, 0x07, 0xc0, 0xfe, 0x01,
- 0x0d, 0xc0, 0x41, 0x06, 0x12, 0x30, 0x00, 0x18, 0xec, 0x0f, 0x40, 0x26,
- 0x14, 0x00, 0x00, 0x46, 0xac, 0xaa, 0x4a, 0x80, 0x14, 0x00, 0x00, 0x62,
- 0xfa, 0x03, 0xc0, 0x1c, 0x0d, 0x0c, 0x14, 0x0d, 0x07, 0x70, 0x9c, 0x03,
- 0x00, 0x80, 0x77, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x03, 0x00};
-
-
- typedef struct fishstr { short x,y,dx,dy; } FISH;
-
-
- #define MAXFISH 100
- FISH fishdat[MAXFISH];
-
- Pixmap lfishP, rfishP;
- int numfish=7;
- int w,h;
- static int firsttime=1;
-
-
- static void dofish(), setfishtimer();
-
-
- /**************/
- StartFish()
- /**************/
- {
- int i;
-
- if (!fish) return;
-
- #if defined(NOTIMER) || defined(USLEEP)
- /* MUST have 'setitimer()' for fish to work */
- return;
- #endif
-
- if (useroot || fishrunning || !mainW) return;
- w = eWIDE; h = eHIGH;
-
- if (firsttime) {
- lfishP=XCreateBitmapFromData(theDisp,mainW,lfish_bits,fwide,fhigh);
- rfishP=XCreateBitmapFromData(theDisp,mainW,rfish_bits,fwide,fhigh);
-
- for (i=0; i<numfish; i++) {
- fishdat[i].x = rand()%w;
- fishdat[i].y = rand()%h;
- fishdat[i].dx = (abs(rand()%3)+4);
-
- if (rand()&0x10) fishdat[i].dx = -fishdat[i].dx;
-
- fishdat[i].dy=rand()%7-3; if (fishdat[i].dy==0) fishdat[i].dy=1;
- }
- firsttime = 0;
- }
-
- fishrunning = 1;
- setfishtimer();
- }
-
-
- /**************/
- StopFish()
- /**************/
- {
- struct itimerval it;
- #ifdef POSIX
- struct sigaction act;
- #endif
-
- if (!fish) return;
- if (!fishrunning) return;
-
- #if defined(NOTIMER) || defined(USLEEP)
- /* MUST have setitimer() for fish to work */
- return;
- #endif
-
- #ifndef POSIX
- HOLD_SIG; /* block ALRM signal while we turn everything off */
- #endif
-
-
- bzero(&it, sizeof(it));
- it.it_interval.tv_usec = 0L;
- it.it_value.tv_usec = 0L;
-
- setitimer(ITIMER_REAL, &it, (struct itimerval *)0);
-
- #ifdef POSIX
- act.sa_handler=SIG_DFL;
- sigaction(SIGALRM,&act,NULL);
- #else
- signal(SIGALRM,SIG_DFL);
- RELEASE_SIG; /* allow ALRM signals to happen (we don't get them) */
- fishrunning = 0;
- #endif /* POSIX */
- }
-
-
-
- /*******************************/
- static void dofish()
- {
- int i;
- FISH *fp;
-
- XSetForeground(theDisp, theGC, infofg);
- XSetBackground(theDisp, theGC, infobg);
-
- for (i=0; i<numfish; i++) {
- fp = &fishdat[i];
- XClearArea(theDisp, mainW, fp->x, fp->y, fwide, fhigh, True);
-
- fp->x += fp->dx;
- fp->y += fp->dy;
- if (fp->x < -50) fp->dx = abs(fp->dx);
- if (fp->x > (w+50)) fp->dx = -abs(fp->dx);
-
- if (fp->y < 10) fp->dy = abs(fp->dy);
- if (fp->y > (h-20)) fp->dy = -abs(fp->dy);
-
- if (fp->dx<0)
- XCopyPlane(theDisp,lfishP,mainW,theGC,0,0,fwide,fhigh,fp->x,fp->y,1L);
- else
- XCopyPlane(theDisp,rfishP,mainW,theGC,0,0,fwide,fhigh,fp->x,fp->y,1L);
- }
-
- XFlush(theDisp);
- setfishtimer();
- }
-
-
-
-
- /*******/
- static void setfishtimer()
- /*******/
- {
- struct itimerval it;
- #ifdef POSIX
- struct sigaction act;
- #endif
-
- bzero(&it, sizeof(it));
- it.it_value.tv_usec = DELAY;
-
- #ifdef POSIX
- act.sa_handler=dofish;
- sigaction(SIGALRM,&act,NULL);
- #else
- signal(SIGALRM,dofish);
- RELEASE_SIG; /* enable ALRM signals */
- setitimer(ITIMER_REAL, &it, (struct itimerval *)0);
- #endif /* POSIX */
- }
-
-
-
-
-
-
- \BARFOO\
- else
- echo "will not over write ./xvfish.c"
- fi
- if `test ! -s ./xvgam.c`
- then
- echo "writting ./xvgam.c"
- cat > ./xvgam.c << '\BARFOO\'
- /*
- * xvgam.c - Gamma Correction box handling functions
- *
- * callable functions:
- *
- * CreateGam(geom) - creates the ctrlW window. Doesn't map it.
- * GamBox(vis) - random processing based on value of 'vis'
- * maps/unmaps window, etc.
- * RedrawGam(x,y,w,h) - called by 'expose' events
- * RedrawGraph(x,y,w,h) - called by 'expose' events
- * ClickGam(x,y) - called when B1 clicked in gamW
- * TrackGraph(x,y) - called when B1 clicked in graphW
- * GenerateGamma() - called to generate/error-check 'ghand'
- * GenerateFSGamma() - called to generate floyd steinberg correction
- * GammifyColors() - does gamma correction of r[],g[],b[] arrays
- * SetGPreset() - sets preset #n to supplied values
- */
-
- /*
- * 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"
-
- #define MAXUNDO 8
-
- #define BUTTW 80
- #define BUTTW2 100
- #define BUTTH 19
-
- #define LINESTR "Lines"
- #define CURVSTR "Spline"
- #define HSVSTR "HSV Mode"
- #define RGBSTR "RGB Mode"
-
-
- XPoint presets[4][NUMHANDS];
- XPoint undo[MAXUNDO][NUMHANDS];
- XPoint defgam[NUMHANDS];
- static int firsttime=1;
-
-
- #ifdef __STDC__
- static void DrawGVals(void);
- static void DoGamCommand(int);
- static void DoGammaApply(int);
- static void SaveUndoState(void);
- static void HSVgamma(void);
- static void spline(int *, int *, int, float *);
- #else
- static void DoGamCommand(), DoGammaApply(), HSVgamma(), spline();
- static void DrawGVals(), SaveUndoState();
- #endif
-
-
- /***************************************************/
- void CreateGam(geom)
- char *geom;
- {
- int i,ptop;
-
- gamW = CreateWindow("xv gamma", geom, GAMWIDE,GAMHIGH,infofg,infobg);
- if (!gamW) FatalError("can't create gamma window!");
-
- graphW = XCreateSimpleWindow(theDisp,gamW, 10,40, 256,256, 1, infofg,infobg);
- if (!graphW) FatalError("can't create graph window!");
- XSelectInput(theDisp, graphW, ExposureMask | ButtonPressMask);
-
- /* call CreateCtrl first to create grayTile */
- XSetWindowBackgroundPixmap(theDisp, gamW, grayTile);
-
- BTCreate(&gbut[G_BUP_BR], gamW, 276, 40,
- BUTTW, BUTTH, "Brighter", infofg, infobg);
- BTCreate(&gbut[G_BDN_BR], gamW, 276, 40 + BUTTH + 4,
- BUTTW, BUTTH, "Dimmer", infofg, infobg);
- BTCreate(&gbut[G_BUP_CN], gamW, 276, 40 + 2*BUTTH + 8 + 16,
- BUTTW, BUTTH, "Sharper", infofg, infobg);
- BTCreate(&gbut[G_BDN_CN], gamW, 276, 40 + 3*BUTTH+12 + 16,
- BUTTW, BUTTH, "Duller", infofg, infobg);
-
- BTCreate(&gbut[G_BHSVRGB], gamW, 276, 40 + 4*BUTTH+16+32,
- BUTTW, BUTTH, HSVSTR, infofg, infobg);
-
- BTCreate(&gbut[G_B1], gamW, 276, 40 + 5*BUTTH+20+48,
- 17, BUTTH, "1", infofg, infobg);
- BTCreate(&gbut[G_B2], gamW, 276 + ((BUTTW-17)*1)/3, 40 + 5*BUTTH+20+48,
- 17, BUTTH, "2", infofg, infobg);
- BTCreate(&gbut[G_B3], gamW, 276 + ((BUTTW-17)*2)/3, 40 + 5*BUTTH+20+48,
- 17, BUTTH, "3", infofg, infobg);
- BTCreate(&gbut[G_B4], gamW, 276 + ((BUTTW-17)*3/3), 40 + 5*BUTTH+20+48,
- 17, BUTTH, "4", infofg, infobg);
-
- BTCreate(&gbut[G_BSET], gamW, 276, 40 + 6*BUTTH+24+48,
- 38, BUTTH, "Set", infofg, infobg);
- gbut[G_BSET].toggle = 1;
-
- BTCreate(&gbut[G_BUNDO], gamW, 276 + 42, 40 + 6*BUTTH+24+48,
- 38, BUTTH, "Undo", infofg, infobg);
-
- ptop = GAMHIGH - (2*BUTTH + 3*8);
- BTCreate(&gbut[G_BAPPLY], gamW, 10, ptop+8, BUTTW2, BUTTH,
- "Apply", infofg, infobg);
- BTCreate(&gbut[G_BNOGAM], gamW, 10, ptop + BUTTH + 2*8, BUTTW2, BUTTH,
- "No Gamma", infofg, infobg);
-
- BTCreate(&gbut[G_BRESET], gamW, 10+(GAMWIDE-20-BUTTW2)/2, ptop+8,
- BUTTW2, BUTTH, "Linear", infofg, infobg);
- BTCreate(&gbut[G_BDEF], gamW, 10+(GAMWIDE-20-BUTTW2)/2, ptop + BUTTH + 2*8,
- BUTTW2, BUTTH, "Default", infofg, infobg);
-
- BTCreate(&gbut[G_BGTYPE], gamW, 10+(2*(GAMWIDE-20-BUTTW2))/2, ptop+8,
- BUTTW2, BUTTH, CURVSTR, infofg, infobg);
- BTCreate(&gbut[G_BCLOSE],gamW, 10+(2*(GAMWIDE-20-BUTTW2))/2, ptop+BUTTH+2*8,
- BUTTW2, BUTTH, "Close", infofg, infobg);
-
- XMapSubwindows(theDisp, gamW);
-
- /* fill up the undo stack */
- for (i=0; i<MAXUNDO; i++)
- memcpy(undo[i], ghand, sizeof(ghand));
- }
-
-
- /***************************************************/
- void GamBox(vis)
- int vis;
- {
- if (vis) XMapRaised(theDisp, gamW);
- else XUnmapWindow(theDisp, gamW);
-
- gamUp = vis;
- }
-
-
- /***************************************************/
- void RedrawGam(x,y,w,h)
- int x,y,w,h;
- {
- int i;
- XRectangle xr;
-
- xr.x = x; xr.y = y; xr.width = w; xr.height = h;
- XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
-
- XSetBackground(theDisp, theGC, infobg);
-
- XSetForeground(theDisp, theGC, infobg);
- XFillRectangle(theDisp,gamW, theGC, 10+1,10+1,256,19);
- XSetForeground(theDisp,theGC,infofg);
- XDrawRectangle(theDisp,gamW, theGC, 10,10,257,20);
- DrawGVals();
-
- for (i=0; i<G_NBUTTS; i++)
- BTRedraw(&gbut[i]);
-
- XSetClipMask(theDisp, theGC, None);
- }
-
-
- /***************************************************/
- static void DrawGVals()
- {
- int w;
- char foo[40];
-
- XSetForeground(theDisp, theGC, infofg);
- XSetBackground(theDisp, theGC, infobg);
-
- sprintf(foo,"%3d %3d %3d %3d %3d %3d", ghand[0].y, ghand[1].x,
- ghand[1].y, ghand[2].x, ghand[2].y, ghand[3].y);
-
- w = XTextWidth(monofinfo, foo, strlen(foo));
- XSetFont(theDisp, theGC, monofont);
- XDrawImageString(theDisp, gamW, theGC, 10 + (256-w)/2,
- 11+(20-(monofinfo->ascent+monofinfo->descent))/2
- + monofinfo->ascent, foo, strlen(foo));
- XSetFont(theDisp, theGC, mfont);
- }
-
- /***************************************************/
- void RedrawGraph(x,y,w,h)
- int x,y,w,h;
- {
- int i;
- XRectangle xr;
- XPoint pts[256], *pt;
-
- xr.x = x; xr.y = y; xr.width = w; xr.height = h;
- XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
-
- XSetForeground(theDisp, theGC, infofg);
- XSetBackground(theDisp, theGC, infobg);
-
- XClearArea(theDisp, graphW, x,y,w,h, False);
-
- for (i=0, pt=pts; i<256; i++,pt++) {
- pt->x = i; pt->y = 255-gamcr[i];
- }
- XDrawLines(theDisp, graphW, theGC, pts, 256, CoordModeOrigin);
-
- for (i=0; i<NUMHANDS; i++) {
- XSetForeground(theDisp, theGC, infobg);
- XFillRectangle(theDisp, graphW, theGC,
- ghand[i].x-2, 255-ghand[i].y-2,5,5);
- XSetForeground(theDisp,theGC,infofg);
- XDrawRectangle(theDisp, graphW, theGC,
- ghand[i].x-3, 255-ghand[i].y-3,6,6);
- XDrawPoint(theDisp, graphW, theGC, ghand[i].x, 255-ghand[i].y);
- }
-
- XSetClipMask(theDisp, theGC, None);
- }
-
-
- /***************************************************/
- void ClickGam(x,y)
- int x,y;
- {
- int i;
- BUTT *bp;
-
- for (i=0; i<G_NBUTTS; i++) {
- bp = &gbut[i];
- if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
- }
-
- /* if 'Set' is lit, and we didn't click 'set' or '1'..'4', turn it off */
- if (i!=G_BSET && i!=G_B1 && i!=G_B2 && i!=G_B3 && i!=G_B4
- && gbut[G_BSET].lit)
- { gbut[G_BSET].lit = 0; BTRedraw(&gbut[G_BSET]); }
-
- if (i==G_NBUTTS) return; /* didn't find one */
-
- if (BTTrack(bp)) DoGamCommand(i);
- }
-
-
-
- /**********************************************/
- void TrackGraph(mx,my)
- int mx,my;
- {
- /* called when we've gotten a click inside graph window */
-
- Window rW, cW;
- int x, y, rx, ry;
- unsigned int mask;
- int h, vertonly, offx, offy;
-
- if (gbut[G_BSET].lit)
- { gbut[G_BSET].lit = 0; BTRedraw(&gbut[G_BSET]); }
-
- my = 255 - my; /* flip y axis */
-
- /* see if x,y is within any of the handles */
- for (h=0; h<NUMHANDS; h++) {
- if (PTINRECT(mx, my, ghand[h].x-5, ghand[h].y-5, 11,11)) break;
- }
- if (h==NUMHANDS) return; /* didn't find one */
-
- offx = ghand[h].x - mx; offy = ghand[h].y - my;
-
- vertonly = (h==0 || h==(NUMHANDS-1));
-
- SaveUndoState();
-
- while (XQueryPointer(theDisp,graphW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
- if (!(mask & Button1Mask)) break; /* button released */
- y = 255 - y; /* flip y-axis */
-
- /* keep this handle between other handles (x-axis) if nec. */
- if (!vertonly) {
- if (x+offx <= ghand[h-1].x) x = (ghand[h-1].x+1)-offx;
- if (x+offx >= ghand[h+1].x) x = (ghand[h+1].x-1)-offx;
- }
- else x = mx; /* if vert only, ignore sidewards motion */
-
- if (mx != x || my != y) { /* this handle has moved... */
- ghand[h].x = x+offx; ghand[h].y = y+offy;
- RANGE(ghand[h].y,0,255);
- GenerateGamma();
- RedrawGraph(0,0,256,256); /* open to better ideas... */
- }
- mx = x; my = y;
- }
-
- if ((rwcolor && rwthistime)) DoGammaApply(1);
- }
-
-
- /*********************/
- void GenerateGamma()
- {
- /* this function generates a gamma correction curve (gamcr)
-
- This function generates a 4 point spline curve to be used as a
- non-linear grey 'colormap'. Two of the points are nailed down at 0,0
- and 255,255, and can't be changed. You specify the other two. If
- you specify points on the line (0,0 - 255,255), you'll get the normal
- linear reponse curve. If you specify points of 50,0 and 200,255, you'll
- get grey values of 0-50 to map to black (0), and grey values of 200-255
- to map to white (255) (roughly). Values between 50 and 200 will cover
- the output range 0-255. The reponse curve will be slightly 's' shaped. */
-
- int i,j,k;
- static int x[NUMHANDS], y[NUMHANDS];
- float yf[NUMHANDS];
- static float splint();
-
- /* do some idiot-proofing (x-coords must be monotonically increasing) */
-
- for (i=0; i<4; i++) {
- RANGE(ghand[i].x, 0, 255);
- RANGE(ghand[i].y, 0, 255);
- }
-
- ghand[0].x = 0; ghand[3].x = 255;
- if (ghand[1].x < 1) ghand[1].x = 1;
- if (ghand[1].x >253) ghand[1].x = 253;
- if (ghand[2].x < ghand[1].x) ghand[2].x = ghand[1].x + 1;
- if (ghand[2].x >254) ghand[2].x = 254;
-
- if (firsttime) { /* if this is the first 'generate' save as 'default' */
- memcpy(defgam, ghand, sizeof(ghand));
- firsttime=0;
- }
-
- DrawGVals();
-
- if (!strcmp(gbut[G_BGTYPE].str,LINESTR)) {
- /* do linear interpolation */
- for (i=0; i<NUMHANDS-1; i++) {
- for (j=ghand[i].x,k=0; j<=ghand[i+1].x; j++,k++) {
- gamcr[j] = ghand[i].y + (k * (ghand[i+1].y - ghand[i].y)) /
- (ghand[i+1].x - ghand[i].x);
- }
- }
- return;
- }
-
-
-
- for (i=0; i<NUMHANDS; i++) { x[i] = ghand[i].x; y[i] = ghand[i].y; }
- spline(x, y, NUMHANDS, yf);
-
- for (i=0; i<256; i++) {
- j = (int) splint(x, y, yf, NUMHANDS, (float) i);
- if (j<0) j=0;
- else if (j>255) j=255;
- gamcr[i] = j;
- }
- }
-
-
- /*********************/
- void GenerateFSGamma()
- {
- /* this function generates the Floyd-Steinberg gamma curve (fsgamcr)
-
- This function generates a 4 point spline curve to be used as a
- non-linear grey 'colormap'. Two of the points are nailed down at 0,0
- and 255,255, and can't be changed. You specify the other two. If
- you specify points on the line (0,0 - 255,255), you'll get the normal
- linear reponse curve. If you specify points of 50,0 and 200,255, you'll
- get grey values of 0-50 to map to black (0), and grey values of 200-255
- to map to white (255) (roughly). Values between 50 and 200 will cover
- the output range 0-255. The reponse curve will be slightly 's' shaped. */
-
- int i,j;
- static int x[4] = {0,32,224,255};
- static int y[4] = {0, 0,255,255};
- float yf[4];
- static float splint();
-
- spline(x, y, 4, yf);
-
- for (i=0; i<256; i++) {
- j = (int) splint(x, y, yf, 4, (float) i);
- if (j<0) j=0;
- else if (j>255) j=255;
- fsgamcr[i] = j;
- }
- }
-
-
- /*********************/
- static void spline(x,y,n,y2)
- int *x, *y, n;
- float *y2;
- {
- /* given arrays of data points x[0..n-1] and y[0..n-1], computes the
- values of the second derivative at each of the data points
- y2[0..n-1] for use in the splint function */
-
- int i,k;
- float p,qn,sig,un,u[NUMHANDS];
-
- y2[0] = u[0] = 0.0;
-
- for (i=1; i<n-1; i++) {
- sig = ((float) x[i]-x[i-1]) / ((float) x[i+1] - x[i-1]);
- p = sig * y2[i-1] + 2.0;
- y2[i] = (sig-1.0) / p;
- u[i] = (((float) y[i+1]-y[i]) / (x[i+1]-x[i])) -
- (((float) y[i]-y[i-1]) / (x[i]-x[i-1]));
- u[i] = (6.0 * u[i]/(x[i+1]-x[i-1]) - sig*u[i-1]) / p;
- }
- qn = un = 0.0;
-
- y2[n-1] = (un-qn*u[n-2]) / (qn*y2[n-2]+1.0);
- for (k=n-2; k>=0; k--)
- y2[k] = y2[k]*y2[k+1]+u[k];
- }
-
-
-
- /*********************/
- static float splint(xa,ya,y2a,n,x)
- float y2a[],x;
- int n,xa[],ya[];
- {
- int klo,khi,k;
- float h,b,a;
-
- klo = 0;
- khi = n-1;
- while (khi-klo > 1) {
- k = (khi+klo) >> 1;
- if (xa[k] > x) khi = k;
- else klo = k;
- }
- h = xa[khi] - xa[klo];
- if (h==0.0) FatalError("bad xvalues in splint\n");
- a = (xa[khi]-x)/h;
- b = (x-xa[klo])/h;
- return (a*ya[klo] + b*ya[khi] + ((a*a*a-a)*y2a[klo] +(b*b*b-b)*y2a[khi])
- * (h*h) / 6.0);
- }
-
-
- /*********************/
- static void DoGamCommand(cmd)
- int cmd;
- {
- int i,p, app;
-
- app = 1; p=0;
-
- switch (cmd) {
- case G_BAPPLY: DoGammaApply(1); app = 0; break;
- case G_BNOGAM: DoGammaApply(0); app = 0; break;
-
- case G_BRESET: SaveUndoState();
- ghand[0].x = 0; ghand[0].y = 0;
- ghand[1].x = 64; ghand[1].y = 64;
- ghand[2].x = 192; ghand[2].y = 192;
- ghand[3].x = 255; ghand[3].y = 255;
-
- GenerateGamma();
- RedrawGraph(0,0,256,256);
- break;
-
-
-
- case G_BDEF: SaveUndoState();
- memcpy(ghand, defgam, sizeof(ghand));
-
- GenerateGamma();
- RedrawGraph(0,0,256,256);
- break;
-
- case G_BGTYPE: if (!strcmp(gbut[G_BGTYPE].str, LINESTR))
- gbut[G_BGTYPE].str = CURVSTR;
- else gbut[G_BGTYPE].str = LINESTR;
- BTRedraw(&gbut[G_BGTYPE]);
- GenerateGamma();
- RedrawGraph(0,0,256,256);
- break;
-
- case G_BCLOSE: GamBox(0); app=0; break;
-
- case G_BUP_BR: SaveUndoState();
- for (i=0; i<NUMHANDS; i++) {
- ghand[i].y += 10;
- RANGE(ghand[i].y,0,255);
- }
-
- GenerateGamma();
- RedrawGraph(0,0,256,256);
- break;
-
- case G_BDN_BR: SaveUndoState();
- for (i=0; i<NUMHANDS; i++) {
- ghand[i].y -= 10;
- RANGE(ghand[i].y,0,255);
- }
-
- GenerateGamma();
- RedrawGraph(0,0,256,256);
- break;
-
- case G_BUP_CN: SaveUndoState();
- ghand[0].y -= 10;
- ghand[1].y -= 10; ghand[1].x += 5;
- ghand[2].y += 10; ghand[2].x -= 5;
- ghand[3].y += 10;
- if (ghand[1].x > 127) ghand[1].x = 127;
- if (ghand[2].x <= ghand[1].x) ghand[2].x = ghand[1].x+1;
- for (i=0; i<NUMHANDS; i++) RANGE(ghand[i].y,0,255);
-
- GenerateGamma();
- RedrawGraph(0,0,256,256);
- break;
-
- case G_BDN_CN: SaveUndoState();
- if (abs(ghand[0].y - 127) < 10) ghand[0].y = 127;
- else ghand[0].y += ((ghand[0].y>127) ? -10 : 10);
-
- if (abs(ghand[1].y - 127) < 10) ghand[1].y = 127;
- else ghand[1].y += ((ghand[1].y>127) ? -10 : 10);
-
- if (abs(ghand[2].y - 127) < 10) ghand[2].y = 127;
- else ghand[2].y += ((ghand[2].y>127) ? -10 : 10);
-
- if (abs(ghand[3].y - 127) < 10) ghand[3].y = 127;
- else ghand[3].y += ((ghand[3].y>127) ? -10 : 10);
-
- for (i=0; i<NUMHANDS; i++) RANGE(ghand[i].y,0,255);
-
- GenerateGamma();
- RedrawGraph(0,0,256,256);
- break;
-
- case G_BHSVRGB:if (!strcmp(gbut[G_BHSVRGB].str, HSVSTR))
- gbut[G_BHSVRGB].str = RGBSTR;
- else gbut[G_BHSVRGB].str = HSVSTR;
- BTRedraw(&gbut[G_BHSVRGB]);
- break;
-
- case G_B1:
- case G_B2:
- case G_B3:
- case G_B4: if (cmd==G_B1) p = 0;
- else if (cmd==G_B2) p = 1;
- else if (cmd==G_B3) p = 2;
- else if (cmd==G_B4) p = 3;
-
- if (gbut[G_BSET].lit) {
- memcpy(presets[p], ghand, sizeof(ghand));
- gbut[G_BSET].lit = 0;
- BTRedraw(&gbut[G_BSET]);
- app=0;
- }
- else {
- SaveUndoState();
- memcpy(ghand, presets[p], sizeof(ghand));
- GenerateGamma();
- RedrawGraph(0,0,256,256);
- }
- break;
-
- case G_BSET: app=0; break;
-
- case G_BUNDO: bcopy(undo[0], ghand, sizeof(ghand));
- bcopy(undo[1], undo[0], (MAXUNDO-1)*sizeof(ghand));
- GenerateGamma();
- RedrawGraph(0,0,256,256);
- break;
- }
-
- if (app && rwcolor && rwthistime) DoGammaApply(1);
- }
-
-
- /*********************/
- static void DoGammaApply(app)
- int app;
- {
- int i,j;
-
- DoMonoAndRV();
-
- if (app) GammifyColors();
-
- /* special case: if using R/W color, just modify the colors and leave */
- if (rwcolor && rwthistime) {
- XColor ctab[256];
- for (i=0; i<nfcols; i++) {
- j = fc2pcol[i];
- ctab[i].pixel = freecols[i];
- ctab[i].red = r[j]<<8;
- ctab[i].green = g[j]<<8;
- ctab[i].blue = b[j]<<8;
- ctab[i].flags = DoRed | DoGreen | DoBlue;
- XStoreColor(theDisp, LocalCmap ? LocalCmap : theCmap, &ctab[i]);
- }
- return;
- }
-
-
- if (useroot && (LocalCmap || nfcols)) {
- XSetWindowBackgroundPixmap(theDisp, rootW, None);
- }
-
-
- if (LocalCmap) {
- XClearWindow(theDisp,mainW);
- XFreeColormap(theDisp,LocalCmap);
- LocalCmap = 0;
- }
- else {
- if (!brokeFreeCols) {
- for (i=0; i<nfcols; i++)
- XFreeColors(theDisp, theCmap, &freecols[i], 1, 0L);
- }
- else {
- for (i=0; i<nfcols; i++) {
- int j;
- for (j=0; j<i; j++) {
- if (freecols[i] == freecols[j]) /* already been freed once */
- break;
- }
- if (j==i) /* wasn't found in already-freed list */
- XFreeColors(theDisp, theCmap, &freecols[i], 1, 0L);
- }
- }
-
- if (nfcols) {
- XFlush(theDisp); /* just to make sure they're all freed right now... */
-
- /* clear window if we're on a non-static display */
- if (theVisual->class & 1 && ncols>0) XClearWindow(theDisp,mainW);
- }
- }
-
-
- AllocColors();
- CreateXImage();
-
- if (useroot) MakeRootPic();
- else DrawWindow(0,0,eWIDE,eHIGH);
- if (but[BCROP].active) InvCropRect();
- SetCursors(-1);
- }
-
-
- /*********************/
- void GammifyColors()
- {
- int i;
-
- if (!strcmp(gbut[G_BHSVRGB].str,RGBSTR)) {
- for (i=0; i<numcols; i++) {
- r[i] = gamcr[r[i]];
- g[i] = gamcr[g[i]];
- b[i] = gamcr[b[i]];
- }
- }
- else HSVgamma();
- }
-
-
- /*********************/
- void SetGPreset(n,y0,x1,y1,x2,y2,y3)
- int n,y0,x1,y1,x2,y2,y3;
- {
- if (n<0 || n>3) return;
-
- presets[n][0].x = 0; presets[n][0].y = y0;
- presets[n][1].x = x1; presets[n][1].y = y1;
- presets[n][2].x = x2; presets[n][2].y = y2;
- presets[n][3].x = 255; presets[n][3].y = y3;
- }
-
-
- #define NOHUE -1
-
- /*********************/
- static void HSVgamma()
- {
- int i, vi, j;
- double rd, gd, bd, h, s, v, max, min, del, rc, gc, bc;
- double f, p, q, t;
-
- for (i=0; i<numcols; i++) {
- /* convert RGB to HSV */
- rd = r[i] / 255.0; /* rd,gd,bd range 0-1 instead of 0-255 */
- gd = g[i] / 255.0;
- bd = b[i] / 255.0;
-
- /* compute maximum of rd,gd,bd */
- if (rd>=gd) { if (rd>=bd) max = rd; else max = bd; }
- else { if (gd>=bd) max = gd; else max = bd; }
-
- /* compute minimum of rd,gd,bd */
- if (rd<=gd) { if (rd<=bd) min = rd; else min = bd; }
- else { if (gd<=bd) min = gd; else min = bd; }
-
- del = max - min;
- v = max;
- if (max != 0.0) s = (del) / max;
- else s = 0.0;
-
- h = NOHUE;
- if (s != 0.0) {
- rc = (max - rd) / del;
- gc = (max - gd) / del;
- bc = (max - bd) / del;
-
- if (rd==max) h = bc - gc;
- else if (gd==max) h = 2 + rc - bc;
- else if (bd==max) h = 4 + gc - rc;
-
- h = h * 60;
- if (h<0) h += 360;
- }
-
- /* map near-black to black to avoid weird effects */
- if (v <= .0625) s = 0.0;
-
- /* apply gamcr[] function to 'v' (the intensity) */
- vi = (int) floor(v * 255);
- v = gamcr[vi] / 255.0;
-
- /* convert HSV back to RGB */
- if (s==0.0) { rd = v; gd = v; bd = v; }
- else {
- if (h==360.0) h = 0.0;
- h = h / 60.0;
- j = (int) floor(h);
- f = h - j;
- p = v * (1-s);
- q = v * (1 - (s*f));
- t = v * (1 - (s*(1 - f)));
-
- switch (j) {
- case 0: rd = v; gd = t; bd = p; break;
- case 1: rd = q; gd = v; bd = p; break;
- case 2: rd = p; gd = v; bd = t; break;
- case 3: rd = p; gd = q; bd = v; break;
- case 4: rd = t; gd = p; bd = v; break;
- case 5: rd = v; gd = p; bd = q; break;
- }
- }
-
- r[i] = (int) floor(rd * 255);
- g[i] = (int) floor(gd * 255);
- b[i] = (int) floor(bd * 255);
- }
- }
-
-
-
-
- /*********************/
- static void SaveUndoState()
- {
- /* pushes the current 'ghand' values onto the undo stack */
-
- /* use bcopy 'cause it knows how to do overlapped copies */
- bcopy(undo[0], undo[1], (MAXUNDO-1) * sizeof(ghand));
-
- /* and put 'ghand' on the top of the stack */
- bcopy(ghand, undo[0], sizeof(ghand));
- }
- \BARFOO\
- else
- echo "will not over write ./xvgam.c"
- fi
- if `test ! -s ./xvgif.c`
- then
- echo "writting ./xvgif.c"
- cat > ./xvgif.c << '\BARFOO\'
- /*
- * xvgif.c - GIF loading code for 'xv'. Based strongly on...
- *
- * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
- *
- * Copyright (c) 1988, 1989 by Patrick J. Naughton
- *
- * Author: Patrick J. Naughton
- * naughton@wind.sun.com
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation.
- *
- * This file is provided AS IS with no warranties of any kind. The author
- * shall have no liability with respect to the infringement of copyrights,
- * trade secrets or any patents by this file or any part thereof. In no
- * event will the author be liable for any lost revenue or profits or
- * other special, indirect and consequential damages.
- *
- */
-
- /*
- * 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"
-
- typedef int boolean;
-
- #define NEXTBYTE (*ptr++)
- #define IMAGESEP 0x2c
- #define EXTENSION 0x21
- #define INTERLACEMASK 0x40
- #define COLORMAPMASK 0x80
-
-
-
- FILE *fp;
-
- int BitOffset = 0, /* Bit Offset of next code */
- XC = 0, YC = 0, /* Output X and Y coords of current pixel */
- Pass = 0, /* Used by output routine if interlaced pic */
- OutCount = 0, /* Decompressor output 'stack count' */
- RWidth, RHeight, /* screen dimensions */
- Width, Height, /* image dimensions */
- LeftOfs, TopOfs, /* image offset */
- BitsPerPixel, /* Bits per pixel, read from GIF header */
- BytesPerScanline, /* bytes per scanline in output raster */
- ColorMapSize, /* number of colors */
- Background, /* background color */
- CodeSize, /* Code size, read from GIF header */
- InitCodeSize, /* Starting code size, used during Clear */
- Code, /* Value returned by ReadCode */
- MaxCode, /* limiting value for current code size */
- ClearCode, /* GIF clear code */
- EOFCode, /* GIF end-of-information code */
- CurCode, OldCode, InCode, /* Decompressor variables */
- FirstFree, /* First free code, generated per GIF spec */
- FreeCode, /* Decompressor,next free slot in hash table */
- FinChar, /* Decompressor variable */
- BitMask, /* AND mask for data size */
- ReadMask, /* Code AND mask for current code size */
- Misc; /* miscellaneous bits (interlace, local cmap)*/
-
-
- boolean Interlace, HasColormap;
-
- byte *RawGIF; /* The heap array to hold it, raw */
- byte *Raster; /* The raster data stream, unblocked */
-
- /* The hash table used by the decompressor */
- int Prefix[4096];
- int Suffix[4096];
-
- /* An output array used by the decompressor */
- int OutCode[1025];
-
- char *id = "GIF87a";
-
- static int EGApalette[16][3] = {
- {0,0,0}, {0,0,128}, {0,128,0}, {0,128,128},
- {128,0,0}, {128,0,128}, {128,128,0}, {200,200,200},
- {100,100,100}, {100,100,255}, {100,255,100}, {100,255,255},
- {255,100,100}, {255,100,255}, {255,255,100}, {255,255,255} };
-
-
- static int ReadCode();
- static void DoInterlace();
- static int GifError();
-
- int filesize;
-
- /*****************************/
- int LoadGIF(fname,nc)
- char *fname;
- int nc;
- /*****************************/
- {
- register byte ch, ch1;
- register byte *ptr, *ptr1, *picptr;
- register int i;
- int npixels, maxpixels;
-
- /* initialize variables */
- BitOffset = XC = YC = Pass = OutCount = npixels = maxpixels = 0;
- RawGIF = Raster = pic = NULL;
-
- fp = fopen(fname,"r");
- if (!fp) {
- fprintf(stderr,"%s: LoadGIF() - unable to open file '%s'\n",cmd,fname);
- return 1;
- }
-
- /* find the size of the file */
- fseek(fp, 0L, 2);
- filesize = ftell(fp);
- fseek(fp, 0L, 0);
-
- /* the +256's are so we can read truncated GIF files without fear of
- segmentation violation */
- if (!(ptr = RawGIF = (byte *) malloc(filesize+256)))
- return( GifError("not enough memory to read gif file") );
-
- if (!(Raster = (byte *) malloc(filesize+256)))
- return( GifError("not enough memory to read gif file") );
-
- if (fread(ptr, filesize, 1, fp) != 1)
- return( GifError("GIF data read failed") );
-
- if (strncmp(ptr, id, 6))
- return( GifError("not a GIF file"));
-
- ptr += 6;
-
- /* Get variables from the GIF screen descriptor */
-
- ch = NEXTBYTE;
- RWidth = ch + 0x100 * NEXTBYTE; /* screen dimensions... not used. */
- ch = NEXTBYTE;
- RHeight = ch + 0x100 * NEXTBYTE;
-
- ch = NEXTBYTE;
- HasColormap = ((ch & COLORMAPMASK) ? True : False);
-
- BitsPerPixel = (ch & 7) + 1;
- numcols = ColorMapSize = 1 << BitsPerPixel;
- BitMask = ColorMapSize - 1;
-
- Background = NEXTBYTE; /* background color... not used. */
-
- if (NEXTBYTE) /* supposed to be NULL */
- return( GifError("corrupt GIF file (screen descriptor)") );
-
-
- /* Read in global colormap. */
-
- if (HasColormap)
- for (i=0; i<ColorMapSize; i++) {
- r[i] = NEXTBYTE;
- g[i] = NEXTBYTE;
- b[i] = NEXTBYTE;
- }
- else { /* no colormap in GIF file */
- /* put std EGA palette (repeated 16 times) into colormap, for lack of
- anything better to do */
-
- for (i=0; i<256; i++) {
- r[i] = EGApalette[i&15][0];
- g[i] = EGApalette[i&15][1];
- b[i] = EGApalette[i&15][2];
- }
- }
-
-
- while ( (i=NEXTBYTE) == EXTENSION) { /* parse extension blocks */
- int i, fn, blocksize, aspnum, aspden;
-
- /* read extension block */
- fn = NEXTBYTE;
-
- do {
- i = 0; blocksize = NEXTBYTE;
- while (i<blocksize) {
- if (fn == 'R' && blocksize == 2) { /* aspect ratio extension */
- aspnum = NEXTBYTE; i++;
- aspden = NEXTBYTE; i++;
- if (aspden>0 && aspnum>0)
- normaspect = (float) aspnum / (float) aspden;
- else { normaspect = 1.0; aspnum = aspden = 1; }
-
- /* fprintf(stderr,"aspect extension: %d:%d = %f\n",
- aspnum, aspden,normaspect); */
- }
- else { NEXTBYTE; i++; }
- }
- } while (blocksize);
- }
-
-
- /* Check for image seperator */
- if (i != IMAGESEP)
- return( GifError("corrupt GIF file (no image separator)") );
-
- /* Now read in values from the image descriptor */
-
- ch = NEXTBYTE;
- LeftOfs = ch + 0x100 * NEXTBYTE;
- ch = NEXTBYTE;
- TopOfs = ch + 0x100 * NEXTBYTE;
- ch = NEXTBYTE;
- Width = ch + 0x100 * NEXTBYTE;
- ch = NEXTBYTE;
- Height = ch + 0x100 * NEXTBYTE;
-
- Misc = NEXTBYTE;
- Interlace = ((Misc & INTERLACEMASK) ? True : False);
-
- if (Misc & 0x80) {
- for (i=0; i< 1 << ((Misc&7)+1); i++) {
- r[i] = NEXTBYTE;
- g[i] = NEXTBYTE;
- b[i] = NEXTBYTE;
- }
- }
-
-
- if (!HasColormap && !(Misc&0x80)) {
- /* no global or local colormap */
- SetISTR(ISTR_WARNING,
- "No colormap in this GIF file. Assuming EGA colors.");
- }
-
-
-
- /* Start reading the raster data. First we get the intial code size
- * and compute decompressor constant values, based on this code size.
- */
-
- CodeSize = NEXTBYTE;
- ClearCode = (1 << CodeSize);
- EOFCode = ClearCode + 1;
- FreeCode = FirstFree = ClearCode + 2;
-
- /* The GIF spec has it that the code size is the code size used to
- * compute the above values is the code size given in the file, but the
- * code size used in compression/decompression is the code size given in
- * the file plus one. (thus the ++).
- */
-
- CodeSize++;
- InitCodeSize = CodeSize;
- MaxCode = (1 << CodeSize);
- ReadMask = MaxCode - 1;
-
-
-
- /* UNBLOCK:
- * Read the raster data. Here we just transpose it from the GIF array
- * to the Raster array, turning it from a series of blocks into one long
- * data stream, which makes life much easier for ReadCode().
- */
-
- ptr1 = Raster;
- do {
- ch = ch1 = NEXTBYTE;
- while (ch--) { *ptr1 = NEXTBYTE; ptr1++; }
- if ((ptr - RawGIF) > filesize) {
- SetISTR(ISTR_WARNING,
- "This GIF file seems to be truncated. Winging it.");
- break;
- }
- } while(ch1);
- free(RawGIF); RawGIF = NULL; /* We're done with the raw data now */
-
-
-
- if (DEBUG) {
- fprintf(stderr,"xv: LoadGIF() - picture is %dx%d, %d bits, %sinterlaced\n",
- Width, Height, BitsPerPixel, Interlace ? "" : "non-");
- }
-
- SetISTR(ISTR_FORMAT, "GIF, %d bits per pixel, %sinterlaced. (%d bytes)",
- BitsPerPixel, Interlace ? "" : "non-", filesize);
-
-
-
- /* Allocate the 'pic' */
- pWIDE = Width; pHIGH = Height;
- maxpixels = Width*Height;
- picptr = pic = (byte *) malloc(maxpixels);
- if (!pic)
- return( GifError("not enough memory for 'pic'") );
-
-
- /* Decompress the file, continuing until you see the GIF EOF code.
- * One obvious enhancement is to add checking for corrupt files here.
- */
-
- Code = ReadCode();
- while (Code != EOFCode) {
- /* Clear code sets everything back to its initial value, then reads the
- * immediately subsequent code as uncompressed data.
- */
-
- if (Code == ClearCode) {
- CodeSize = InitCodeSize;
- MaxCode = (1 << CodeSize);
- ReadMask = MaxCode - 1;
- FreeCode = FirstFree;
- Code = ReadCode();
- CurCode = OldCode = Code;
- FinChar = CurCode & BitMask;
- if (!Interlace) *picptr++ = FinChar;
- else DoInterlace(FinChar);
- npixels++;
- }
- else {
- /* If not a clear code, must be data: save same as CurCode and InCode */
-
- /* if we're at maxcode and didn't get a clear, stop loading */
- if (FreeCode>=4096) { /* printf("freecode blew up\n"); */
- break; }
-
- CurCode = InCode = Code;
-
- /* If greater or equal to FreeCode, not in the hash table yet;
- * repeat the last character decoded
- */
-
- if (CurCode >= FreeCode) {
- CurCode = OldCode;
- if (OutCount > 1024) { /* printf("outcount1 blew up\n"); */ break; }
- OutCode[OutCount++] = FinChar;
- }
-
- /* Unless this code is raw data, pursue the chain pointed to by CurCode
- * through the hash table to its end; each code in the chain puts its
- * associated output code on the output queue.
- */
-
- while (CurCode > BitMask) {
- if (OutCount > 1024) break; /* corrupt file */
- OutCode[OutCount++] = Suffix[CurCode];
- CurCode = Prefix[CurCode];
- }
-
- if (OutCount > 1024) { /* printf("outcount blew up\n"); */ break; }
-
- /* The last code in the chain is treated as raw data. */
-
- FinChar = CurCode & BitMask;
- OutCode[OutCount++] = FinChar;
-
- /* Now we put the data out to the Output routine.
- * It's been stacked LIFO, so deal with it that way...
- */
-
- /* safety thing: prevent exceeding range of 'pic' */
- if (npixels + OutCount > maxpixels) OutCount = maxpixels-npixels;
-
- npixels += OutCount;
- if (!Interlace) for (i=OutCount-1; i>=0; i--) *picptr++ = OutCode[i];
- else for (i=OutCount-1; i>=0; i--) DoInterlace(OutCode[i]);
- OutCount = 0;
-
- /* Build the hash table on-the-fly. No table is stored in the file. */
-
- Prefix[FreeCode] = OldCode;
- Suffix[FreeCode] = FinChar;
- OldCode = InCode;
-
- /* Point to the next slot in the table. If we exceed the current
- * MaxCode value, increment the code size unless it's already 12. If it
- * is, do nothing: the next code decompressed better be CLEAR
- */
-
- FreeCode++;
- if (FreeCode >= MaxCode) {
- if (CodeSize < 12) {
- CodeSize++;
- MaxCode *= 2;
- ReadMask = (1 << CodeSize) - 1;
- }
- }
- }
- Code = ReadCode();
- if (npixels >= maxpixels) break;
- }
- free(Raster); Raster = NULL;
-
- if (npixels != maxpixels) {
- SetISTR(ISTR_WARNING,"This GIF file seems to be truncated. Winging it.");
- memset(pic+npixels, 0, maxpixels-npixels); /* clear to EOBuffer */
- }
-
- if (fp != stdin) fclose(fp);
-
- return 0;
- }
-
-
- /* Fetch the next code from the raster data stream. The codes can be
- * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
- * maintain our location in the Raster array as a BIT Offset. We compute
- * the byte Offset into the raster array by dividing this by 8, pick up
- * three bytes, compute the bit Offset into our 24-bit chunk, shift to
- * bring the desired code to the bottom, then mask it off and return it.
- */
-
- static int ReadCode()
- {
- int RawCode, ByteOffset;
-
- ByteOffset = BitOffset / 8;
- RawCode = Raster[ByteOffset] + (Raster[ByteOffset + 1] << 8);
- if (CodeSize >= 8)
- RawCode += (Raster[ByteOffset + 2] << 16);
- RawCode >>= (BitOffset % 8);
- BitOffset += CodeSize;
-
- return(RawCode & ReadMask);
- }
-
-
- /***************************/
- static void DoInterlace(Index)
- byte Index;
- {
- static byte *ptr = NULL;
- static int oldYC = -1;
-
- if (oldYC != YC) { ptr = pic + YC * Width; oldYC = YC; }
-
- if (YC<Height)
- *ptr++ = Index;
-
- /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
-
- if (++XC == Width) {
-
- /* deal with the interlace as described in the GIF
- * spec. Put the decoded scan line out to the screen if we haven't gone
- * past the bottom of it
- */
-
- XC = 0;
-
- switch (Pass) {
- case 0:
- YC += 8;
- if (YC >= Height) { Pass++; YC = 4; }
- break;
-
- case 1:
- YC += 8;
- if (YC >= Height) { Pass++; YC = 2; }
- break;
-
- case 2:
- YC += 4;
- if (YC >= Height) { Pass++; YC = 1; }
- break;
-
- case 3:
- YC += 2; break;
-
- default:
- break;
- }
- }
- }
-
-
-
- /*****************************/
- static int GifError(st)
- char *st;
- {
- fprintf(stderr,"%s: LoadGIF() - %s\n",cmd,st);
-
- if (RawGIF != NULL) free(RawGIF);
- if (Raster != NULL) free(Raster);
- if (pic != NULL) free(pic);
-
- return -1;
- }
-
- \BARFOO\
- else
- echo "will not over write ./xvgif.c"
- fi
- if `test ! -s ./xvgifwr.c`
- then
- echo "writting ./xvgifwr.c"
- cat > ./xvgifwr.c << '\BARFOO\'
- /*
- * xvgifwr.c - handles writing of GIF files. based on flgife.c and
- * flgifc.c from the FBM Library, by Michael Maudlin
- *
- * Contains:
- * WriteGIF(fp, pic, w, h, rmap, gmap, bmap, numcols, colorstyle)
- *
- * Note: slightly brain-damaged, in that it'll only write non-interlaced
- * GIF files (in the interests of speed, or something)
- *
- */
-
-
-
- /*****************************************************************
- * Portions of this code Copyright (C) 1989 by Michael Mauldin.
- * Permission is granted to use this file in whole or in part provided
- * that you do not sell it for profit and that this copyright notice
- * and the names of all authors are retained unchanged.
- *
- * Authors: Michael Mauldin (mlm@cs.cmu.edu)
- * David Rowley (mgardi@watdcsu.waterloo.edu)
- *
- * Based on: compress.c - File compression ala IEEE Computer, June 1984.
- *
- * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
- * Jim McKie (decvax!mcvax!jim)
- * Steve Davies (decvax!vax135!petsd!peora!srd)
- * Ken Turkowski (decvax!decwrl!turtlevax!ken)
- * James A. Woods (decvax!ihnp4!ames!jaw)
- * Joe Orost (decvax!vax135!petsd!joe)
- *****************************************************************/
-
- /*
- * 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"
-
- typedef long int count_int;
-
- static int Width, Height;
- static int curx, cury;
- static long CountDown;
- static int Interlace;
- static byte bw[2] = {0, 0xff};
-
- #ifdef __STDC__
- static void putword(int, FILE *);
- static void compress(int, FILE *, byte *, int);
- static void output(int);
- static void cl_block(void);
- static void cl_hash(count_int);
- static void char_init(void);
- static void char_out(int);
- static void flush_char(void);
- #else
- static void putword(), compress(), output(), cl_block(), cl_hash();
- static void char_init(), char_out(), flush_char();
- #endif
-
- /*************************************************************/
- int WriteGIF(fp, pic, w, h, rmap, gmap, bmap, numcols, colorstyle)
- FILE *fp;
- byte *pic;
- int w,h;
- byte *rmap, *gmap, *bmap;
- int numcols, colorstyle;
- {
- int RWidth, RHeight;
- int LeftOfs, TopOfs;
- int Resolution, ColorMapSize, InitCodeSize, Background, BitsPerPixel;
- int i,j;
-
-
- /* if writing B/W stipple... */
- if (colorstyle==2) {
- rmap = gmap = bmap = bw;
- numcols = 2;
- }
-
- Interlace = 0;
- Background = 0;
-
- /* figure out 'BitsPerPixel' */
- for (i=1; i<8; i++)
- if ( (1<<i) >= numcols) break;
-
- BitsPerPixel = i;
-
- ColorMapSize = 1 << BitsPerPixel;
-
- RWidth = Width = w;
- RHeight = Height = h;
- LeftOfs = TopOfs = 0;
-
- Resolution = BitsPerPixel;
-
- CountDown = w * h; /* # of pixels we'll be doing */
-
- if (BitsPerPixel <= 1) InitCodeSize = 2;
- else InitCodeSize = BitsPerPixel;
-
- curx = cury = 0;
-
- if (!fp) {
- fprintf(stderr, "WriteGIF: file not open for writing\n" );
- return (1);
- }
-
- if (DEBUG)
- fprintf(stderr,"WrGIF: pic=%lx, w,h=%dx%d, numcols=%d, Bits%d,Cmap=%d\n",
- pic, w,h,numcols,BitsPerPixel,ColorMapSize);
-
- fwrite("GIF87a", 1, 6, fp); /* the GIF magic number */
-
- putword(RWidth, fp); /* screen descriptor */
- putword(RHeight, fp);
-
- i = 0x80; /* Yes, there is a color map */
- i |= (8-1)<<4; /* OR in the color resolution (hardwired 8) */
- i |= (BitsPerPixel - 1); /* OR in the # of bits per pixel */
- fputc(i,fp);
-
- fputc(Background, fp); /* background color */
-
- fputc(0, fp); /* future expansion byte */
-
-
- if (colorstyle == 1) { /* greyscale */
- for (i=0; i<ColorMapSize; i++) {
- j = MONO(rmap[i], gmap[i], bmap[i]);
- fputc(j, fp);
- fputc(j, fp);
- fputc(j, fp);
- }
- }
- else {
- for (i=0; i<ColorMapSize; i++) { /* write out Global colormap */
- fputc(rmap[i], fp);
- fputc(gmap[i], fp);
- fputc(bmap[i], fp);
- }
- }
-
- fputc( ',', fp ); /* image separator */
-
- /* Write the Image header */
- putword(LeftOfs, fp);
- putword(TopOfs, fp);
- putword(Width, fp);
- putword(Height, fp);
- if (Interlace) fputc(0x40, fp); /* Use Global Colormap, maybe Interlace */
- else fputc(0x00, fp);
-
- fputc(InitCodeSize, fp);
- compress(InitCodeSize+1, fp, pic, w*h);
-
- fputc(0,fp); /* Write out a Zero-length packet (EOF) */
- fputc(';',fp); /* Write GIF file terminator */
-
- return (0);
- }
-
-
-
-
- /******************************/
- static void putword(w, fp)
- int w;
- FILE *fp;
- {
- /* writes a 16-bit integer in GIF order (LSB first) */
- fputc(w & 0xff, fp);
- fputc((w>>8)&0xff, fp);
- }
-
-
-
-
- /***********************************************************************/
-
-
- static unsigned long cur_accum = 0;
- static int cur_bits = 0;
-
-
-
-
- #define min(a,b) ((a>b) ? b : a)
-
- #define BITS 12
- #define MSDOS 1
-
- #define HSIZE 5003 /* 80% occupancy */
-
- typedef unsigned char char_type;
-
-
- static int n_bits; /* number of bits/code */
- static int maxbits = BITS; /* user settable max # bits/code */
- static int maxcode; /* maximum code, given n_bits */
- static int maxmaxcode = 1 << BITS; /* NEVER generate this */
-
- #define MAXCODE(n_bits) ( (1 << (n_bits)) - 1)
-
- static count_int htab [HSIZE];
- static unsigned short codetab [HSIZE];
- #define HashTabOf(i) htab[i]
- #define CodeTabOf(i) codetab[i]
-
- static int hsize = HSIZE; /* for dynamic table sizing */
-
- /*
- * To save much memory, we overlay the table used by compress() with those
- * used by decompress(). The tab_prefix table is the same size and type
- * as the codetab. The tab_suffix table needs 2**BITS characters. We
- * get this from the beginning of htab. The output stack uses the rest
- * of htab, and contains characters. There is plenty of room for any
- * possible stack (stack used to be 8000 characters).
- */
-
- #define tab_prefixof(i) CodeTabOf(i)
- #define tab_suffixof(i) ((char_type *)(htab))[i]
- #define de_stack ((char_type *)&tab_suffixof(1<<BITS))
-
- static int free_ent = 0; /* first unused entry */
-
- /*
- * block compression parameters -- after all codes are used up,
- * and compression rate changes, start over.
- */
- static int clear_flg = 0;
-
- static long int in_count = 1; /* length of input */
- static long int out_count = 0; /* # of codes output (for debugging) */
-
- /*
- * compress stdin to stdout
- *
- * Algorithm: use open addressing double hashing (no chaining) on the
- * prefix code / next character combination. We do a variant of Knuth's
- * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
- * secondary probe. Here, the modular division first probe is gives way
- * to a faster exclusive-or manipulation. Also do block compression with
- * an adaptive reset, whereby the code table is cleared when the compression
- * ratio decreases, but after the table fills. The variable-length output
- * codes are re-sized at this point, and a special CLEAR code is generated
- * for the decompressor. Late addition: construct the table according to
- * file size for noticeable speed improvement on small files. Please direct
- * questions about this implementation to ames!jaw.
- */
-
- static int g_init_bits;
- static FILE *g_outfile;
-
- static int ClearCode;
- static int EOFCode;
-
-
- /********************************************************/
- static void compress(init_bits, outfile, data, len)
- int init_bits;
- FILE *outfile;
- byte *data;
- int len;
- {
- register long fcode;
- register int i = 0;
- register int c;
- register int ent;
- register int disp;
- register int hsize_reg;
- register int hshift;
-
- /*
- * Set up the globals: g_init_bits - initial number of bits
- * g_outfile - pointer to output file
- */
- g_init_bits = init_bits;
- g_outfile = outfile;
-
- /* initialize 'compress' globals */
- maxbits = BITS;
- maxmaxcode = 1<<BITS;
- memset((char *) htab, 0, sizeof(htab));
- memset((char *) codetab, 0, sizeof(codetab));
- hsize = HSIZE;
- free_ent = 0;
- clear_flg = 0;
- in_count = 1;
- out_count = 0;
- cur_accum = 0;
- cur_bits = 0;
-
-
- /*
- * Set up the necessary values
- */
- out_count = 0;
- clear_flg = 0;
- in_count = 1;
- maxcode = MAXCODE(n_bits = g_init_bits);
-
- ClearCode = (1 << (init_bits - 1));
- EOFCode = ClearCode + 1;
- free_ent = ClearCode + 2;
-
- char_init();
- ent = *data++; len--;
-
- hshift = 0;
- for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
- hshift++;
- hshift = 8 - hshift; /* set hash code range bound */
-
- hsize_reg = hsize;
- cl_hash( (count_int) hsize_reg); /* clear hash table */
-
- output(ClearCode);
-
- while (len) {
- c = *data++; len--;
- in_count++;
-
- fcode = (long) ( ( (long) c << maxbits) + ent);
- i = (((int) c << hshift) ^ ent); /* xor hashing */
-
- if ( HashTabOf (i) == fcode ) {
- ent = CodeTabOf (i);
- continue;
- }
-
- else if ( (long)HashTabOf (i) < 0 ) /* empty slot */
- goto nomatch;
-
- disp = hsize_reg - i; /* secondary hash (after G. Knott) */
- if ( i == 0 )
- disp = 1;
-
- probe:
- if ( (i -= disp) < 0 )
- i += hsize_reg;
-
- if ( HashTabOf (i) == fcode ) {
- ent = CodeTabOf (i);
- continue;
- }
-
- if ( (long)HashTabOf (i) > 0 )
- goto probe;
-
- nomatch:
- output(ent);
- out_count++;
- ent = c;
-
- if ( free_ent < maxmaxcode ) {
- CodeTabOf (i) = free_ent++; /* code -> hashtable */
- HashTabOf (i) = fcode;
- }
- else
- cl_block();
- }
-
- /* Put out the final code */
- output(ent);
- out_count++;
- output(EOFCode);
- }
-
-
- /*****************************************************************
- * TAG( output )
- *
- * Output the given code.
- * Inputs:
- * code: A n_bits-bit integer. If == -1, then EOF. This assumes
- * that n_bits =< (long)wordsize - 1.
- * Outputs:
- * Outputs code to the file.
- * Assumptions:
- * Chars are 8 bits long.
- * Algorithm:
- * Maintain a BITS character long buffer (so that 8 codes will
- * fit in it exactly). Use the VAX insv instruction to insert each
- * code in turn. When the buffer fills up empty it and start over.
- */
-
- static
- unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
- 0x001F, 0x003F, 0x007F, 0x00FF,
- 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
- 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
-
- static void output(code)
- int code;
- {
- cur_accum &= masks[cur_bits];
-
- if (cur_bits > 0)
- cur_accum |= ((long)code << cur_bits);
- else
- cur_accum = code;
-
- cur_bits += n_bits;
-
- while( cur_bits >= 8 ) {
- char_out( (unsigned int) (cur_accum & 0xff) );
- cur_accum >>= 8;
- cur_bits -= 8;
- }
-
- /*
- * If the next entry is going to be too big for the code size,
- * then increase it, if possible.
- */
-
- if (free_ent > maxcode || clear_flg) {
-
- if( clear_flg ) {
- maxcode = MAXCODE (n_bits = g_init_bits);
- clear_flg = 0;
- }
- else {
- n_bits++;
- if ( n_bits == maxbits )
- maxcode = maxmaxcode;
- else
- maxcode = MAXCODE(n_bits);
- }
- }
-
- if( code == EOFCode ) {
- /* At EOF, write the rest of the buffer */
- while( cur_bits > 0 ) {
- char_out( (unsigned int)(cur_accum & 0xff) );
- cur_accum >>= 8;
- cur_bits -= 8;
- }
-
- flush_char();
-
- fflush( g_outfile );
-
- if( ferror( g_outfile ) )
- FatalError("unable to write GIF file");
- }
- }
-
-
- /********************************/
- static void cl_block () /* table clear for block compress */
- {
- /* Clear out the hash table */
-
- cl_hash ( (count_int) hsize );
- free_ent = ClearCode + 2;
- clear_flg = 1;
-
- output(ClearCode);
- }
-
-
- /********************************/
- static void cl_hash(hsize) /* reset code table */
- register count_int hsize;
- {
- register count_int *htab_p = htab+hsize;
- register long i;
- register long m1 = -1;
-
- i = hsize - 16;
- do { /* might use Sys V memset(3) here */
- *(htab_p-16) = m1;
- *(htab_p-15) = m1;
- *(htab_p-14) = m1;
- *(htab_p-13) = m1;
- *(htab_p-12) = m1;
- *(htab_p-11) = m1;
- *(htab_p-10) = m1;
- *(htab_p-9) = m1;
- *(htab_p-8) = m1;
- *(htab_p-7) = m1;
- *(htab_p-6) = m1;
- *(htab_p-5) = m1;
- *(htab_p-4) = m1;
- *(htab_p-3) = m1;
- *(htab_p-2) = m1;
- *(htab_p-1) = m1;
- htab_p -= 16;
- } while ((i -= 16) >= 0);
-
- for ( i += 16; i > 0; i-- )
- *--htab_p = m1;
- }
-
-
- /******************************************************************************
- *
- * GIF Specific routines
- *
- ******************************************************************************/
-
- /*
- * Number of characters so far in this 'packet'
- */
- static int a_count;
-
- /*
- * Set up the 'byte output' routine
- */
- static void char_init()
- {
- a_count = 0;
- }
-
- /*
- * Define the storage for the packet accumulator
- */
- static char accum[ 256 ];
-
- /*
- * Add a character to the end of the current packet, and if it is 254
- * characters, flush the packet to disk.
- */
- static void char_out(c)
- int c;
- {
- accum[ a_count++ ] = c;
- if( a_count >= 254 )
- flush_char();
- }
-
- /*
- * Flush the packet to disk, and reset the accumulator
- */
- static void flush_char()
- {
- if( a_count > 0 ) {
- fputc( a_count, g_outfile );
- fwrite( accum, 1, a_count, g_outfile );
- a_count = 0;
- }
- }
- \BARFOO\
- else
- echo "will not over write ./xvgifwr.c"
- fi
- echo "Finished archive 6 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.
-