home *** CD-ROM | disk | FTP | other *** search
- /*
- * xv.c - main section of xv. X setup, window creation, event loop, etc.
- *
- * Author: John Bradley, University of Pennsylvania
- * (bradley@cis.upenn.edu)
- */
-
-
- /*
- * 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.
- */
- /* $Header $ */
- /* $Log $ */
- static char xvtiffrcsid[] = "$Header: /Source/Media/collab/DisplayTool/RCS/xvimage.c,v 1.3 92/10/30 18:49:18 drapeau Exp $";
-
- #define NEEDSDIR /* for value of MAXPATHLEN */
- #include "xvimage.h"
- #include <X11/Xatom.h>
- #include "DisplayTool.h"
-
- /* file types that can be read */
- #define UNKNOWN 0
- #define GIF 1
- #define PM 2
- #define PBM 3
- #define XBM 4
- #define SUNRAS 5
- #define JFIF 6
- #define TIFF 7
- #define PDSVICAR 8
-
- static unsigned long rootbg, rootfg; /* fg/bg for root border */
- static int roottile = 0; /* resize pic to tile evenly on rootW */
- static int automax = 0; /* resize pic to dispWIDE, dispHIGH on open */
- static int autoquit = 0; /* quit after loading first pic to rootW */
- static int autogamma = 1; /* perform gamma correction by default */
- static char *maingeom = NULL;
- static char initpath[MAXPATHLEN];
- XImage *theImage; /* X version of epic */
-
-
- /* function pre-definitions */
- IMAGE openPic(int filenum);
- static void FixAspect();
- XImage* CreateXImage(byte* origData, int width, int height);
-
-
- /*******************************************/
- IMAGE xvimage_main(char *file)
- /*******************************************/
- {
- int imap, ctrlmap, gmap, clrroot;
- char *display, *fname, *whitestr, *blackstr,
- *fgstr, *bgstr;
- char *rootfgstr, *rootbgstr;
- char *function;
- char *argument;
- XColor ecdef;
-
- getwd(initpath);
- function = "-geom";
- argument = "100x100";
- display = fname = whitestr = blackstr = NULL; /* init internal variables */
- fgstr = bgstr = rootfgstr = rootbgstr = NULL;
- pic = epic = cpic = NULL;
- theImage = NULL;
- LocalCmap = 0;
- cmd = (char *)strdup("xvimage");
- formatStr[0] ='\0';
-
- expand = 1; ncols = -1; noglob = 0; revvideo = 0; mono = 0; /* Init command-line options flags */
- perfect = 0; ninstall = 0; fixedaspect = 0;
- DEBUG = 0; bwidth = 2;
- useroot = clrroot = noqcheck = rwcolor = fishrunning = 0;
- fish = 0;
- brokeFreeCols = 1;
- defaspect = normaspect = 1.0;
-
- mainW = NULL;
- imap = ctrlmap = gmap = 0;
-
- if (!file)
- {
- printf("NULL filename\n");
- return((IMAGE)NULL);
- }
- namelist[0] = (char *)strdup(file);
- numnames = 1;
-
- if (function)
- {
- if (!strncmp(function,"-as",3)) { /* default aspect */
- int n,d;
- if (sscanf(argument,"%d:%d",&n,&d)!=2 || n<1 || d<1)
- fprintf(stderr,"%s: bad aspect ratio '%s'\n",cmd,argument);
- else defaspect = (float) n / (float) d;
- }
-
- else if (!strncmp(function,"-au",3)) /* autogamma */
- autogamma++;
-
- else if (!strncmp(function,"-ge",3)) /* geometry */
- {
- maingeom = argument;
- if (!strcmp(argument, "100x100"))
- fixedaspect++;
- }
- }
-
- if (DEBUG) XSynchronize(theDisp, True);
-
- /* if using root, generally gotta map ctrl window, 'cause there won't be
- any way to ask for it. (no kbd or mouse events from rootW) */
- if (useroot && !autoquit)
- ctrlmap = 1;
-
- ncells = DisplayCells(theDisp, theScreen);
-
- /* set up white,black colors */
- white = WhitePixel(theDisp,theScreen);
- black = BlackPixel(theDisp,theScreen);
- if (whitestr && XParseColor(theDisp, theCmap, whitestr, &ecdef) &&
- XAllocColor(theDisp, theCmap, &ecdef)) white = ecdef.pixel;
- if (blackstr && XParseColor(theDisp, theCmap, blackstr, &ecdef) &&
- XAllocColor(theDisp, theCmap, &ecdef)) black = ecdef.pixel;
-
- /* set up fg,bg colors */
- fg = black; bg = white;
- if (fgstr && XParseColor(theDisp, theCmap, fgstr, &ecdef) &&
- XAllocColor(theDisp, theCmap, &ecdef)) fg = ecdef.pixel;
- if (bgstr && XParseColor(theDisp, theCmap, bgstr, &ecdef) &&
- XAllocColor(theDisp, theCmap, &ecdef)) bg = ecdef.pixel;
-
- /* set up root fg,bg colors */
- rootfg = white; rootbg = black;
- if (rootfgstr && XParseColor(theDisp, theCmap, rootfgstr, &ecdef) &&
- XAllocColor(theDisp, theCmap, &ecdef)) rootfg = ecdef.pixel;
- if (rootbgstr && XParseColor(theDisp, theCmap, rootbgstr, &ecdef) &&
- XAllocColor(theDisp, theCmap, &ecdef)) rootbg = ecdef.pixel;
-
- XSetForeground(theDisp,theGC,fg);
- XSetBackground(theDisp,theGC,bg);
-
- /* set up infofg,infobg colors */
- infofg = fg; infobg = bg;
-
-
- /* if '-mono' not forced, determine if we're on a b/w or color monitor */
- if (!mono) {
- if (DEBUG) fprintf(stderr,"%s: VisualClass = %d\n",cmd, theVisual->class);
- if (theVisual->class == StaticGray || theVisual->class == GrayScale)
- mono = 1;
- }
-
- /* if ncols wasn't set, set it to 2^dispDEEP, unless dispDEEP=1, in which
- case ncols = 0; (ncols = max number of colors allocated. on 1-bit
- displays, no colors are allocated */
-
- if (ncols == -1)
- {
- if (dispDEEP>1) ncols = 1<<dispDEEP;
- else ncols = 0;
- }
- else if (ncols>256) /* So program doesn't blow up */
- ncols = 256;
-
- if (numnames==0) /* No filenames. build one-name (stdio) list */
- {
- namelist[0] = "<stdin>";
- numnames = 1;
- }
-
- if (!(theVisual->class & 1) && rwcolor) /* If we're not on a colormapped display, turn off rwcolor */
- {
- fprintf(stderr,"xv: not a colormapped display. 'rwcolor' turned off.\n");
- rwcolor = 0;
- }
- return(openPic(0));
- } /* end function xvimage_main */
-
-
-
- /***********************************/
- IMAGE openPic(int filenum)
- {
- /* tries to load file #filenum (from 'namelist' list)
- * returns 0 on failure (cleans up after itself)
- * if successful, returns 1, creates mainW
- */
-
- int i,filetype,okay,freename, nw, nh;
- char *tmp;
- FILE *fp;
- char *fullname, /* full name of the original file */
- filename[256], /* full name of the file to be loaded (could be /tmp) */
- basename[128]; /* just the name of the original file. No path */
- byte magicno[8]; /* first 8 bytes of file */
- IMAGE newImage = (IMAGE)NULL; /* Holds new IMAGE info if function is successful */
-
- normaspect = defaspect;
- curname = filenum;
- XFlush(theDisp); /* update NOW */
- formatStr[0] = '\0'; /* Clear any old error messages */
- okay = 0;
- fullname = namelist[filenum]; /* Set up fullname and basename */
- tmp = rindex(fullname,'/');
- if (!tmp) tmp = fullname; else tmp++;
- strcpy(basename,tmp);
- if (strlen(basename)>2 && strcmp(basename+strlen(basename)-2,".Z")==0)
- basename[strlen(basename)-2]='\0'; /* chop off .Z, if any */
-
- freename = 0;
- if (fullname[0] != '/' && strcmp(fullname,"<stdin>")!=0) /* If fullname doesn't start with a '/' (ie, it's... */
- { /* ... a relative path), (and it's not the special... */
- char *tmp; /* ...case '<stdin>') prepend 'initpath' to it */
- tmp = (char *) MyMalloc(strlen(fullname) + strlen(initpath) + 2);
- if (!tmp) FatalError("MyMalloc 'filename' failed");
- sprintf(tmp,"%s/%s", initpath, fullname);
- fullname = tmp;
- freename = 1;
- }
-
- strcpy(filename,fullname);
-
- /* now, try to determine what type of file we've got by reading the
- first couple bytes and looking for a Magic Number */
-
- fp=fopen(filename,"r");
- if (!fp) {
- goto FAILED;
- }
-
- fread(magicno,8,1,fp);
- fclose(fp);
- filetype = UNKNOWN;
- if (strncmp((char *) magicno,"GIF87a",6)==0 ||
- strncmp((char *) magicno,"GIF89a",6)==0) filetype = GIF;
-
- else if (strncmp((char *) magicno,"VIEW",4)==0 ||
- strncmp((char *) magicno,"WEIV",4)==0) filetype = PM;
-
- else if (magicno[0] == 'P' && magicno[1]>='1' &&
- magicno[1]<='6') filetype = PBM;
-
- else if (strncmp((char *) magicno,"#define",7)==0) filetype = XBM;
-
- else if (magicno[0]==0x59 && (magicno[1]&0x7f)==0x26 &&
- magicno[2]==0x6a && (magicno[3]&0x7f)==0x15) filetype = SUNRAS;
-
- else if (magicno[0]==0xff && magicno[1]==0xd8 &&
- magicno[2]==0xff) filetype = JFIF;
-
- else if (strncmp(magicno,"MM",2)==0 ||
- strncmp(magicno,"II",2)==0) filetype = TIFF;
-
- else if (strncmp((char *) magicno, "NJPL1I00",8)==0 || /* fixed-len pds */
- strncmp((char *) magicno+2,"NJPL1I", 6)==0 || /* vger+other pds */
- strncmp((char *) magicno, "CCSD3ZF", 7)==0 || /* vikng pds browse*/
- strncmp((char *) magicno+2,"CCSD3Z", 6)==0 || /* vik. huffman pds*/
- strncmp((char *) magicno, "LBLSIZE=",8)==0) /* vicar */
- filetype = PDSVICAR;
-
- if (filetype == UNKNOWN) {
- goto FAILED;
- }
-
- switch (filetype) {
- case GIF: i = LoadGIF(filename,ncols); break;
- case PM: i = LoadPM (filename,ncols); break;
- case PBM: i = LoadPBM(filename,ncols); break;
- case XBM: i = LoadXBM(filename,ncols); break;
- case SUNRAS: i = LoadSunRas(filename, ncols); break;
- case JFIF: i = LoadJFIF(filename, ncols); break;
- case TIFF: i = LoadTIFF(filename, ncols); break;
- case PDSVICAR: i = LoadPDS(filename, ncols); break;
- }
-
- if (i) {
- goto FAILED;
- }
- /*
- for (i=0; i<numcols; i++)
- printf("r[%d]=%d g[%d]=%d b[%d]=%d\n", i, r[i], i, g[i], i, b[i]);
- */
-
- /* successfully read this picture */
- if (strcmp(fullname,filename)!=0) /* If we read a /tmp file, delete it; won't be... */
- unlink(filename); /* ...needing it any more */
-
- normFact = 1; nw = pWIDE; nh = pHIGH;
- /* if pic is larger than screen, half picture until it fits on screen */
- while (nw > dispWIDE || nh > dispHIGH) {
- nw = nw / 2;
- nh = nh / 2;
- normFact = normFact * 2;
- }
-
- /* expand: if expansion is negative, treat it as a reciprocal */
- if (expand<0) { eWIDE = pWIDE/abs(expand); eHIGH = pHIGH/abs(expand); }
- else { eWIDE = pWIDE * expand; eHIGH = pHIGH * expand; }
-
- if (1) { /* bry -- was useroot */
- int i,x,y; unsigned int w,h;
- i = XParseGeometry(maingeom,&x,&y,&w,&h);
- if (i&WidthValue) eWIDE = w;
- if (i&HeightValue) eHIGH = h;
- RANGE(eWIDE,1,dispWIDE); RANGE(eHIGH,1,dispHIGH);
-
- if (roottile) {
- /* make picture size a divisor of the rootW size. round down */
- i = (dispWIDE + eWIDE-1) / eWIDE; eWIDE = (dispWIDE + i-1) / i;
- i = (dispHIGH + eHIGH-1) / eHIGH; eHIGH = (dispHIGH + i-1) / i;
- }
- }
-
- cpic = pic; cWIDE = pWIDE; cHIGH = pHIGH; cXOFF = cYOFF = 0;
-
- if (automax) {
- eWIDE = dispWIDE; eHIGH = dispHIGH;
- if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH);
- }
-
- if (useroot) {
- mainW = rootW;
-
- if (theVisual->class & 1) /* Clear old root pixmap before doing the ... */
- { /* ...'alloc colors scene' to avoid annoying... */
- XSetWindowBackgroundPixmap(theDisp, rootW, None); /* ...'rainbow' effect as colors are realloced */
- XClearWindow(theDisp, rootW);
- XFlush(theDisp);
- }
- }
-
- if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH);
- else if (i&WidthValue && i&HeightValue)
- { RANGE(eWIDE,1,dispWIDE); RANGE(eHIGH,1,dispHIGH); }
-
- SortColormap();
-
- for (i=0; i<numcols; i++) /* Save desired RGB colormap (before gamma-correcting it) */
- { rorg[i] = r[i]; gorg[i] = g[i]; borg[i] = b[i]; }
-
- DoMonoAndRV();
- AllocColors();
-
- if (LocalCmap)
- {
- XSetWindowAttributes xswa;
- if (!ninstall)
- { /* bry - you put in these parens */
- XInstallColormap(theDisp,LocalCmap);
- xswa.colormap = LocalCmap;
- XChangeWindowAttributes(theDisp,mainW,CWColormap,&xswa);
- }
- }
- newImage = (IMAGE)MyMalloc(sizeof(struct ImageStruct)); /* Successful loading of image; create a structure to... */
- if (newImage != (IMAGE)NULL) /* ...hold the new information */
- {
- NullFields(newImage);
- newImage->filename = strdup(fullname);
- newImage->format = strdup(formatStr);
- newImage->origWidth = pWIDE;
- newImage->origHeight = pHIGH;
- newImage->galleryImage = (XImage*)NULL;
- newImage->slideImage = (XImage*)NULL;
- newImage->largeImage = (XImage*)NULL;
- newImage->imageData = cpic;
- }
- if (freename) free(fullname);
- return (newImage);
-
- FAILED:
- if (strcmp(fullname,filename)!=0) unlink(filename); /* kill /tmp file */
- if (freename) free(fullname);
- return ((IMAGE)NULL);
- } /* end function openPic */
-
-
- /***********************************/
- static void FixAspect(grow,w,h)
- int grow;
- int *w, *h;
- {
- /* computes new values of eWIDE and eHIGH which will have aspect ratio
- 'normaspect'. If 'grow' it will preserve aspect by enlarging,
- otherwise, it will shrink to preserve aspect ratio.
- Returns these values in 'w' and 'h' */
-
- float xr,yr,curaspect,a,exp;
-
- *w = eWIDE; *h = eHIGH;
-
- /* xr,yr are expansion factors */
- xr = ((float) eWIDE) / cWIDE;
- yr = ((float) eHIGH) / cHIGH;
- curaspect = xr / yr;
-
- /* if too narrow & shrink, shrink height. too wide and grow, grow height */
- if ((curaspect < normaspect && !grow) ||
- (curaspect > normaspect && grow)) { /* modify height */
- exp = curaspect / normaspect;
- *h = (int) (eHIGH * exp + .5);
- }
-
- /* if too narrow & grow, grow width. too wide and shrink, shrink width */
- if ((curaspect < normaspect && grow) ||
- (curaspect > normaspect && !grow)) { /* modify width */
- exp = normaspect / curaspect;
- *w = (int) (eWIDE * exp + .5);
- }
-
-
- /* shrink to fit screen without changing aspect ratio */
- if (*w>dispWIDE) {
- int i;
- a = (float) *w / dispWIDE;
- *w = dispWIDE;
- i = (int) (*h / a + .5); /* avoid freaking some optimizers */
- *h = i;
- }
-
- if (*h>dispHIGH) {
- a = (float) *h / dispHIGH;
- *h = dispHIGH;
- *w = (int) (*w / a + .5);
- }
-
- if (*w < 1) *w = 1;
- if (*h < 1) *h = 1;
- }
-
-
- /***********************************/
-
- XImage* Resize(byte* origData,
- int origWidth, int origHeight,
- int newWidth, int newHeight)
- {
- int cy,ex,ey, *cxarrp;
- int newSize;
- byte *clptr,*elptr,*epptr;
- static int oldCxArrSize = 0;
- static int sizeOfOldImageData = 0;
- static int* cxarr = (int*)NULL;
- static byte* newImageData = (byte*)NULL;
- XImage* newXImage = (XImage*)NULL;
- char diagString[MAXPATHLEN];
-
- clptr = NULL; cxarrp = NULL; cy = 0; /* Shut up compiler */
- RANGE(newWidth,1,dispWIDE); RANGE(newHeight,1,dispHIGH); /* Force newWidth, newHeight into valid ranges */
- if (DEBUG) fprintf(stderr,"%s: Resize(%d,%d) new size=%d,%d original size=%d,%d\n",
- cmd, newWidth, newHeight, eWIDE,eHIGH,cWIDE,cHIGH);
-
- newSize = newWidth * newHeight; /* Calculate size in bytes of new image */
- if (sizeOfOldImageData < newSize) /* Is it necessary to re-allocate space? */
- { /* Yes, free up old space, allocate a larger block */
- if (newImageData != (byte*)NULL) /* Free up old space, if necessary */
- free(newImageData);
- newImageData = (byte *) MyMalloc(newSize); /* Create a new image of the appropriate size */
- if (newImageData == (byte*)NULL) /* Did the allocation fail? */
- { /* Yes, report the error. */
- sprintf(str,"unable to MyMalloc a %dx%d image\n",
- newWidth, newHeight);
- FatalError(str);
- return(XImage*)NULL;
- }
- sizeOfOldImageData = newSize; /* Update size of memory allocated for new image data */
- }
- /* the scaling routine. not really all that scary after all... */
-
- /* OPTIMIZATON IDEA. MyMalloc an eWIDE array of ints which will hold the
- values of the equation px = (pWIDE * ex) / eWIDE. Faster than doing
- a mul and a div for every point in picture */
-
- if ((cxarr == (int*)NULL) || /* Is it necessary to re-allocate space? */
- (oldCxArrSize < newWidth * sizeof(int)))
- { /* Yes, free up old space, allocate a larger block */
- sprintf(diagString, "In Resize, must allocate a cxarr of %d bytes (oldCxArrSize is %d).\n",
- newWidth * sizeof(int), oldCxArrSize);
- PrintDTDiagnostics(diagString);
- if (cxarr != (int*)NULL) /* Free up old space, if necessary */
- free(cxarr);
- cxarr = (int*) MyMalloc(newWidth * sizeof(int)); /* Create a new cxarr of the appropriate size */
- if (cxarr == (int*)NULL) /* Did the allocation fail? */
- { /* Yes, report the error. */
- sprintf(str,"unable to MyMalloc one cxarr line of size %d.\n",
- newWidth * sizeof(int));
- FatalError(str);
- return(XImage*)NULL;
- }
- oldCxArrSize = newWidth * sizeof(int); /* Update size of memory allocated for one line of image */
- }
- for (ex=0; ex < newWidth; ex++)
- cxarr[ex] = (origWidth * ex) / newWidth;
-
- elptr = epptr = newImageData;
- for (ey=0; ey < newHeight; ey++, elptr+=newWidth)
- {
- cy = (origHeight * ey) / newHeight;
- epptr = elptr;
- clptr = origData + (cy * origWidth);
- for (ex=0, cxarrp = cxarr; ex < newWidth; ex++, epptr++)
- *epptr = clptr[*cxarrp++];
- }
- newXImage = CreateXImage(newImageData, newWidth, newHeight); /* Now make something displayable out of newImageData */
- return(newXImage);
- } /* end function Resize */
-
-
-
- /************************************************/
- /* structure and routine used in SortColormap() */
- /************************************************/
-
- typedef struct thing
- { byte r,g,b;
- int oldindex;
- int use; } CMAPENT;
-
-
- static int CMAPcompare(a,b)
- CMAPENT *a,*b;
- {
- return (b->use - a->use);
- }
-
-
- /***********************************/
- void SortColormap()
- {
- byte *p;
- int i, j, k, mdist, entry, mn, d, hist[256], trans[256];
- static CMAPENT c[256], c1[256], *cp, *cj, *ck;
-
-
- /* no point doing this if we're on a 1-bit display */
- if (ncols == 0) { numcols = 256; return; }
-
- /* initialize histogram and compute it */
- for (i=0; i<256; i++) hist[i]=0;
- for (i=pWIDE*pHIGH, p=pic; i; i--, p++) hist[*p]++;
-
- if (DEBUG>1) {
- fprintf(stderr,"%s: Desired colormap\n",cmd);
- for (i=0; i<256; i++)
- if (hist[i]) fprintf(stderr,"(%3d %02x,%02x,%02x) ",
- i,r[i],g[i],b[i]);
- fprintf(stderr,"\n\n");
- }
-
-
- /* put the actually-used colors into the 'c' array in the order they occur */
- /* also, while we're at it, calculate numcols */
- for (i=numcols=0; i<256; i++) {
- if (hist[i]) {
- cp = &c[numcols++];
- cp->r = r[i]; cp->g = g[i]; cp->b = b[i];
- cp->use = hist[i]; cp->oldindex = i;
- }
- }
-
-
- /* find most-used color, put that in c1[0] */
- entry = -1; mdist = -1;
- for (i=0; i<numcols; i++) {
- if (c[i].use > mdist) { mdist = c[i].use; entry=i; }
- }
- memcpy(&c1[0], &c[entry], sizeof(CMAPENT));
- c[entry].use = 0; /* and mark it dealt with */
-
-
- /* sort rest of colormap, in order of decreasing 'distance' from already
- allocated elements.
-
- FURTHER MODIFICATION of algorithm. The algorithm's performance
- utterly goes to hell as numcols increases. (Probably on the order
- of O^3 performance). Since I don't see a clever way of rewriting
- the algorithm for O^2 performance (which'd be acceptable), I'm going
- to make a trade-off. I'll only run the algorithm for the first 32 colors
- (or so). It can do that Real Fast. Then I'll just stick the rest of
- the unsorted colors (if any), and tack them on the end, in order of
- amount of use. This should give similar picture quality, with
- much higher performance. */
-
- for (i=1; i<numcols && i<32; i++) {
- /* find the i'th most different color */
- entry = -1; mdist = -1;
- for (j=0, cj=c; j<numcols; j++,cj++) {
- if (cj->use) { /* this color has not been marked already */
- mn = 10000;
- for (k=0, ck=c1; k<i; k++,ck++) {
- d = abs(cj->r - ck->r) + abs(cj->g - ck->g) + abs(cj->b - ck->b);
- if (mn>d) mn=d;
- }
- /* mn = minimum distance from c[j] to already used colors */
- /* we want to select the unused color that has the greatest mn */
- if (mn > mdist) { mdist = mn; entry = j; }
- }
- }
-
- /* c[entry] is the next color to put in the map. do so */
- memcpy(&c1[i], &c[entry], sizeof(CMAPENT));
- c[entry].use = 0;
- }
-
- /* tack rest of colors onto colormap in decreasing order of use */
- qsort((char *) c,numcols,sizeof(CMAPENT),CMAPcompare);
- memcpy(&c1[i], c, (numcols - i) * sizeof(CMAPENT));
-
-
- /* build translation table */
- for (i=0; i<numcols; i++) trans[ c1[i].oldindex ] = i;
-
- /* modify 'pic' to reflect the new colormap */
- for (i=pWIDE*pHIGH, p=pic; i; i--, p++) { j = trans[*p]; *p = j; }
-
- /* and copy the new colormap into *the* colormap */
- for (i=0; i<numcols; i++) {
- r[i] = c1[i].r; g[i] = c1[i].g; b[i] = c1[i].b;
- }
-
- if (DEBUG>1) {
- fprintf(stderr,"%s: result of sorting colormap\n",cmd);
- for (i=0; i<numcols; i++)
- fprintf(stderr,"(%3d %02x,%02x,%02x) ",i,r[i],g[i],b[i]);
- fprintf(stderr,"\n\n");
-
- fprintf(stderr,"%s: translate table\n",cmd);
- for (i=0; i<numcols; i++)
- fprintf(stderr,"%3d->%3d ",i,trans[i]);
- fprintf(stderr,"\n\n");
- }
-
- }
-
- #define NOPIX 0xffffffff
-
- /***********************************/
- void AllocColors()
- {
- int i, j, unique, p2alloc, p3alloc;
- Colormap cmap;
- XColor defs[256];
- XColor ctab[256];
- int dc;
-
- nfcols = unique = p2alloc = p3alloc = 0;
- rwthistime = 0;
-
-
- if (ncols == 0) {
- printf("no colors allocated. Using black & white.\n");
- return;
- }
-
- /* FIRST PASS COLOR ALLOCATION:
- for each color in the 'desired colormap', try to get it via
- XAllocColor(). If for any reason it fails, mark that pixel
- 'unallocated' and worry about it later. Repeat. */
-
- /* attempt to allocate first ncols entries in colormap
- note: On displays with less than 8 bits per RGB gun, it's quite
- possible that different colors in the original picture will be
- mapped to the same color on the screen. X does this for you
- silently. However, this is not-desirable for this application,
- because when I say 'allocate me 32 colors' I want it to allocate
- 32 different colors, not 32 instances of the same 4 shades... */
-
- for (i=0; i<numcols; i++) cols[i] = NOPIX;
-
- cmap = theCmap;
- for (i=0; i<numcols && unique<ncols; i++) {
- /* printf("r%ld g%ld b%ld ", r[i], g[i], b[i]); */
- defs[i].red = r[i]<<8;
- defs[i].green = g[i]<<8;
- defs[i].blue = b[i]<<8;
- defs[i].flags = DoRed | DoGreen | DoBlue;
-
- if (XAllocColor(theDisp, cmap, &defs[i])) {
- unsigned long pixel, *fcptr;
- pixel = cols[i] = defs[i].pixel;
-
- /* see if the newly allocated color is new and different */
- for (j=0, fcptr=freecols; j<nfcols && *fcptr!=pixel; j++,fcptr++);
- if (j==nfcols) unique++;
-
- fc2pcol[nfcols] = i;
- freecols[nfcols++] = pixel;
- }
-
- else {
- /* the allocation failed. If we want 'perfect' color, and we haven't
- already created our own colormap, we'll want to do so */
- if (perfect && !LocalCmap) {
- LocalCmap = XCopyColormapAndFree(theDisp,theCmap);
- XSetWindowColormap(theDisp,mainW, LocalCmap);
- cmap = LocalCmap;
- i--; /* redo the allocation request */
- }
-
- else
- /* either we don't care about perfect color, or we do care, have
- allocated our own colormap, and have STILL run out of colors
- (possible, even on an 8 bit display), just mark pixel as
- unallocated. We'll deal with it later */
- cols[i] = NOPIX;
- }
- } /* FIRST PASS */
-
- if (nfcols==numcols && verbose) {
- if (numcols != unique)
- printf("Got all %d desired colors. (%d unique)\n", numcols,
- unique);
- else
- printf("Got all %d desired colors.\n", numcols);
-
- return;
- }
-
-
-
- /* SECOND PASS COLOR ALLOCATION:
- Allocating 'exact' colors failed. Now try to allocate 'closest'
- colors.
-
- Read entire X colormap (or first 256 entries) in from display.
- for each unallocated pixel, find the closest color that actually
- is in the X colormap. Try to allocate that color (read only).
- If that fails, the THIRD PASS will deal with it */
-
- if (verbose)
- printf("Got %d out of %d colors. (%d unique)\n",
- nfcols,numcols,unique);
-
- /* read entire colormap (or first 256 entries) into 'ctab' */
- dc = (ncells<256) ? ncells : 256;
- for (i=0; i<dc; i++) ctab[i].pixel = (unsigned long) i;
-
- XQueryColors(theDisp, cmap, ctab, dc);
-
- for (i=0; i<numcols && unique<ncols; i++)
- if (cols[i]==NOPIX) { /* an unallocated pixel */
- int d, mdist, close;
- unsigned long ri,gi,bi;
-
- mdist = 100000; close = -1;
- ri = r[i]; gi = g[i]; bi = b[i];
-
- for (j=0; j<dc; j++) {
- d = abs(ri - (ctab[j].red>>8)) +
- abs(gi - (ctab[j].green>>8)) +
- abs(bi - (ctab[j].blue>>8));
- if (d<mdist) { mdist=d; close=j; }
- }
-
- if (close<0) FatalError("This Can't Happen! (How reassuring.)");
- if (XAllocColor(theDisp, cmap, &ctab[close])) {
- memcpy(&defs[i], &ctab[close], sizeof(XColor));
- cols[i] = ctab[close].pixel;
- fc2pcol[nfcols] = i;
- freecols[nfcols++] = cols[i];
- p2alloc++;
- unique++;
- }
- }
-
-
- /* THIRD PASS COLOR ALLOCATION:
- We've alloc'ed all the colors we can. Now, we have to map any
- remaining unalloced pixels into either A) the colors that we DID get
- (noglob), or B) the colors found in the X colormap */
-
- for (i=0; i<numcols; i++) {
- if (cols[i] == NOPIX) { /* an unallocated pixel */
- int d, k, mdist, close;
- unsigned long ri,gi,bi;
-
- mdist = 100000; close = -1;
- ri = r[i]; gi = g[i]; bi = b[i];
-
- if (!noglob) { /* search the entire X colormap */
- for (j=0; j<dc; j++) {
- d = abs(ri - (ctab[j].red>>8)) +
- abs(gi - (ctab[j].green>>8)) +
- abs(bi - (ctab[j].blue>>8));
- if (d<mdist) { mdist=d; close=j; }
- }
- if (close<0) FatalError("This Can't Happen! (How reassuring.)");
- memcpy(&defs[i], &ctab[close], sizeof(XColor));
- cols[i] = defs[i].pixel;
- p3alloc++;
- }
-
- else { /* only search the alloc'd colors */
- for (j=0; j<nfcols; j++) {
- k = fc2pcol[j];
- d = abs(ri - (defs[k].red>>8)) +
- abs(gi - (defs[k].green>>8)) +
- abs(bi - (defs[k].blue>>8));
- if (d<mdist) { mdist=d; close=k; }
- }
- if (close<0) FatalError("This Can't Happen! (How reassuring.)");
- memcpy(&defs[i], &defs[close], sizeof(XColor));
- cols[i] = defs[i].pixel;
- }
- }
- } /* THIRD PASS */
-
- if (verbose)
- {
- if (p2alloc && p3alloc)
- printf("Got %d 'close' color%s. 'Borrowed' %d color%s.\n",
- p2alloc, (p2alloc>1) ? "s" : "",
- p3alloc, (p3alloc>1) ? "s" : "");
-
- else if (p2alloc && !p3alloc)
- printf("Got %d 'close' color%s.\n",
- p2alloc, (p2alloc>1) ? "s" : "");
-
- else if (!p2alloc && p3alloc)
- printf("'Borrowed' %d color%s.\n",
- p3alloc, (p3alloc>1) ? "s" : "");
- }
- }
-
-
- /***********************************/
- void DoMonoAndRV()
- {
- int i;
-
- /* operate on original colors, before any gamma correction */
- for (i=0; i<numcols; i++) {
- r[i] = rorg[i]; g[i] = gorg[i]; b[i] = borg[i];
- }
- }
-
-
-
- XImage* CreateXImage(byte* origData, int width, int height)
- {
- int i;
- byte *ip, *pp;
- static byte* imagedata = (byte*)NULL;
- byte* lip;
- int bperline, half, j;
-
- /*
- * this has to do the tricky bit of converting the data in 'origData'
- * into something usable for X.
- *
- * Algorithm notes:
- * if dispDEEP is 8, nothing has to be done other than create an
- * Ximage (ZPixmap, depth=8) and point it at the 'origData' data.
- *
- * if dispDEEP is 1, format'll be an XYBitmap, special case code
- *
- * if dispDEEP is 4, format'll be a ZPixmap, 4 or 8 bits per pixel
- *
- * if dispDEEP is 6, format'll be a ZPixmap, 8 bits per pixel
- *
- * if dispDEEP is 24 or 32, format'll be a ZPixmap. 32 bits per pixel
- *
- * any other value of dispDEEP will use a XYPixmap of the appropriate
- * depth, and some slug-like general-case code DOESN'T YET!!
- */
-
- if (DEBUG)
- fprintf(stderr,"CreateXImage: creating a %dx%d Ximage, %d bits deep\n",
- width, height, dispDEEP);
- if (!origData)
- {
- fprintf(stderr,"CreateXImage called while origData was null.\n");
- return((XImage*)NULL);
- }
-
- switch (dispDEEP)
- {
- case 8:
- imagedata = (byte *) MyMalloc(width*height); /* Try to allocate space for the actual X Image data */
- if (imagedata == (byte*)NULL)
- {
- PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
- return(XImage*)NULL;
- }
- for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++,ip++)
- {
- *ip = (byte) cols[*pp];
- }
-
- theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
- (char *) imagedata, width, height, 8, 0);
- if (!theImage) FatalError("couldn't create theImage!");
- break;
-
- /*********************************/
-
- case 1:
- theImage = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL,
- width, height, 8, 0);
- if (!theImage) FatalError("couldn't create theImage!");
- imagedata = (byte *) MyMalloc(theImage->bytes_per_line * height); /* Try to allocate space for the actual X Image data */
- if (imagedata == (byte*)NULL)
- {
- PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
- return(XImage*)NULL;
- }
- theImage->data = (char *) imagedata;
- break;
-
- /*********************************/
-
- case 4:
- theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
- width, height, 8, 0);
- if (!theImage) FatalError("couldn't create theImage!");
- bperline = theImage->bytes_per_line;
- imagedata = (byte *) MyMalloc(bperline * height); /* Try to allocate space for the actual X Image data */
- if (imagedata == (byte*)NULL)
- {
- PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
- return(XImage*)NULL;
- }
- theImage->data = (char *) imagedata;
-
- if (ncols==0)
- { /* ditherize */
- byte *dith;
-
- dith = (byte *) MyMalloc(width*height); /* Try to allocate space for the actual X Image data */
- if (dith == (byte*)NULL)
- {
- PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
- return(XImage*)NULL;
- }
- if (theImage->bits_per_pixel == 4) {
- for (i=0, pp=dith, lip=imagedata; i<height; i++, lip+=bperline)
- for (j=0, ip=lip, half=0; j<width; j++,pp++,half++) {
- if (half&1) { *ip = *ip + ((*pp&0x0f)<<4); ip++; }
- else *ip = *pp&0x0f;
- }
- }
- else if (theImage->bits_per_pixel == 8)
- memcpy(imagedata, dith, width*height);
-
- else FatalError("This display is too bizarre. Can't create XImage.");
-
- free(dith);
- }
-
- else { /* don't ditherize */
- if (theImage->bits_per_pixel == 4) {
- for (i=0, pp=origData, lip=imagedata; i<height; i++, lip+=bperline) {
- for (j=0, ip=lip, half=0; j<width; j++,pp++,half++) {
- if (half&1) { *ip = *ip + ((cols[*pp]&0x0f)<<4); ip++; }
- else *ip = cols[*pp]&0x0f;
- }
- }
- }
- else if (theImage->bits_per_pixel == 8) {
- for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++,ip++) {
- *ip = (byte) cols[*pp];
- }
- }
- else FatalError("This display's too bizarre. Can't create XImage.");
- }
- break;
-
- /*********************************/
-
- case 6:
- theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
- width, height, 8, 0);
- if (!theImage) FatalError("couldn't create theImage!");
-
- if (theImage->bits_per_pixel != 8)
- FatalError("This display's too bizarre. Can't create XImage.");
-
- bperline = theImage->bytes_per_line;
- imagedata = (byte *) MyMalloc(bperline * height); /* Try to allocate space for the actual X Image data */
- if (imagedata == (byte*)NULL)
- {
- PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
- return(XImage*)NULL;
- }
- theImage->data = (char *) imagedata;
-
- for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++,ip++) {
- *ip = (byte) cols[*pp];
- }
- break;
-
- /*********************************/
-
- case 24:
- case 32:
- imagedata = (byte *) MyMalloc(4 * width * height); /* Try to allocate space for the actual X Image data */
- if (imagedata == (byte*)NULL)
- {
- PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
- return(XImage*)NULL;
- }
- theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
- (char *) imagedata, width, height, 32, 0);
- if (!theImage) FatalError("couldn't create theImage!");
-
- if (theImage->byte_order == MSBFirst)
- for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++) {
- *ip++ = 0;
- *ip++ = (cols[*pp]>>16) & 0xff;
- *ip++ = (cols[*pp]>>8) & 0xff;
- *ip++ = cols[*pp] & 0xff;
- }
- else
- for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++) {
- *ip++ = cols[*pp] & 0xff;
- *ip++ = (cols[*pp]>>8) & 0xff;
- *ip++ = (cols[*pp]>>16) & 0xff;
- *ip++ = 0;
- }
- break;
-
- /*********************************/
-
- default:
- sprintf(str,"no code to handle this display type (%d bits deep)",
- dispDEEP);
- FatalError(str);
- break;
- }
- return(theImage);
- } /* end function CreateXImage */
-
-
-
-
- /***********************************/
- void FatalError (identifier)
- char *identifier;
- {
- fprintf(stderr, "%s: %s\n",cmd, identifier);
- }
-
-