Back to index

plt-scheme  4.2.1
wx_img.cc
Go to the documentation of this file.
00001 /*
00002  * xvmisc.c - random routines that most of the work involved in putting
00003  *            a picture on an X display.
00004  *
00005  *  Resize(w,h)    -  generates epic, new Ximage,
00006  *  SortColormap() -  sorts the desired colormap into a 'most important color
00007  *                    to allocate first' order
00008  *  AllocColors()  -  Takes the desired colormap and sees what it can do about
00009  *                    getting it.
00010  *  Rotate()       -  rotates 'pic' 90-degrees clockwise
00011  *  FloydDitherize8 - Takes epic, and produces a b/w dithered version of it,
00012  *                    stored in 8-bit per pixel format
00013  *  FloydDitherize1 - Does the same, but the output is an XYBitmap (1 bit per
00014  *                    pixel, packed 8 pixels to a byte.
00015  *  CreateXImage    - Given epic, generate an ximage of it.  Handles displays
00016  *                    of different depths.
00017  *  CenterString    - civilized string drawing routine.  uses font 'mfinfo'
00018  *  ULineString     - draws underlined string.  uses font 'mfinfo'
00019  *  StringWidth     - civilized XTextWidth width interface, uses font 'mfinfo'
00020  *  FakeButtonPress - when a keyboard equiv is hit, fakes mouse click in button
00021  *  Timer           - sleeps for a given # of milliseconds
00022  */
00023 
00024 /*
00025  * Copyright 1989, 1990 by the University of Pennsylvania
00026  *
00027  * Permission to use, copy, and distribute for non-commercial purposes,
00028  * is hereby granted without fee, providing that the above copyright
00029  * notice appear in all copies and that both the copyright notice and this
00030  * permission notice appear in supporting documentation.
00031  *
00032  * The software may be modified for your own purposes, but modified versions
00033  * may not be distributed.
00034  *
00035  * This software is provided "as is" without any express or implied warranty.
00036  */
00037 
00038 
00039 #define NEEDSTIME
00040 
00041 #include <stdlib.h>
00042 #include "wx_image.h"
00043 #include "wx_utils.h"
00044 #include "../../../src/XWidgets/wxAllocColor.h"
00045 
00046 #ifdef MZ_PRECISE_GC
00047 END_XFORM_ARITH;
00048 #endif
00049 
00050 /***********************************/
00051 void wxImage::Resize(int w, int h)
00052 {
00053   int          cy,ex,ey,*cxarr, *cxarrp;
00054   byte        *clptr,*elptr,*epptr;
00055 
00056   clptr = NULL;  cxarrp = NULL;  cy = 0;  /* shut up compiler */
00057 #if 0
00058   /* force w,h into valid ranges */
00059   RANGE(w,1,(int)dispWIDE);  RANGE(h,1,(int)dispHIGH);
00060 #endif
00061 
00062   /* if same size, and Ximage created, do nothing */
00063   if (w == (int)eWIDE && h == (int)eHIGH && theImage!=NULL) return;
00064 
00065   if (imgDEBUG) fprintf(stderr,"wxImage: Resize(%d,%d)  eSIZE=%d,%d  cSIZE=%d,%d\n",
00066                    w,h,eWIDE,eHIGH,cWIDE,cHIGH);
00067 
00068   if (w == (int)cWIDE && h == (int)cHIGH) {  /* 1:1 expansion.  point epic at cpic */
00069     if (epic != cpic && epic!=NULL) free(epic);
00070     epic = cpic;  eWIDE = cWIDE;  eHIGH = cHIGH;
00071   }
00072 
00073   else {  /* have to actually SCALE THE PIC.  Drats! */
00074 
00075     /* first, kill the old epic, if one exists */
00076     if (epic!=NULL && epic!=cpic) {
00077       free(epic);  epic = NULL;
00078     }
00079 
00080     /* create a new epic of the appropriate size */
00081     eWIDE = w;  eHIGH = h;
00082     {
00083       byte *ba;
00084       ba = (byte *)malloc(w*h);
00085       epic = ba;
00086     }
00087     if (epic==NULL) {
00088       sprintf(wxBuffer,"unable to malloc a %dx%d image\n",w,h);
00089       FatalError(wxBuffer);
00090     }
00091 
00092     /* the scaling routine.  not really all that scary after all... */
00093 
00094     /* OPTIMIZATON IDEA.  Malloc an eWIDE array of ints which will hold the
00095        values of the equation px = (pWIDE * ex) / eWIDE.  Faster than doing 
00096        a mul and a div for every point in picture */
00097 
00098     cxarr = (int *) malloc(eWIDE * sizeof(int));
00099     if (!cxarr) FatalError("unable to allocate cxarr");
00100     for (ex=0; ex < (int)eWIDE; ex++) {
00101       cxarr[ex] = (cWIDE * ex) / eWIDE;
00102     }
00103 
00104     elptr = epptr = epic;
00105     for (ey=0;  ey < (int)eHIGH;  ey++, elptr+=eWIDE) {
00106       cy = (cHIGH * ey) / eHIGH;
00107       epptr = elptr;
00108       clptr = cpic + (cy * cWIDE);
00109       for (ex=0, cxarrp = cxarr;  ex < (int)eWIDE;  ex++, epptr++) {
00110        *epptr = clptr[*cxarrp++];
00111       }
00112     }
00113     free(cxarr);
00114   }
00115 
00116   /* now make something displayable out of epic */
00117   CreateXImage();
00118 }
00119                 
00120 
00121 
00122 
00123 /************************************************/
00124 /* structure and routine used in SortColormap() */
00125 /************************************************/
00126 
00127 typedef struct thing 
00128     { byte r,g,b; 
00129       int oldindex; 
00130       int use; } CMAPENT;
00131 
00132 
00133 static int CMAPcompare(CMAPENT *a,CMAPENT *b)
00134 {
00135   return (b->use - a->use);
00136 }
00137 
00138 typedef int (*image_Compare_Proc)(const void *, const void *);
00139 
00140 /***********************************/
00141 void wxImage::SortColormap()
00142 {
00143   byte *p;
00144   int   i, j, k, mdist, entry, mn, d, hist[256], trans[256];
00145   static CMAPENT c[256], c1[256], *cp, *cj, *ck;
00146 
00147 
00148   /* no point doing this if we're on a 1-bit display */
00149   if (ncols == 0) { numcols = 256; return; }
00150   
00151   /* initialize histogram and compute it */
00152   for (i=0; i<256; i++) {
00153     hist[i]=0;
00154   }
00155   for (i=pWIDE*pHIGH, p=pic; i; i--, p++) {
00156     hist[*p]++;
00157   }
00158   
00159   if (imgDEBUG>1) {
00160     fprintf(stderr,"Desired colormap\n");
00161     for (i=0; i<256; i++) {
00162       if (hist[i]) 
00163        fprintf(stderr,"(%3d  %02x,%02x,%02x)     ",
00164               i,r[i],g[i],b[i]);
00165     }
00166     fprintf(stderr,"\n\n");
00167   }
00168 
00169   /* Is the transparent index used? */
00170   if (transparent_index >= 0) {
00171     if (!hist[transparent_index])
00172       transparent_index = -1;
00173   }
00174   
00175   /* put the actually-used colors into the 'c' array in the order they occur */
00176   /* also, while we're at it, calculate numcols */
00177   for (i=numcols=0; i<256; i++) {
00178     if (hist[i]) { 
00179       cp = &c[numcols++];
00180       cp->r = r[i];  cp->g = g[i];  cp->b = b[i];
00181       cp->use = hist[i];  cp->oldindex = i;
00182     }
00183   }
00184 
00185 
00186   /* find most-used color, put that in c1[0] */
00187   entry = -1;  mdist = -1;
00188   for (i=0; i<numcols; i++) {
00189     if (c[i].use > mdist) { mdist = c[i].use;  entry=i; }
00190   }
00191   memcpy(&c1[0], &c[entry], sizeof(CMAPENT));
00192   c[entry].use = 0;   /* and mark it dealt with */
00193   
00194   
00195   /* sort rest of colormap, in order of decreasing 'distance' from already
00196      allocated elements.
00197   
00198      FURTHER MODIFICATION of algorithm.  The algorithm's performance
00199      utterly goes to hell as numcols increases.  (Probably on the order
00200      of O^3 performance).  Since I don't see a clever way of rewriting
00201      the algorithm for O^2 performance (which'd be acceptable), I'm going
00202      to make a trade-off.  I'll only run the algorithm for the first 32 colors
00203      (or so).  It can do that Real Fast.  Then I'll just stick the rest of
00204      the unsorted colors (if any), and tack them on the end, in order of
00205      amount of use.  This should give similar picture quality, with 
00206      much higher performance. */
00207 
00208   for (i=1; i<numcols && i<32; i++) {
00209     /* find the i'th most different color */
00210     entry = -1;  mdist = -1;
00211     for (j=0, cj=c; j<numcols; j++,cj++) {
00212       if (cj->use) {  /* this color has not been marked already */
00213        mn = 10000;
00214        for (k=0, ck=c1; k<i; k++,ck++) {
00215          d = abs((int)(cj->r - ck->r)) + abs((int)(cj->g - ck->g)) + abs((int)(cj->b - ck->b));
00216          if (mn>d) mn=d;
00217        }
00218        /* mn = minimum distance from c[j] to already used colors */
00219        /* we want to select the unused color that has the greatest mn */
00220        if (mn > mdist) { mdist = mn;  entry = j; }
00221       }
00222     }
00223     
00224     /* c[entry] is the next color to put in the map.  do so */
00225     memcpy(&c1[i], &c[entry], sizeof(CMAPENT));
00226     c[entry].use = 0;
00227   }
00228   
00229   /* tack rest of colors onto colormap in decreasing order of use */
00230   qsort((char *)c, numcols, sizeof(CMAPENT), (image_Compare_Proc)CMAPcompare);
00231 
00232   memcpy(&c1[i], c, (numcols - i) * sizeof(CMAPENT));
00233 
00234 
00235   /* build translation table */
00236   for (i=0; i<numcols; i++) {
00237     trans[ c1[i].oldindex ] = i;
00238   }
00239 
00240   /* modify 'pic' to reflect the new colormap */
00241   for (i=pWIDE*pHIGH, p=pic; i; i--, p++) {
00242     *p = trans[*p];
00243   }
00244   
00245   if (transparent_index >= 0)
00246     transparent_index = trans[transparent_index];
00247   
00248   /* and copy the new colormap into *the* colormap */
00249   for (i=0; i<numcols; i++) {
00250     r[i] = c1[i].r;  g[i] = c1[i].g;  b[i] = c1[i].b;
00251   }
00252   
00253   if (imgDEBUG>1) {
00254     fprintf(stderr,"Result of sorting colormap\n");
00255     for (i=0; i<numcols; i++) {
00256       fprintf(stderr,"(%3d  %02x,%02x,%02x)     ",i,r[i],g[i],b[i]);
00257     }
00258     fprintf(stderr,"\n\n");
00259     
00260     fprintf(stderr,"Translate table\n");
00261     for (i=0; i<numcols; i++) {
00262       fprintf(stderr,"%3d->%3d  ",i,trans[i]);
00263     }
00264     fprintf(stderr,"\n\n");
00265   }
00266   
00267 }
00268 
00269 
00270 
00271 #define NOPIX 0xffffffff    
00272 
00273 /***********************************/
00274 void wxImage::AllocColors()
00275 {
00276   int      i, j, unique, p2alloc, p3alloc;
00277   Colormap cmap;
00278   XColor   defs[256];
00279   XColor   ctab[256];
00280   int      dc;
00281 
00282 
00283   nfcols = unique = p2alloc = p3alloc = 0;
00284   rwthistime = 0;
00285 
00286 
00287   if (ncols == 0) {
00288     return;
00289   }
00290 
00291 
00292   /* FIRST PASS COLOR ALLOCATION:  
00293      for each color in the 'desired colormap', try to get it via
00294      XAllocColor().  If for any reason it fails, mark that pixel
00295      'unallocated' and worry about it later.  Repeat. */
00296 
00297   /* attempt to allocate first ncols entries in colormap 
00298      note: On displays with less than 8 bits per RGB gun, it's quite
00299      possible that different colors in the original picture will be
00300      mapped to the same color on the screen.  X does this for you
00301      silently.  However, this is not-desirable for this application, 
00302      because when I say 'allocate me 32 colors' I want it to allocate
00303      32 different colors, not 32 instances of the same 4 shades... */
00304   
00305   for (i=0; i<numcols; i++) {
00306     cols[i] = NOPIX;
00307   }
00308   
00309   cmap = theCmap;
00310   for (i=0; i<numcols && unique<ncols; i++) {
00311     defs[i].red   = r[i]<<8;
00312     defs[i].green = g[i]<<8;
00313     defs[i].blue  = b[i]<<8;
00314     defs[i].flags = DoRed | DoGreen | DoBlue;
00315     
00316     if (XAllocColor(theDisp, cmap, &defs[i])) { 
00317       unsigned long pixel, *fcptr;
00318       
00319       pixel = cols[i] = defs[i].pixel;
00320       
00321       /* see if the newly allocated color is new and different */
00322       for (j=0, fcptr=freecols; j<nfcols && *fcptr!=pixel; j++,fcptr++) {
00323       }
00324       if (j==nfcols) unique++;
00325       
00326       fc2pcol[nfcols] = i;
00327       freecols[nfcols++] = pixel;
00328     }
00329 
00330     else {
00331       /* the allocation failed.  If we want 'perfect' color, and we haven't 
00332         already created our own colormap, we'll want to do so */
00333       if (perfect && !LocalCmap) {
00334        LocalCmap = XCopyColormapAndFree(theDisp,theCmap);
00335 //     XSetWindowColormap(theDisp,mainW, LocalCmap);
00336        cmap = LocalCmap;
00337        i--;     /* redo the allocation request */
00338       }
00339 
00340       else
00341        /* either we don't care about perfect color, or we do care, have
00342           allocated our own colormap, and have STILL run out of colors
00343           (possible, even on an 8 bit display), just mark pixel as
00344           unallocated.  We'll deal with it later */
00345        cols[i] = NOPIX;
00346     }
00347   }  /* FIRST PASS */
00348   
00349   
00350   
00351   if (nfcols==numcols) {
00352     return;
00353   }
00354   
00355 
00356 
00357   /* SECOND PASS COLOR ALLOCATION:
00358      Allocating 'exact' colors failed.  Now try to allocate 'closest'
00359      colors.
00360 
00361      Read entire X colormap (or first 256 entries) in from display.
00362      for each unallocated pixel, find the closest color that actually
00363      is in the X colormap.  Try to allocate that color (read only).
00364      If that fails, the THIRD PASS will deal with it */
00365 
00366   /* read entire colormap (or first 256 entries) into 'ctab' */
00367   dc = (ncells<256) ? ncells : 256;
00368   for (i=0; i<dc; i++) {
00369     ctab[i].pixel = (unsigned long) i;
00370   }
00371 
00372   XQueryColors(theDisp, cmap, ctab, dc);
00373 
00374   for (i=0; i<numcols && unique<ncols; i++) {
00375     if (cols[i]==NOPIX) {  /* an unallocated pixel */
00376       int           d, mdist, close;
00377       unsigned long ri,gi,bi;
00378 
00379       mdist = 100000;   close = -1;
00380       ri = r[i];  gi = g[i];  bi = b[i];
00381       
00382       for (j=0; j<dc; j++) {
00383        d = abs((int)(ri - (ctab[j].red>>8))) +
00384            abs((int)(gi - (ctab[j].green>>8))) +
00385            abs((int)(bi - (ctab[j].blue>>8)));
00386        if (d<mdist) { mdist=d; close=j; }
00387       }
00388 
00389       if (close<0) FatalError("This Can't Happen! (How reassuring.)");
00390       if (XAllocColor(theDisp, cmap, &ctab[close])) { 
00391        memcpy(&defs[i], &ctab[close], sizeof(XColor));
00392        cols[i] = ctab[close].pixel;
00393        fc2pcol[nfcols] = i;
00394        freecols[nfcols++] = cols[i];
00395        p2alloc++;
00396        unique++;
00397       }
00398     }
00399   }
00400 
00401 
00402   /* THIRD PASS COLOR ALLOCATION:
00403      We've alloc'ed all the colors we can.  Now, we have to map any
00404      remaining unalloced pixels into either A) the colors that we DID get
00405      (noglob), or B) the colors found in the X colormap */
00406 
00407   for (i=0; i<numcols; i++) {
00408     if (cols[i] == NOPIX) {  /* an unallocated pixel */
00409       int           d, k, mdist, close;
00410       unsigned long ri,gi,bi;
00411 
00412       mdist = 100000;   close = -1;
00413       ri = r[i];  gi = g[i];  bi = b[i];
00414       
00415       if (!noglob) {   /* search the entire X colormap */
00416        for (j=0; j<dc; j++) {
00417          d = abs((int)(ri - (ctab[j].red>>8))) +
00418              abs((int)(gi - (ctab[j].green>>8))) +
00419              abs((int)(bi - (ctab[j].blue>>8)));
00420          if (d<mdist) { mdist=d; close=j; }
00421        }
00422        if (close<0) FatalError("This Can't Happen! (How reassuring.)");
00423        memcpy(&defs[i], &ctab[close], sizeof(XColor));
00424        cols[i] = defs[i].pixel;
00425        p3alloc++;
00426       }
00427          
00428       else {                     /* only search the alloc'd colors */
00429        for (j=0; j<nfcols; j++) {
00430          k = fc2pcol[j];
00431          d = abs((int)(ri - (defs[k].red>>8))) +
00432              abs((int)(gi - (defs[k].green>>8))) +
00433              abs((int)(bi - (defs[k].blue>>8)));
00434          if (d<mdist) { mdist=d;  close=k; }
00435        }
00436        if (close<0) FatalError("This Can't Happen! (How reassuring.)");
00437        memcpy(&defs[i], &defs[close], sizeof(XColor));
00438        cols[i] = defs[i].pixel;
00439       }
00440     }
00441   }  /* THIRD PASS */
00442 }
00443 
00444 
00445 
00446 /***********************************/
00447 void wxImage::AllocRWColors()
00448 {
00449   int i,j;
00450   Colormap cmap;
00451   XColor   defs[256];
00452 
00453   nfcols = 0;   rwthistime = 1;
00454 
00455   if (ncols == 0) {
00456     rwthistime = 0;
00457     return;
00458   }
00459 
00460 
00461   cmap = theCmap;
00462 
00463   for (i=0; i<numcols; i++) {
00464     cols[i] = NOPIX;
00465   }
00466 
00467   for (i=0; i<numcols && i<ncols; i++) {
00468     unsigned long pmr[1], pix[1];
00469     if (XAllocColorCells(theDisp, cmap, False, pmr, 0, pix, 1)) {
00470       defs[i].pixel = cols[i] = pix[0];
00471       defs[i].red   = r[i]<<8;
00472       defs[i].green = g[i]<<8;
00473       defs[i].blue  = b[i]<<8;
00474       defs[i].flags = DoRed | DoGreen | DoBlue;
00475 
00476       fc2pcol[nfcols]    = i;
00477       freecols[nfcols++] = pix[0];
00478       }
00479 
00480     else {
00481       if (perfect && !LocalCmap) {
00482        LocalCmap = XCopyColormapAndFree(theDisp,theCmap);
00483 //     XSetWindowColormap(theDisp,mainW, LocalCmap);
00484        cmap = LocalCmap;
00485        i--;     /* redo the allocation request */
00486       }
00487 
00488       else cols[i] = NOPIX;
00489     }
00490   }  /* for (i=0; ... */
00491 
00492 
00493 
00494   if (nfcols==numcols) {
00495   }
00496 
00497   else {
00498     /* Failed to allocate all colors in picture.  Map remaining desired 
00499        colors into closest allocated desired colors */
00500 
00501       if (nfcols==0) {
00502        AllocColors();
00503        return;
00504       }
00505        
00506       for (i=0; i<numcols; i++) {
00507        if (cols[i]==NOPIX) {  /* an unallocated pixel */
00508          int           k, d, mdist, close;
00509          unsigned long ri,gi,bi;
00510 
00511          mdist = 100000;   close = -1;
00512          ri = r[i];  gi = g[i];  bi = b[i];
00513 
00514          for (j=0; j<nfcols; j++) {
00515            k = fc2pcol[j];
00516            d = abs((int)(ri - (defs[k].red>>8))) + abs((int)(gi - (defs[k].green>>8))) +
00517                abs((int)(bi - (defs[k].blue>>8)));
00518            if (d<mdist) { mdist=d; close=k; }
00519          }
00520 
00521          if (close<0) FatalError("This Can't Happen! (How reassuring.)");
00522          cols[i] = defs[close].pixel;
00523        }
00524       }
00525     }
00526 
00527   /* load up the allocated colorcells */
00528   for (i=0; i<nfcols; i++) {
00529     j = fc2pcol[i];
00530     defs[i].pixel = freecols[i];
00531     defs[i].red   = r[j]<<8;
00532     defs[i].green = g[j]<<8;
00533     defs[i].blue  = b[j]<<8;
00534     defs[i].flags = DoRed | DoGreen | DoBlue;
00535     /* fprintf(stderr,"StoreColors: %3d = %3d,%3d,%3d\n",
00536        defs[i].pixel,r[j],g[j],b[j]); */
00537   }
00538   XStoreColors(theDisp, cmap, defs, nfcols);
00539   XStoreColor(theDisp, cmap, &defs[0]);   /* bug in XStoreColors call */
00540 }
00541 
00542 
00543 
00544 /***********************************/
00545 void wxImage::DoMonoAndRV()
00546 {
00547   int i;
00548 
00549   /* operate on original colors, before any gamma correction */
00550   for (i=0; i<numcols; i++) {
00551     r[i] = rorg[i];  g[i] = gorg[i];  b[i] = borg[i];
00552   }
00553 
00554   if (mono || ncols==0)  /* if monochrome, mono-ify the desired colormap */
00555     for (i=0; i<numcols; i++) {
00556       r[i] = g[i] = b[i] = MONO(r[i],g[i],b[i]);
00557     }
00558 
00559   if (revvideo)  /* reverse the desired colormaps */
00560     for (i=0; i<numcols; i++) {
00561       r[i] = 255-r[i];  g[i] = 255-g[i];  b[i] = 255-b[i];
00562     }
00563 }
00564 
00565 /***********************************/
00566 #if 0
00567 void wxImage::Rotate(int dir)
00568 {
00569   int i;
00570 
00571   /* dir=0: clockwise, else counter-clockwise */
00572 
00573   RotatePic(pic, &pWIDE, &pHIGH, dir);
00574 
00575   /* rotate clipped version and modify 'clip' coords */
00576   if (cpic != pic && cpic != NULL) {
00577     if (!dir) {
00578       i = pWIDE - (cYOFF + cHIGH);      /* have to rotate offsets */
00579       cYOFF = cXOFF;
00580       cXOFF = i;
00581     }
00582     else {
00583       i = pHIGH - (cXOFF + cWIDE);
00584       cXOFF = cYOFF;
00585       cYOFF = i;
00586     }
00587     RotatePic(cpic, &cWIDE, &cHIGH,dir);
00588   }
00589   else { cWIDE = pWIDE;  cHIGH = pHIGH; }
00590 
00591   /* rotate expanded version */
00592   if (epic != cpic && epic != NULL) {
00593     RotatePic(epic, &eWIDE, &eHIGH,dir);
00594   }
00595   else { eWIDE = cWIDE;  eHIGH = cHIGH; }
00596 
00597   CreateXImage();
00598 //  WRotate();
00599 }
00600 #endif
00601 
00602 
00603 /************************/
00604 #if 0
00605 void wxImage::RotatePic(byte *pic, unsigned int *wp, unsigned int *hp, int dir)
00606 {
00607   /* rotates a w*h array of bytes 90 deg clockwise (dir=0) 
00608      or counter-clockwise (dir != 0).  swaps w and h */
00609 
00610   byte *pic1, *pix1, *pix;
00611   int          i,j;
00612   unsigned int w,h;
00613 
00614   w = *wp;  h = *hp;  
00615   pix1 = pic1 = (byte *) malloc(w*h);
00616   if (!pic1) FatalError("Not enough memory to rotate!");
00617 
00618   /* do the rotation */
00619   if (dir==0) {
00620     for (i=0; i < (int)w; i++) {        /* CW */
00621       for (j=h-1, pix=pic+(h-1)*w + i; j>=0; j--, pix1++, pix-=w) {
00622        *pix1 = *pix;
00623       }
00624     }
00625   }
00626   else {
00627     for (i=w-1; i>=0; i--) {     /* CCW */
00628       for (j=0, pix=pic+i; j < (int)h; j++, pix1++, pix+=w) {
00629        *pix1 = *pix;
00630       }
00631     }
00632   }
00633 
00634 
00635   /* copy the rotated buffer into the original buffer */
00636   memcpy(pic, pic1, w*h);
00637 
00638   free(pic1);
00639 
00640   /* swap w and h */
00641   *wp = h;  *hp = w;
00642 }
00643 #endif
00644   
00645 
00646 /************************/
00647 void wxImage::FloydDitherize8(byte *image)
00648 {
00649   /* takes epic, and builds a black&white dithered version of it.
00650      stores result in 8bit Pixmap format in 'image' */
00651 
00652   int i;
00653   byte *p;
00654 
00655   FSDither(epic, eWIDE, eHIGH, image);
00656 
00657   /* set to 'black' and 'white' instead of '0' and '1' */
00658   if (black != 0 || white != 1) {
00659     for (i=eWIDE*eHIGH, p=image; i>0; i--, p++) {
00660       if (*p) *p = white;  else *p = black;
00661     }
00662   }
00663 }
00664 
00665 
00666 
00667 /************************/
00668 void wxImage::FloydDitherize1(XImage * /* ximage */)
00669 {
00670   /* same as FloydDitherize8, but output is a 1-bit per pixel XYBitmap,
00671      packed 8 pixels per byte */
00672 
00673   register short *dp;
00674   register byte   pix8, bit;
00675   short          *dithpic;
00676   int             i, j, err, bperln, order;
00677   byte           *pp, *image, w, blck, w8, b8;
00678 
00679 
00680   image  = (byte *) theImage->data;
00681   bperln = theImage->bytes_per_line;
00682   order  = theImage->bitmap_bit_order;
00683 
00684   if (imgDEBUG) fprintf(stderr,"Ditherizing1...");
00685 
00686   dithpic = (short *) malloc(eWIDE * eHIGH * sizeof(short));
00687   if (dithpic == NULL) FatalError("not enough memory to ditherize");
00688 
00689   w = white&0x1;  blck=black&0x1;
00690   w8 = w<<7;  b8 = blck<<7;        /* b/w bit in high bit */
00691   
00692   /* copy r[epic] into dithpic so that we can run the algorithm */
00693   pp = epic;  dp = dithpic;
00694   for (i=eHIGH * eWIDE; i>0; i--) {
00695     *dp++ = fsgamcr[r[*pp++]];
00696   }
00697 
00698   dp = dithpic;
00699   pp = image;
00700 
00701   for (i=0; i<(int)eHIGH; i++) {
00702     pp = image + i*bperln;
00703 
00704     if (order==LSBFirst) {
00705       bit = pix8 = 0;
00706       for (j=0; j<(int)eWIDE; j++,dp++) {
00707        if (*dp<128) { err = *dp;     pix8 |= b8; }
00708                else { err = *dp-255; pix8 |= w8; }
00709 
00710        if (bit==7) {
00711          *pp++ = pix8;  bit=pix8=0;
00712        }
00713        else { pix8 >>= 1;  bit++; }
00714 
00715        if (j < (int)eWIDE-1) dp[1] += ((err*7)/16);
00716 
00717        if (i < (int)eHIGH-1) {
00718          dp[eWIDE] += ((err*5)/16);
00719          if (j > 0)       dp[eWIDE-1] += ((err*3)/16);
00720          if (j < (int)eWIDE-1) dp[eWIDE+1] += (err/16);
00721        }
00722       }
00723       if (bit) *pp++ = pix8>>(7-bit);  /* write partial byte at end of line */
00724     }
00725 
00726     else {   /* order==MSBFirst */
00727       bit = pix8 = 0;
00728       for (j=0; j < (int)eWIDE; j++,dp++) {
00729        if (*dp<128) { err = *dp;     pix8 |= blck; }
00730                else { err = *dp-255; pix8 |= w; }
00731 
00732        if (bit==7) {
00733          *pp++ = pix8;  bit=pix8=0;
00734        }
00735        else { pix8 <<= 1; bit++; }
00736 
00737        if (j < (int)eWIDE-1) dp[1] += ((err*7)/16);
00738 
00739        if (i < (int)eHIGH-1) {
00740          dp[eWIDE] += ((err*5)/16);
00741          if (j>0)       dp[eWIDE-1] += ((err*3)/16);
00742          if (j < (int)eWIDE-1) dp[eWIDE+1] += (err/16);
00743        }
00744       }
00745       if (bit) *pp++ = pix8<<(7-bit);  /* write partial byte at end of line */
00746     }
00747   }
00748 
00749   if (imgDEBUG) fprintf(stderr,"done\n");
00750 
00751   free(dithpic);
00752 }
00753 
00754 
00755 
00756 /************************/
00757 void wxImage::FSDither(byte *inpic, int w, int h, byte *outpic)
00758 {
00759   /* takes inpic, and builds a black&white dithered version of it.
00760      stores result as 1 byte per pixel format in 'image'
00761      black = 0;  white = 1;
00762      temporarily mallocs a w*h array of SHORTS.
00763      (need to be signed, also to avoid overflow problems.)  */
00764 
00765   /* floyd-steinberg dithering.
00766    *
00767    * ----   x    7/16
00768    * 3/16  5/16  1/16
00769    *
00770    */
00771 
00772   short *dp, *dithpic;
00773   int    i, j, err, w1, h1;
00774   byte  *pp, rgb[256];
00775 
00776   if (imgDEBUG) fprintf(stderr,"Ditherizing...");
00777 
00778   /* first thing to do is build rgb[], which will hold the B/W intensity
00779      of the colors in the r,g,b arrays */
00780   for (i=0; i<256; i++) {
00781     rgb[i] = MONO(r[i], g[i], b[i]);
00782   }
00783 
00784 
00785   dithpic = (short *) malloc(w*h * sizeof(short));
00786   if (dithpic == NULL) FatalError("not enough memory to ditherize");
00787 
00788   w1 = w-1;  h1 = h-1;
00789 
00790   /* copy rgb[inpic] into dithpic so that we can run the algorithm */
00791   pp = inpic;  dp = dithpic;
00792   for (i=w*h; i>0; i--) {
00793     *dp++ = fsgamcr[rgb[*pp++]];
00794   }
00795 
00796   dp = dithpic;  pp = outpic;
00797   for (i=0; i<h; i++) {
00798     for (j=0; j<w; j++,dp++,pp++) {
00799       if (*dp<128) { err = *dp;     *pp = 0; }
00800               else { err = *dp-255; *pp = 1; }
00801 
00802       if (j<w1) dp[1] += ((err*7)/16);
00803 
00804       if (i<h1) {
00805         dp[w] += ((err*5)/16);
00806         if (j>0)  dp[w1] += ((err*3)/16);
00807         if (j<w1) dp[w+1] += (err/16);
00808       }
00809     }
00810   }
00811 
00812   if (imgDEBUG) fprintf(stderr,"done\n");
00813 
00814   free(dithpic);
00815 }
00816 
00817 /***********************************/
00818 void wxImage::CreateXImage()
00819 {
00820   /*
00821    * this has to do the tricky bit of converting the data in 'epic'
00822    * into something usable for X.
00823    *
00824    * Algorithm notes:
00825    *   if dispDEEP is 8, nothing has to be done other than create an
00826    *      Ximage (ZPixmap, depth=8) and point it at the 'epic' data.
00827    *
00828    *   if dispDEEP is 1, format'll be an XYBitmap, special case code
00829    *   
00830    *   if dispDEEP is 4, format'll be a ZPixmap, 4 or 8 bits per pixel
00831    *
00832    *   if dispDEEP is 6, format'll be a ZPixmap, 8 bits per pixel
00833    *
00834    *   if dispDEEP is 16, format'll be a ZPixmap.  16 bits per pixel
00835    *
00836    *   if dispDEEP is 24, format'll be a ZPixmap.  24 bits per pixel
00837    *
00838    *   if dispDEEP is 32, format'll be a ZPixmap.  32 bits per pixel
00839    *
00840    *   any other value of dispDEEP will use a XYPixmap of the appropriate
00841    *   depth, and some slug-like general-case code  DOESN'T YET!!
00842    */
00843 
00844   if (imgDEBUG) 
00845     fprintf(stderr,"Creating a %dx%d Ximage, %d bits deep\n",
00846            eWIDE, eHIGH, dispDEEP);
00847 
00848   /* destroy old image and imagedata, if there is one */
00849   if (theImage) xvDestroyImage(theImage);
00850   theImage = NULL;
00851 
00852   if (!epic) {
00853     /* fprintf(stderr,"CreateXImage called while epic was null\n"); */
00854     Resize(eWIDE,eHIGH);
00855     return;
00856   }
00857 
00858   if (transparent_index >= 0) {
00859     byte *pp = epic;
00860     int i, j;
00861 
00862     theMask = wxiAllocMask(eWIDE, eHIGH);
00863     for (j = 0; j < (int)eHIGH; j++) {
00864       for (i = 0; i < (int)eWIDE; i++, pp++) {
00865        if (*pp == transparent_index)
00866          wxiSetMask(theMask, i, j, 0);
00867        else
00868          wxiSetMask(theMask, i, j, 1);
00869       }
00870     }
00871   }  
00872 
00873   if (numcols)
00874   switch (dispDEEP) 
00875     {
00876     case 8:
00877       {
00878       byte  *imagedata, *ip, *pp;
00879       int i;
00880 
00881       imagedata = (byte *) malloc(eWIDE*eHIGH);
00882       if (!imagedata) FatalError("couldn't malloc imagedata");
00883       
00884       if (ncols==0) FloydDitherize8(imagedata);
00885       else {
00886        for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) {
00887          *ip = (byte) cols[*pp];
00888        }
00889       }
00890 
00891       theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
00892                            (char *) imagedata, eWIDE, eHIGH, 8, 0);
00893       if (!theImage) FatalError("couldn't create theImage!");
00894       }
00895 
00896     return;
00897 
00898     /*********************************/
00899 
00900     case 1:
00901       {
00902       byte  *imagedata;
00903 
00904       theImage = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL, 
00905                            eWIDE, eHIGH, 8, 0);
00906       if (!theImage) FatalError("couldn't create theImage!");
00907       imagedata = (byte *) malloc(theImage->bytes_per_line * eHIGH);
00908       if (!imagedata) FatalError("couldn't malloc imagedata");
00909       theImage->data = (char *) imagedata;
00910       FloydDitherize1(theImage);
00911       }
00912 
00913     return;
00914       
00915     /*********************************/
00916       
00917     case 4: {
00918       byte  *imagedata, *ip, *pp;
00919       byte *lip;
00920       int  bperline, half, j, i;
00921 
00922       theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, 
00923                            eWIDE, eHIGH, 8, 0);
00924       if (!theImage) {
00925        // FatalError("couldn't create theImage!");
00926        return;
00927       }
00928 
00929       bperline = theImage->bytes_per_line;
00930       imagedata = (byte *) malloc(bperline * eHIGH);
00931       if (!imagedata) FatalError("couldn't malloc imagedata");
00932       theImage->data = (char *) imagedata;
00933 
00934       if (ncols==0) {            /* ditherize */
00935        byte *dith;
00936        dith = (byte *) malloc(eWIDE * eHIGH);
00937        if (!dith) FatalError("can't create dithered image");
00938        FloydDitherize8(dith);
00939 
00940        if (theImage->bits_per_pixel == 4) {
00941          for (i=0, pp=dith, lip=imagedata; i < (int)eHIGH; i++, lip+=bperline) {
00942            for (j=0, ip=lip, half=0; j < (int)eWIDE; j++,pp++,half++) {
00943              if (half&1) { *ip = *ip + ((*pp&0x0f)<<4);  ip++; }
00944              else *ip = *pp&0x0f;
00945            }
00946          }
00947        }
00948        else if (theImage->bits_per_pixel == 8)
00949          memcpy(imagedata, dith, eWIDE*eHIGH);
00950        
00951        else {
00952          // FatalError("This display is too bizarre.  Can't create XImage.");
00953          theImage = NULL;
00954          return;
00955        }
00956 
00957        free(dith);
00958       }
00959 
00960       else {     /* don't ditherize */
00961        if (theImage->bits_per_pixel == 4) {
00962          for (i=0, pp=epic, lip=imagedata; i < (int)eHIGH; i++, lip+=bperline) {
00963            for (j=0, ip=lip, half=0; j < (int)eWIDE; j++,pp++,half++) {
00964              if (half&1) { *ip = *ip + ((cols[*pp]&0x0f)<<4);  ip++; }
00965              else *ip = cols[*pp]&0x0f;
00966            }
00967          }
00968        }
00969        else if (theImage->bits_per_pixel == 8) {
00970          for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) {
00971            *ip = (byte) cols[*pp];
00972          }
00973        }
00974        else {
00975          theImage = NULL;
00976          return;
00977          // FatalError("This display's too bizarre.  Can't create XImage.");
00978        }
00979       }
00980       
00981       }
00982 
00983     return;
00984       
00985     /*********************************/
00986       
00987     case 6: {
00988       byte  *imagedata, *ip, *pp;
00989       int  bperline, i;
00990 
00991       theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, 
00992                            eWIDE, eHIGH, 8, 0);
00993       if (!theImage) {
00994        return;
00995        // FatalError("couldn't create theImage!");
00996       }
00997 
00998       if (theImage->bits_per_pixel != 8) {
00999        theImage = NULL;
01000        return;
01001        // FatalError("This display's too bizarre.  Can't create XImage.");
01002       }
01003 
01004       bperline = theImage->bytes_per_line;
01005       imagedata = (byte *) malloc(bperline * eHIGH);
01006       if (!imagedata) FatalError("couldn't malloc imagedata");
01007       theImage->data = (char *) imagedata;
01008 
01009       if (ncols==0) FloydDitherize8(imagedata);
01010       else {
01011        for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) {
01012          *ip = (byte) cols[*pp];
01013        }
01014       }
01015       
01016       }
01017     return;
01018       
01019     }
01020 
01021   theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0,
01022                        NULL, eWIDE, eHIGH, 8, 0);
01023   {
01024     char *data;
01025     data = (char *)malloc(eHIGH * theImage->bytes_per_line);
01026     theImage->data = data;
01027   }
01028 
01029   {
01030     byte *pp = epic;
01031     int i, j;
01032     unsigned long wite;
01033     wite = WhitePixelOfScreen(DefaultScreenOfDisplay(theDisp));
01034     
01035     for (j = 0; j < (int)eHIGH; j++) {
01036       for (i = 0; i < (int)eWIDE; i++, pp++) {
01037        unsigned long pixel;
01038        if (numcols)
01039          pixel = cols[*pp];
01040        else {
01041          XColor c;
01042 
01043          c.red   = (*pp++)<<8;
01044          c.green = (*pp++)<<8;
01045          c.blue  = (*pp)<<8;
01046          c.flags = DoRed | DoGreen | DoBlue;
01047        
01048          if (wxAllocColor(theDisp, theCmap, &c))
01049            pixel = c.pixel;
01050          else
01051            pixel = wite;
01052        }
01053 
01054        XPutPixel(theImage, i, j, pixel);
01055       }
01056     }
01057   }
01058 }
01059 
01060 /***********************************/
01061 void wxImage::FatalError (char *identifier)
01062 {
01063   fprintf(stderr, "wxImage: %s\n", identifier);
01064   exit(-1);
01065 }
01066 
01067 /***********************************/
01068 void wxImage::FreeMostResources()
01069 {
01070   /* called when the program exits.  frees everything explictly created
01071      EXCEPT allocated colors.  This is used when 'useroot' is in operation,
01072      as we have to keep the alloc'd colors around, but we don't want anything
01073      else to stay */
01074 
01075   if (!theDisp) return;   /* called before connection opened */
01076 
01077   XFlush(theDisp);
01078 }
01079 
01080 void xvDestroyImage(XImage *image)
01081 {
01082   /* called in place of XDestroyImage().  Explicitly destroys *BOTH* the
01083      data and the structure.  XDestroyImage() doesn't seem to do this on all
01084      systems.  Also, can be called with a NULL image pointer */
01085 
01086   if (image) {
01087     /* free data by hand, since XDestroyImage is vague about it */
01088     if (image->data) free(image->data);
01089     image->data = NULL;
01090     XDestroyImage(image);
01091   }
01092 }
01093 
01094 void xvbzero(char *s, int len)
01095 {
01096   for ( ; len>0; len--) {
01097     *s++ = 0;
01098   }
01099 }