This is xvimage.c in view mode; [Download] [Up]
/* * xvimage.c - image manipulation functions (crop,resize,rotate...) for XV * * Author: John Bradley, University of Pennsylvania * (bradley@cis.upenn.edu) * * Contains: * void Resize(int, int) * void GenerateEpic(w,h) * void Crop() * void UnCrop() * void AutoCrop() * void DoCrop(x,y,w,h) * void Rotate(int) * void RotatePic(); * void InstallNewPic(void); * void DrawEpic(void); * byte *FSDither() * void CreateXImage() * void Set824Menus( pictype ); * void Change824Mode( pictype ); * void ConvertPics824(oldtype, newtype); * */ /* Copyright Notice * ================ * Copyright 1989, 1990, 1991, 1992, 1993 by John Bradley * * Permission to use, copy, and distribute XV in its entirety, for * non-commercial purposes, is hereby granted without fee, provided that * this license information and copyright notice appear in all copies. * * Note that distributing XV 'bundled' in with ANY product is considered * to be a 'commercial purpose'. * * Also note that any copies of XV that are distributed MUST be built * and/or configured to be in their 'unregistered copy' mode, so that it * is made obvious to the user that XV is shareware, and that they should * consider donating, or at least reading this License Info. * * The software may be modified for your own purposes, but modified * versions may NOT be distributed without prior consent of the author. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author be held liable for any damages * arising from the use of this software. * * If you would like to do something with XV that this copyright * prohibits (such as distributing it with a commercial product, * using portions of the source in some other program, etc.), please * contact the author (preferably via email). Arrangements can * probably be worked out. * * XV is shareware for PERSONAL USE only. You may use XV for your own * amusement, and if you find it nifty, useful, generally cool, or of * some value to you, your non-deductable donation would be greatly * appreciated. $25 is the suggested donation, though, of course, * larger donations are quite welcome. Folks who donate $25 or more * can receive a Real Nice bound copy of the XV manual for no extra * charge. * * Commercial, government, and institutional users MUST register their * copies of XV, for the exceedingly REASONABLE price of just $25 per * workstation/X terminal. Site licenses are available for those who * wish to run XV on a large number of machines. Contact the author * for more details. * * The author may be contacted via: * US Mail: John Bradley * 1053 Floyd Terrace * Bryn Mawr, PA 19010 * * Phone: (215) 898-8813 * EMail: bradley@cis.upenn.edu */ #include "xv.h" #ifdef __STDC__ static void do_zoom(int, int); static void compute_zoom_crop(int, int); static void do_unzoom(void); static void crop1(int, int, int, int, int); static int doAutoCrop24(void); static void FloydDitherize1(XImage *, byte *, int, int, int, byte *, byte *,byte *); static int highbit(unsigned long); #else static void do_zoom(), compute_zoom_crop(), do_unzoom(); static void crop1(); static int doAutoCrop24(); static void FloydDitherize1(); static int highbit(); #endif #define DO_CROP 0 #define DO_ZOOM 1 /***********************************/ void Resize(w,h) int w,h; { static char *rstr = "Resizing Image. Please wait..."; RANGE(w,1,maxWIDE); RANGE(h,1,maxHIGH); if (psUp) PSResize(); /* if PSDialog is open, mention size change */ /* if same size, and Ximage created, do nothing */ if (w==eWIDE && h==eHIGH && theImage!=NULL) return; if (DEBUG) fprintf(stderr,"Resize(%d,%d) eSIZE=%d,%d cSIZE=%d,%d\n", w,h,eWIDE,eHIGH,cWIDE,cHIGH); BTSetActive(&but[BCROP],0); SetCropString(but[BCROP].active); if (epicMode == EM_SMOOTH) { /* turn off smoothing */ epicMode = EM_RAW; SetEpicMode(); } GenerateEpic(w,h); CreateXImage(); } /***********************************/ void GenerateEpic(w,h) int w,h; { int cy,ex,ey,*cxarr, *cxarrp; byte *clptr,*elptr,*epptr; WaitCursor(); clptr = NULL; cxarrp = NULL; cy = 0; /* shut up compiler */ SetISTR(ISTR_EXPAND, "%.5g%% x %.5g%% (%d x %d)", 100.0 * ((float) w) / cWIDE, 100.0 * ((float) h) / cHIGH, w, h); if (DEBUG) fprintf(stderr,"GenerateEpic(%d,%d) eSIZE=%d,%d cSIZE=%d,%d epicode=%d\n", w,h,eWIDE,eHIGH,cWIDE,cHIGH, epicMode); FreeEpic(); /* get rid of the old one */ eWIDE = w; eHIGH = h; if (epicMode == EM_SMOOTH) { if (picType == PIC8) { epic = SmoothResize(cpic, cWIDE, cHIGH, eWIDE, eHIGH, rMap,gMap,bMap, rdisp,gdisp,bdisp, numcols); } else { /* PIC24 */ epic = Smooth24(cpic, 1, cWIDE, cHIGH, eWIDE, eHIGH, NULL, NULL, NULL); } if (epic) return; /* success */ else { /* failed. Try to generate a *raw* image, at least... */ epicMode = EM_RAW; SetEpicMode(); /* fall through to rest of code */ } } /* generate a 'raw' epic, as we'll need it for ColorDither if EM_DITH */ if (eWIDE==cWIDE && eHIGH==cHIGH) { /* 1:1 expansion. point epic at cpic */ epic = cpic; } else { /* run the rescaling algorithm */ int bperpix; bperpix = (picType == PIC8) ? 1 : 3; WaitCursor(); /* create a new epic of the appropriate size */ epic = (byte *) malloc(eWIDE * eHIGH * bperpix); if (!epic) FatalError("GenerateEpic(): unable to malloc 'epic'"); /* the scaling routine. not really all that scary after all... */ /* OPTIMIZATON: Malloc 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 */ cxarr = (int *) malloc(eWIDE * sizeof(int)); if (!cxarr) FatalError("unable to allocate cxarr"); for (ex=0; ex<eWIDE; ex++) cxarr[ex] = bperpix * ((cWIDE * ex) / eWIDE); elptr = epptr = epic; for (ey=0; ey<eHIGH; ey++, elptr+=(eWIDE*bperpix)) { if ((ey&127) == 0) WaitCursor(); cy = (cHIGH * ey) / eHIGH; epptr = elptr; clptr = cpic + (cy * cWIDE * bperpix); if (bperpix == 1) { for (ex=0, cxarrp = cxarr; ex<eWIDE; ex++, epptr++) *epptr = clptr[*cxarrp++]; } else { int j; byte *cp; for (ex=0, cxarrp = cxarr; ex<eWIDE; ex++,cxarrp++) { cp = clptr + *cxarrp; for (j=0; j<bperpix; j++) *epptr++ = *cp++; } } } free(cxarr); } /* at this point, we have a raw epic. Potentially dither it */ if (picType == PIC8 && epicMode == EM_DITH) { byte *tmp; tmp = DoColorDither(NULL, epic, eWIDE, eHIGH, rMap,gMap,bMap, rdisp,gdisp,bdisp, numcols); if (tmp) { /* success */ FreeEpic(); epic = tmp; } else { /* well... just use the raw image. */ epicMode = EM_RAW; SetEpicMode(); } } } /***********************************/ void DoZoom(x,y,button) int x,y,button; { if (button == Button1) do_zoom(x,y); else if (button == Button3) do_unzoom(); else XBell(theDisp,0); } /***********************************/ static void do_zoom(mx,my) int mx,my; { int i,w,h,x,y,x2,y2,ox,oy; /* if there's already a cropping rectangle drawn, turn it off */ if (but[BCROP].active) InvCropRect(); ox = mx; oy = my; compute_zoom_crop(mx,my); InvCropRect(); /* track until Button1 is released */ while (1) { Window rW, cW; unsigned int mask; int rx, ry; if (XQueryPointer(theDisp, mainW, &rW, &cW, &rx, &ry, &mx, &my, &mask)) { if (!(mask & Button1Mask)) break; /* button released */ if (mx!=ox || my!=oy) { InvCropRect(); compute_zoom_crop(mx,my); InvCropRect(); ox = mx; oy = my; } } } for (i=0; i<6; i++) { InvCropRect(); XFlush(theDisp); Timer(150); } /* figure out what the crop rectangles coordinates are in pic coordinates */ x = cXOFF + (crx1 * cWIDE) / eWIDE; y = cYOFF + (cry1 * cHIGH) / eHIGH; x2 = cXOFF + (crx2 * cWIDE) / eWIDE; y2 = cYOFF + (cry2 * cHIGH) / eHIGH; w = (x2 - x); h = (y2 - y); if (w<1) w = 1; if (x+w > pWIDE) w = pWIDE - x; if (h<1) h = 1; if (y+h > pHIGH) h = pHIGH - y; crop1(x,y,w,h, DO_ZOOM); } /***********************************/ static void compute_zoom_crop(x,y) int x,y; { int w,h; w = eWIDE/2; h = eHIGH/2; crx1 = x - w/2; cry1 = y - h/2; if (crx1 < 0) crx1 = 0; if (cry1 < 0) cry1 = 0; if (crx1 > eWIDE-w) crx1 = eWIDE-w; if (cry1 > eHIGH-h) cry1 = eHIGH-h; crx2 = crx1 + w; cry2 = cry1 + h; } /***********************************/ static void do_unzoom() { int x,y,w,h; /* compute a cropping rectangle (in screen coordinates) that's twice the size of eWIDE,eHIGH, centered around eWIDE/2, eHIGH/2, but no larger than pWIDE,PHIGH */ if (!but[BUNCROP].active) { /* not cropped, can't zoom out */ XBell(theDisp, 0); return; } crx1 = -eWIDE/2; cry1 = -eHIGH/2; /* figure out what the crop rectangles coordinates are in pic coordinates */ x = cXOFF + (crx1 * cWIDE - (eWIDE/2)) / eWIDE; y = cYOFF + (cry1 * cHIGH - (eHIGH/2)) / eHIGH; w = cWIDE*2; h = cHIGH*2; RANGE(w, 1, pWIDE); RANGE(h, 1, pHIGH); if (x<0) x = 0; if (y<0) y = 0; if (x+w > pWIDE) x = pWIDE - w; if (y+h > pHIGH) y = pHIGH - h; crop1(x,y,w,h, DO_ZOOM); } /***********************************/ void Crop() { int i, x, y, x2, y2, w, h; if (!but[BCROP].active) return; /* turn off the cropping rectangle */ InvCropRect(); BTSetActive(&but[BCROP],0); /* sort crx1,crx2,cry1,cry2 so that crx1,cry1 are top left corner */ if (crx1>crx2) { i = crx1; crx1 = crx2; crx2 = i; } if (cry1>cry2) { i = cry1; cry1 = cry2; cry2 = i; } /* see if cropping to same size, in which case do nothing */ if (crx2-crx1 == eWIDE && cry2-cry1 == eHIGH) return; /* figure out what the crop rectangles coordinates are in pic coordinates */ x = cXOFF + (crx1 * cWIDE) / eWIDE; y = cYOFF + (cry1 * cHIGH) / eHIGH; x2 = cXOFF + (crx2 * cWIDE) / eWIDE; y2 = cYOFF + (cry2 * cHIGH) / eHIGH; w = (x2 - x) + 1; h = (y2 - y) + 1; if (w<1) w = 1; if (x+w > pWIDE) w = pWIDE - x; if (h<1) h = 1; if (y+h > pHIGH) h = pHIGH - y; crop1(x,y,w,h,DO_CROP); } /**********************************/ static void crop1(x,y,w,h,zm) int x,y,w,h,zm; { int i,j,oldew,oldeh; byte *cp, *pp; oldew = eWIDE; oldeh = eHIGH; DoCrop(x,y,w,h); if (zm == DO_ZOOM) { eWIDE = oldew; eHIGH = oldeh; } GenerateEpic(eWIDE, eHIGH); if (useroot) DrawEpic(); else { if (zm == DO_CROP) { WCrop(eWIDE, eHIGH); /* shrink window */ CreateXImage(); } else DrawEpic(); } SetCursors(-1); } /***********************************/ void UnCrop() { int w,h; if (cpic == pic) return; /* not cropped */ BTSetActive(&but[BUNCROP],0); if (epicMode == EM_SMOOTH) { /* turn off smoothing */ epicMode = EM_RAW; SetEpicMode(); } /* dispose of old cpic and epic */ FreeEpic(); if (cpic && cpic != pic) free(cpic); cpic = NULL; w = (pWIDE * eWIDE) / cWIDE; h = (pHIGH * eHIGH) / cHIGH; if (w>maxWIDE || h>maxHIGH) { /* return to 'normal' size */ if (pWIDE>maxWIDE || pHIGH>maxHIGH) { double r,wr,hr; wr = ((double) pWIDE) / maxWIDE; hr = ((double) pHIGH) / maxHIGH; r = (wr>hr) ? wr : hr; /* r is the max(wr,hr) */ w = (int) ((pWIDE / r) + 0.5); h = (int) ((pHIGH / r) + 0.5); } else { w = pWIDE; h = pHIGH; } } cpic = pic; cXOFF = cYOFF = 0; cWIDE = pWIDE; cHIGH = pHIGH; /* generate an appropriate 'epic' */ GenerateEpic(w,h); CreateXImage(); WUnCrop(); SetCropString(but[BCROP].active); } /***********************************/ void AutoCrop() { /* called when AutoCrop button is pressed */ if (DoAutoCrop()) { if (useroot) DrawEpic(); else { CreateXImage(); WCrop(eWIDE, eHIGH); } } SetCursors(-1); } /***********************************/ int DoAutoCrop() { /* returns '1' if any cropping was actually done. */ byte *cp, *cp1; int i, ctop, cbot, cleft, cright, bperpix; byte bgcol; ctop = cbot = cleft = cright = 0; bperpix = (picType == PIC8) ? 1 : 3; if (picType == PIC24) return( doAutoCrop24() ); /* crop the top */ cp = cpic; bgcol = cp[0]; while (ctop+1 < cHIGH) { /* see if we can delete this line */ for (i=0, cp1=cp; i<cWIDE && *cp1==bgcol; i++, cp1++); if (i==cWIDE) { cp += cWIDE; ctop++; } else break; } /* crop the bottom */ cp = cpic + (cHIGH-1) * cWIDE; bgcol = cp[0]; while (ctop + cbot + 1 < cHIGH) { /* see if we can delete this line */ for (i=0, cp1=cp; i<cWIDE && *cp1==bgcol; i++,cp1++); if (i==cWIDE) { cp -= cWIDE; cbot++; } else break; } /* crop the left side */ cp = cpic; bgcol = cp[0]; while (cleft + 1 < cWIDE) { /* see if we can delete this line */ for (i=0, cp1=cp; i<cHIGH && *cp1==bgcol; i++, cp1 += cWIDE); if (i==cHIGH) { cp++; cleft++; } else break; } /* crop the right side */ cp = cpic + cWIDE-1; bgcol = cp[0]; while (cleft + cright + 1 < cWIDE) { /* see if we can delete this line */ for (i=0, cp1=cp; i<cHIGH && *cp1==bgcol; i++, cp1 += cWIDE); if (i==cHIGH) { cp--; cright++; } else break; } /* do the actual cropping */ if (cleft || ctop || cbot || cright) { DoCrop(cXOFF+cleft, cYOFF+ctop, cWIDE-(cleft+cright), cHIGH-(ctop+cbot)); return 1; } return 0; } /***********************************/ static int doAutoCrop24() { /* returns '1' if any cropping was actually done */ byte *cp, *cp1; int i, ctop, cbot, cleft, cright; byte bgR, bgG, bgB; ctop = cbot = cleft = cright = 0; if (picType != PIC24) FatalError("doAutoCrop24 called when pic!=PIC24"); /* crop the top */ cp = cpic; bgR = cp[0]; bgG = cp[1]; bgB = cp[2]; while (ctop+1 < cHIGH) { /* see if we can delete this line */ for (i=0, cp1=cp; i<cWIDE && cp1[0]==bgR && cp1[1]==bgG && cp1[2]==bgB; i++, cp1+=3); if (i==cWIDE) { cp += cWIDE*3; ctop++; } else break; } /* crop the bottom */ cp = cpic + (cHIGH-1) * cWIDE*3; bgR = cp[0]; bgG = cp[1]; bgB = cp[2]; while (ctop + cbot + 1 < cHIGH) { /* see if we can delete this line */ for (i=0, cp1=cp; i<cWIDE && cp1[0]==bgR && cp1[1]==bgG && cp1[2]==bgB; i++, cp1+=3); if (i==cWIDE) { cp -= cWIDE*3; cbot++; } else break; } /* crop the left side */ cp = cpic; bgR = cp[0]; bgG = cp[1]; bgB = cp[2]; while (cleft + 1 < cWIDE) { /* see if we can delete this line */ for (i=0, cp1=cp; i<cHIGH && cp1[0]==bgR && cp1[1]==bgG && cp1[2]==bgB; i++, cp1 += (cWIDE * 3)); if (i==cHIGH) { cp+=3; cleft++; } else break; } /* crop the right side */ cp = cpic + (cWIDE-1) * 3; bgR = cp[0]; bgG = cp[1]; bgB = cp[2]; while (cleft + cright + 1 < cWIDE) { /* see if we can delete this line */ for (i=0, cp1=cp; i<cHIGH && cp1[0]==bgR && cp1[1]==bgG && cp1[2]==bgB; i++, cp1 += (cWIDE*3)); if (i==cHIGH) { cp-=3; cright++; } else break; } /* do the actual cropping */ if (cleft || ctop || cbot || cright) { DoCrop(cXOFF+cleft, cYOFF+ctop, cWIDE-(cleft+cright), cHIGH-(ctop+cbot)); return 1; } return 0; } /*******************************/ void DoCrop(x,y,w,h) int x,y,w,h; { /* given a cropping rectangle in image coordinates, it regens cpic and sticks likely values into eWIDE,eHIGH, assuming you wanted to crop. epic is not regnerated (but is freed) */ int i,j,k,bperpix; byte *cp, *pp; double expw, exph; bperpix = (picType == PIC8) ? 1 : 3; BTSetActive(&but[BCROP],0); /* get the cropping rectangle inside pic, if it isn't... */ RANGE(x, 0, pWIDE-1); RANGE(y, 0, pHIGH-1); if (w<1) w=1; if (h<1) h=1; if (x+w > pWIDE) w = pWIDE-x; if (y+h > pHIGH) h = pHIGH-y; FreeEpic(); if (cpic && cpic != pic) free(cpic); cpic = NULL; expw = (double) eWIDE / (double) cWIDE; exph = (double) eHIGH / (double) cHIGH; crx1 = (int) ((x - cXOFF) * expw); cry1 = (int) ((y - cYOFF) * exph); cXOFF = x; cYOFF = y; cWIDE = w; cHIGH = h; if (DEBUG) fprintf(stderr,"DoCrop(): cropping to %dx%d rectangle at %d,%d\n", cWIDE, cHIGH, cXOFF, cYOFF); if (cWIDE == pWIDE && cHIGH == pHIGH) { /* not really cropping */ cpic = pic; cXOFF = cYOFF = 0; } else { /* at this point, we want to generate cpic, which will contain a cWIDE*cHIGH subsection of 'pic', top-left at cXOFF,cYOFF */ cpic = (byte *) malloc(cWIDE * cHIGH * bperpix); if (cpic == NULL) { fprintf(stderr,"%s: unable to allocate memory for cropped image\n", cmd); WUnCrop(); cpic = pic; cXOFF = cYOFF = 0; cWIDE = pWIDE; cHIGH = pHIGH; SetCropString(but[BCROP].active); return; } /* copy relevant pixels from pic to cpic */ cp = cpic; for (i=0; i<cHIGH; i++) { pp = pic + (i+cYOFF) * (pWIDE*bperpix) + (cXOFF * bperpix); for (j=0; j<cWIDE*bperpix; j++) *cp++ = *pp++; } } SetCropString(but[BCROP].active); BTSetActive(&but[BUNCROP], (cpic!=pic)); eWIDE = (int) (cWIDE * expw); eHIGH = (int) (cHIGH * exph); SetCursors(-1); } /***********************************/ void Rotate(dir) int dir; { /* called when rotate CW and rotate CCW controls are clicked */ /* dir=0: clockwise, else counter-clockwise */ DoRotate(dir); CreateXImage(); WRotate(); } /***********************************/ void DoRotate(dir) int dir; { int i; /* dir=0: 90 degrees clockwise, else 90 degrees counter-clockwise */ WaitCursor(); RotatePic(pic, picType, &pWIDE, &pHIGH, dir); /* rotate clipped version and modify 'clip' coords */ if (cpic != pic && cpic != NULL) { if (!dir) { i = pWIDE - (cYOFF + cHIGH); /* have to rotate offsets */ cYOFF = cXOFF; cXOFF = i; } else { i = pHIGH - (cXOFF + cWIDE); cXOFF = cYOFF; cYOFF = i; } WaitCursor(); RotatePic(cpic, picType, &cWIDE, &cHIGH,dir); } else { cWIDE = pWIDE; cHIGH = pHIGH; } /* rotate expanded version */ if (epic != cpic && epic != NULL) { WaitCursor(); RotatePic(epic, picType, &eWIDE, &eHIGH,dir); } else { eWIDE = cWIDE; eHIGH = cHIGH; } } /************************/ void RotatePic(pic, ptype, wp, hp, dir) byte *pic; int *wp, *hp; int ptype, dir; { /* rotates a w*h array of bytes 90 deg clockwise (dir=0) or counter-clockwise (dir != 0). swaps w and h */ byte *pic1, *pix1, *pix; int i,j,bperpix; unsigned int w,h; bperpix = (ptype == PIC8) ? 1 : 3; w = *wp; h = *hp; pix1 = pic1 = (byte *) malloc(w*h*bperpix); if (!pic1) FatalError("Not enough memory to rotate!"); /* do the rotation */ if (dir==0) { for (i=0; i<w; i++) { /* CW */ if (bperpix == 1) { for (j=h-1, pix=pic+(h-1)*w + i; j>=0; j--, pix1++, pix-=w) *pix1 = *pix; } else { int bperlin = w*bperpix; int k; for (j=h-1, pix=pic+(h-1)*w*bperpix + i*bperpix; j>=0; j--, pix -= bperlin) for (k=0; k<bperpix; k++) *pix1++ = pix[k]; } } } else { for (i=w-1; i>=0; i--) { /* CCW */ if (bperpix == 1) { for (j=0, pix=pic+i; j<h; j++, pix1++, pix+=w) *pix1 = *pix; } else { int k; int bperlin = w*bperpix; for (j=0, pix=pic+i*bperpix; j<h; j++, pix+=bperlin) for (k=0; k<bperpix; k++) *pix1++ = pix[k]; } } } /* copy the rotated buffer into the original buffer */ xvbcopy(pic1, pic, w*h*bperpix); free(pic1); /* swap w and h */ *wp = h; *hp = w; } /***********************************/ void Flip(dir) int dir; { /* dir=0: flip horizontally, else vertically * * Note: flips pic, cpic, and epic. Doesn't touch Ximage, nor does it draw */ WaitCursor(); FlipPic(pic, pWIDE, pHIGH, dir); /* flip clipped version */ if (cpic && cpic != pic) { WaitCursor(); FlipPic(cpic, cWIDE, cHIGH, dir); } /* flip expanded version */ if (epic && epic != cpic) { WaitCursor(); FlipPic(epic, eWIDE, eHIGH, dir); } } /************************/ void FlipPic(pic, w, h, dir) byte *pic; int w, h; int dir; { /* flips a w*h array of bytes horizontally (dir=0) or vertically (dir!=0) */ byte *plin; int i,j,k,l,bperpix,bperlin; bperpix = (picType == PIC8) ? 1 : 3; bperlin = w * bperpix; if (dir==0) { /* horizontal flip */ byte *leftp, *rightp; for (i=0; i<h; i++) { plin = pic + i*bperlin; leftp = plin; rightp = plin + (w-1)*bperpix; for (j=0; j<w/2; j++, rightp -= (2*bperpix)) { for (l=0; l<bperpix; l++, leftp++, rightp++) { k = *leftp; *leftp = *rightp; *rightp = k; } } } } else { /* vertical flip */ byte *topp, *botp; for (i=0; i<w; i++) { topp = pic + i*bperpix; botp = pic + (h-1)*bperlin + i*bperpix; for (j=0; j<h/2; j++, topp+=(w-1)*bperpix, botp-=(w+1)*bperpix) { for (l=0; l<bperpix; l++, topp++, botp++) { k = *topp; *topp = *botp; *botp = k; } } } } } /************************/ void InstallNewPic() { /* given a new pic and colormap, (or new 24-bit pic) installs everything, regens cpic and epic, and redraws image */ /* toss old cpic and epic, if any */ FreeEpic(); if (cpic && cpic != pic) free(cpic); cpic = NULL; /* toss old colors, and allocate new ones */ NewPicGetColors(0,0); /* generate cpic,epic,theImage from new 'pic' */ crop1(cXOFF, cYOFF, cWIDE, cHIGH, DO_ZOOM); HandleDispMode(); } /***********************************/ void DrawEpic() { /* given an 'epic', builds a new Ximage, and draws it. Basically called whenever epic is changed, or whenever color allocation changes (ie, the created X image will look different for the same epic) */ CreateXImage(); if (useroot) MakeRootPic(); else DrawWindow(0,0,eWIDE,eHIGH); if (but[BCROP].active) InvCropRect(); } /************************************/ void KillOldPics() { /* throw away all previous images */ FreeEpic(); if (cpic && cpic != pic) free(cpic); if (pic) free(pic); xvDestroyImage(theImage); theImage = NULL; pic = egampic = epic = cpic = NULL; if (picComments) free(picComments); picComments = (char *) NULL; ChangeCommentText(); } /************************/ static void FloydDitherize1(ximage,pic824,ptype, wide, high, rmap, gmap, bmap) XImage *ximage; byte *pic824, *rmap, *gmap, *bmap; int ptype, wide, high; { /* does floyd-steinberg ditherizing algorithm. * * takes a wide*high input image, of type 'ptype' (PIC8, PIC24) * (if PIC8, colormap is specified by rmap,gmap,bmap) * * output is a 1-bit per pixel XYBitmap, packed 8 pixels per byte * * Note: this algorithm is *only* used when running on a 1-bit display */ register byte pix8, bit; int *thisline, *nextline; int *thisptr, *nextptr, *tmpptr; int i, j, err, bperpix, bperln, order; byte *pp, *image, w1, b1, w8, b8, rgb[256]; if (ptype == PIC8) { /* monoify colormap */ for (i=0; i<256; i++) rgb[i] = MONO(rmap[i], gmap[i], bmap[i]); } image = (byte *) ximage->data; bperln = ximage->bytes_per_line; order = ximage->bitmap_bit_order; bperpix = (ptype == PIC8) ? 1 : 3; thisline = (int *) malloc(wide * sizeof(int)); nextline = (int *) malloc(wide * sizeof(int)); if (!thisline || !nextline) FatalError("ran out of memory in FloydDitherize1()\n"); /* load up first line of picture */ pp = pic824; if (ptype == PIC24) { for (j=0, tmpptr = nextline; j<wide; j++, pp+=3) *tmpptr++ = fsgamcr[MONO(pp[0], pp[1], pp[2])]; } else { for (j=0, tmpptr = nextline; j<wide; j++, pp++) *tmpptr++ = fsgamcr[rgb[*pp]]; } w1 = white&0x1; b1=black&0x1; w8 = w1<<7; b8 = b1<<7; /* b/w bit in high bit */ for (i=0; i<high; i++) { if ((i&63) == 0) WaitCursor(); /* get next line of image */ tmpptr = thisline; thisline = nextline; nextline = tmpptr; /* swap */ if (i!=high-1) { pp = pic824 + (i+1) * wide * bperpix; if (ptype == PIC24) { for (j=0, tmpptr = nextline; j<wide; j++, pp+=3) *tmpptr++ = fsgamcr[MONO(pp[0], pp[1], pp[2])]; } else { for (j=0, tmpptr = nextline; j<wide; j++, pp++) *tmpptr++ = fsgamcr[rgb[*pp]]; } } thisptr = thisline; nextptr = nextline; pp = image + i*bperln; if (order==LSBFirst) { bit = pix8 = 0; for (j=0; j<wide; j++, thisptr++, nextptr++) { if (*thisptr<128) { err = *thisptr; pix8 |= b8; } else { err = *thisptr-255; pix8 |= w8; } if (bit==7) { *pp++ = pix8; bit=pix8=0; } else { pix8 >>= 1; bit++; } if (j<wide-1) thisptr[1] += ((err*7)/16); if (i<high-1) { nextptr[0] += ((err*5)/16); if (j>0) nextptr[-1] += ((err*3)/16); if (j<wide-1) nextptr[ 1] += (err/16); } } if (bit) *pp++ = pix8>>(7-bit); /* write partial byte at end of line */ } else { /* order==MSBFirst */ bit = pix8 = 0; for (j=0; j<wide; j++, thisptr++, nextptr++) { if (*thisptr<128) { err = *thisptr; pix8 |= b1; } else { err = *thisptr-255; pix8 |= w1; } if (bit==7) { *pp++ = pix8; bit=pix8=0; } else { pix8 <<= 1; bit++; } if (j<wide-1) thisptr[1] += ((err*7)/16); if (i<high-1) { nextptr[0] += ((err*5)/16); if (j>0) nextptr[-1] += ((err*3)/16); if (j<wide-1) nextptr[ 1] += (err/16); } } if (bit) *pp++ = pix8<<(7-bit); /* write partial byte at end of line */ } } free(thisline); free(nextline); } /************************/ byte *FSDither(inpic, intype, w, h, rmap, gmap, bmap, bval, wval) byte *inpic, *rmap, *gmap, *bmap; int w,h, intype, bval, wval; { /* takes an input pic of size w*h, and type 'intype' (PIC8 or PIC24), * (if PIC8, colormap specified by rmap,gmap,bmap) * and does the floyd-steinberg dithering algorithm on it. * generates (mallocs) a w*h 1-byte-per-pixel 'outpic', using 'bval' * and 'wval' as the 'black' and 'white' pixel values, respectively */ int i, j, err, w1, h1; byte *pp, *outpic, rgb[256]; int *thisline, *nextline, *thisptr, *nextptr, *tmpptr; outpic = (byte *) malloc(w * h); if (!outpic) return outpic; if (intype == PIC8) { /* monoify colormap */ for (i=0; i<256; i++) rgb[i] = MONO(rmap[i], gmap[i], bmap[i]); } thisline = (int *) malloc(w * sizeof(int)); nextline = (int *) malloc(w * sizeof(int)); if (!thisline || !nextline) FatalError("ran out of memory in FSDither()\n"); w1 = w-1; h1 = h-1; /* load up first line of picture */ pp = inpic; if (intype == PIC24) { for (j=0, tmpptr=nextline; j<w; j++, pp+=3) *tmpptr++ = fsgamcr[MONO(pp[0], pp[1], pp[2])]; } else { for (j=0, tmpptr=nextline; j<w; j++, pp++) *tmpptr++ = fsgamcr[rgb[*pp]]; } for (i=0; i<h; i++) { if ((i&31) == 0) WaitCursor(); /* get next line of picture */ tmpptr = thisline; thisline = nextline; nextline = tmpptr; /* swap */ if (i!=h1) { if (intype == PIC24) { pp = inpic + (i+1) * w * 3; for (j=0, tmpptr=nextline; j<w; j++, pp+=3) *tmpptr++ = fsgamcr[MONO(pp[0], pp[1], pp[2])]; } else { pp = inpic + (i+1) * w; for (j=0, tmpptr = nextline; j<w; j++, pp++) *tmpptr++ = fsgamcr[rgb[*pp]]; } } pp = outpic + i * w; thisptr = thisline; nextptr = nextline; for (j=0; j<w; j++, pp++, thisptr++, nextptr++) { if (*thisptr<128) { err = *thisptr; *pp = (byte) bval; } else { err = *thisptr-255; *pp = (byte) wval; } if (j<w1) thisptr[1] += ((err*7)/16); if (i<h1) { nextptr[0] += ((err*5)/16); if (j>0) nextptr[-1] += ((err*3)/16); if (j<w1) nextptr[ 1] += (err/16); } } } free(thisline); free(nextline); return outpic; } /***********************************/ void CreateXImage() { xvDestroyImage(theImage); theImage = NULL; if (!epic) GenerateEpic(eWIDE, eHIGH); /* shouldn't happen... */ if (picType == PIC24) { /* generate egampic */ if (egampic && egampic != epic) free(egampic); egampic = GammifyPic24(epic, eWIDE, eHIGH); if (!egampic) egampic = epic; } if (picType == PIC8) theImage = Pic8ToXImage(epic, eWIDE, eHIGH, cols, rMap, gMap, bMap); else if (picType == PIC24) theImage = Pic24ToXImage(egampic, eWIDE, eHIGH); } /***********************************/ XImage *Pic8ToXImage(pic8, wide, high, xcolors, rmap, gmap, bmap) byte *pic8, *rmap, *gmap, *bmap; int wide, high; unsigned long *xcolors; { /* * this has to do the tricky bit of converting the data in 'pic8' * into something usable for X. * */ int i; unsigned long xcol; XImage *xim; byte *dithpic; xim = (XImage *) NULL; dithpic = (byte *) NULL; if (!pic8) return xim; /* shouldn't happen */ if (DEBUG > 1) fprintf(stderr,"Pic8ToXImage(): creating a %dx%d Ximage, %d bits deep\n", wide, high, dispDEEP); /* special case: 1-bit display */ if (dispDEEP == 1) { byte *imagedata; xim = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL, wide, high, 32, 0); if (!xim) FatalError("couldn't create xim!"); imagedata = (byte *) malloc(xim->bytes_per_line * high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; FloydDitherize1(xim, pic8, PIC8, wide, high, rmap, gmap, bmap); return xim; } /* if ncols==0, do a 'black' and 'white' dither */ if (ncols == 0) { /* note that if dispDEEP > 8, dithpic will just have '0' and '1' instead of 'black' and 'white' */ dithpic = FSDither(pic8, PIC8, wide, high, rmap, gmap, bmap, (dispDEEP <= 8) ? black : 0, (dispDEEP <= 8) ? white : 1); } switch (dispDEEP) { case 8: { byte *imagedata, *ip, *pp; int j, imWIDE, nullCount; nullCount = (4 - (wide % 4)) & 0x03; /* # of padding bytes per line */ imWIDE = wide + nullCount; /* Now create the image data - pad each scanline as necessary */ imagedata = (byte *) malloc(imWIDE * high); if (!imagedata) FatalError("couldn't malloc imagedata"); pp = (dithpic) ? dithpic : pic8; for (i=0, ip=imagedata; i<high; i++) { if ((i&0x7f) == 0) WaitCursor(); if (dithpic) { for (j=0; j<wide; j++, ip++, pp++) *ip = *pp; /* pp already is Xval */ } else { for (j=0; j<wide; j++, ip++, pp++) *ip = (byte) xcolors[*pp]; } for (j=0; j<nullCount; j++, ip++) *ip = 0; } xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0, (char *) imagedata, wide, high, 32, imWIDE); if (!xim) FatalError("couldn't create xim!"); } break; /*********************************/ case 4: { byte *imagedata, *ip, *pp; byte *lip; int bperline, half, j; xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, wide, high, 8, 0); if (!xim) FatalError("couldn't create xim!"); bperline = xim->bytes_per_line; imagedata = (byte *) malloc(bperline * high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; pp = (dithpic) ? dithpic : pic8; if (xim->bits_per_pixel == 4) { for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) { xcol = ((dithpic) ? *pp : xcolors[*pp]) & 0x0f; if (ImageByteOrder(theDisp) == LSBFirst) { if (half&1) { *ip = *ip + (xcol<<4); ip++; } else *ip = xcol; } else { if (half&1) { *ip = *ip + xcol; ip++; } else *ip = xcol << 4; } } } } else if (xim->bits_per_pixel == 8) { for (i=wide*high, ip=imagedata; i>0; i--,pp++,ip++) { if ((i&0x1ffff) == 0) WaitCursor(); *ip = (dithpic) ? *pp : (byte) xcolors[*pp]; } } else FatalError("This display's too bizarre. Can't create XImage."); } break; /*********************************/ case 2: { /* by M.Kossa@frec.bull.fr (Marc Kossa) */ /* MSBFirst mods added by dale@ntg.com (Dale Luck) */ /* additional fixes by evol@infko.uni-koblenz.de (Randolf Werner) for NeXT 2bit grayscale with MouseX */ byte *imagedata, *ip, *pp; byte *lip; int bperline, half, j; xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, wide, high, 8, 0); if (!xim) FatalError("couldn't create xim!"); bperline = xim->bytes_per_line; imagedata = (byte *) malloc(bperline * high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; pp = (dithpic) ? dithpic : pic8; if (xim->bits_per_pixel == 2) { for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) { xcol = ((dithpic) ? *pp : xcolors[*pp]) & 0x03; if (xim->bitmap_bit_order == LSBFirst) { if (half%4==0) *ip = xcol; else if (half%4==1) *ip |= (xcol<<2); else if (half%4==2) *ip |= (xcol<<4); else { *ip |= (xcol<<6); ip++; } } else { /* MSBFirst. NeXT, among others */ if (half%4==0) *ip = (xcol<<6); else if (half%4==1) *ip |= (xcol<<4); else if (half%4==2) *ip |= (xcol<<2); else { *ip |= xcol; ip++; } } } } } else if (xim->bits_per_pixel == 4) { for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) { xcol = ((dithpic) ? *pp : xcolors[*pp]) & 0x0f; if (xim->bitmap_bit_order == LSBFirst) { if (half&1) { *ip |= (xcol<<4); ip++; } else *ip = xcol; } else { /* MSBFirst */ if (half&1) { *ip |= xcol; ip++; } else *ip = xcol << 4; } } } } else if (xim->bits_per_pixel == 8) { for (i=wide*high, ip=imagedata; i>0; i--,pp++,ip++) { if ((i&0x1ffff) == 0) WaitCursor(); *ip = (dithpic) ? *pp : (byte) xcolors[*pp]; } } else FatalError("This display's too bizarre. Can't create XImage."); } break; /*********************************/ case 5: case 6: { byte *imagedata, *ip, *pp; int bperline; xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, wide, high, 8, 0); if (!xim) FatalError("couldn't create xim!"); if (xim->bits_per_pixel != 8) FatalError("This display's too bizarre. Can't create XImage."); bperline = xim->bytes_per_line; imagedata = (byte *) malloc(bperline * high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; pp = (dithpic) ? dithpic : pic8; for (i=wide*high, ip=imagedata; i>0; i--,pp++,ip++) { if ((i&0x1ffff) == 0) WaitCursor(); *ip = (dithpic) ? *pp : (byte) xcolors[*pp]; } } break; /*********************************/ case 12: case 16: { short *imagedata, *ip; byte *pp; imagedata = (short *) malloc(2*wide*high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0, (char *) imagedata, wide, high, 16, 0); if (!xim) FatalError("couldn't create xim!"); if (dispDEEP == 12 && xim->bits_per_pixel != 16) { char buf[128]; sprintf(buf,"No code for this type of display (depth=%d, bperpix=%d)", dispDEEP, xim->bits_per_pixel); FatalError(buf); } pp = (dithpic) ? dithpic : pic8; if (xim->byte_order == MSBFirst) { for (i=wide*high, ip=imagedata; i>0; i--,pp++) { if ((i&0x1ffff) == 0) WaitCursor(); if (dithpic) { *ip++ = ((*pp) ? white : black) & 0xffff; } else *ip++ = xcolors[*pp] & 0xffff; } } else { /* LSBFirst */ for (i=wide*high, ip=imagedata; i>0; i--,pp++) { if ((i&0x1ffff) == 0) WaitCursor(); if (dithpic) xcol = ((*pp) ? white : black) & 0xffff; else xcol = xcolors[*pp]; *ip++ = ((xcol>>8) & 0xff) | ((xcol&0xff) << 8); } } } break; /*********************************/ case 24: case 32: { byte *imagedata, *ip, *pp; imagedata = (byte *) malloc(4*wide*high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0, (char *) imagedata, wide, high, 32, 0); if (!xim) FatalError("couldn't create xim!"); pp = (dithpic) ? dithpic : pic8; if (xim->byte_order == MSBFirst) { for (i=wide*high, ip=imagedata; i>0; i--,pp++) { if ((i&0x1ffff) == 0) WaitCursor(); xcol = (dithpic) ? ((*pp) ? white : black) : xcolors[*pp]; *ip++ = 0; *ip++ = (xcol>>16) & 0xff; *ip++ = (xcol>>8) & 0xff; *ip++ = xcol & 0xff; } } else { /* LSBFirst */ for (i=wide*high, ip=imagedata; i>0; i--,pp++) { xcol = (dithpic) ? ((*pp) ? white : black) : xcolors[*pp]; if ((i&0x1ffff) == 0) WaitCursor(); *ip++ = xcol & 0xff; *ip++ = (xcol>>8) & 0xff; *ip++ = (xcol>>16) & 0xff; *ip++ = 0; } } } break; /*********************************/ default: sprintf(str,"no code to handle this display type (%d bits deep)", dispDEEP); FatalError(str); break; } return(xim); } static int foo = 0; /***********************************/ XImage *Pic24ToXImage(pic24, wide, high) byte *pic24; int wide, high; { /* * this has to do the none-to-simple bit of converting the data in 'pic24' * into something usable by X. * * There are two major approaches: if we're displaying on a TrueColor * or DirectColor display, we've got all the colors we're going to need, * and 'all we have to do' is convert 24-bit RGB pixels into whatever * variation of RGB the X device in question wants. No color allocation * is involved. * * Alternately, if we're on a PseudoColor, GrayScale, StaticColor or * StaticGray display, we're going to continue to operate in an 8-bit * mode. (In that by this point, a 3/3/2 standard colormap has been * created for our use (though all 256 colors may not be unique...), and * we're just going to display the 24-bit picture by dithering with those * colors * */ int i,j; XImage *xim; xim = (XImage *) NULL; if (!pic24) return xim; /* shouldn't happen */ /* special case: 1-bit display. Doesn't much matter *what* the visual is */ if (dispDEEP == 1) { byte *imagedata; xim = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL, wide, high, 32, 0); if (!xim) FatalError("couldn't create xim!"); imagedata = (byte *) malloc(xim->bytes_per_line * high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; FloydDitherize1(xim, pic24, PIC24, wide, high, NULL, NULL, NULL); return xim; } if (theVisual->class == TrueColor || theVisual->class == DirectColor) { /************************************************************************/ /* Non-ColorMapped Visuals: TrueColor, DirectColor */ /************************************************************************/ unsigned long r, g, b, rmask, gmask, bmask, xcol; int rshift, gshift, bshift, bperpix, bperline, border; byte *imagedata, *lip, *ip, *pp; /* compute various shifting constants that we'll need... */ rmask = theVisual->red_mask; gmask = theVisual->green_mask; bmask = theVisual->blue_mask; rshift = 7 - highbit(rmask); gshift = 7 - highbit(gmask); bshift = 7 - highbit(bmask); xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, wide, high, 32, 0); if (!xim) FatalError("couldn't create X image!"); bperline = xim->bytes_per_line; bperpix = xim->bits_per_pixel; border = xim->byte_order; imagedata = (byte *) malloc(high * bperline); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; if (bperpix != 8 && bperpix != 16 && bperpix != 24 && bperpix != 32) { char buf[128]; sprintf(buf,"Sorry, no code written to handle %d-bit %s", bperpix, "TrueColor/DirectColor displays!"); FatalError(buf); } lip = imagedata; pp = pic24; for (i=0; i<high; i++, lip+=bperline) { for (j=0, ip=lip; j<wide; j++) { r = *pp++; g = *pp++; b = *pp++; /* shift r,g,b so that high bit of 8-bit color specification is * aligned with high bit of r,g,b-mask in visual, * AND each component with its mask, * and OR the three components together */ /* shift the bits around */ if (rshift<0) r = r << (-rshift); else r = r >> rshift; if (gshift<0) g = g << (-gshift); else g = g >> gshift; if (bshift<0) b = b << (-bshift); else b = b >> bshift; r = r & rmask; g = g & gmask; b = b & bmask; xcol = r | g | b; if (bperpix == 32) { if (border == MSBFirst) { *ip++ = (xcol>>24) & 0xff; *ip++ = (xcol>>16) & 0xff; *ip++ = (xcol>>8) & 0xff; *ip++ = xcol & 0xff; } else { /* LSBFirst */ *ip++ = xcol & 0xff; *ip++ = (xcol>>8) & 0xff; *ip++ = (xcol>>16) & 0xff; *ip++ = (xcol>>24) & 0xff; } } else if (bperpix == 24) { if (border == MSBFirst) { *ip++ = (xcol>>16) & 0xff; *ip++ = (xcol>>8) & 0xff; *ip++ = xcol & 0xff; } else { /* LSBFirst */ *ip++ = xcol & 0xff; *ip++ = (xcol>>8) & 0xff; *ip++ = (xcol>>16) & 0xff; } } else if (bperpix == 16) { if (border == MSBFirst) { *ip++ = (xcol>>8) & 0xff; *ip++ = xcol & 0xff; } else { /* LSBFirst */ *ip++ = xcol & 0xff; *ip++ = (xcol>>8) & 0xff; } } else if (bperpix == 8) { *ip++ = xcol & 0xff; } } } } else { /************************************************************************/ /* CMapped Visuals: PseudoColor, GrayScale, StaticGray, StaticColor... */ /************************************************************************/ byte *pic8; int bwdith; /* in all cases, make an 8-bit version of the image, either using 'black' and 'white', or the stdcmap */ bwdith = 0; if (ncols == 0 && dispDEEP != 1) { /* do 'black' and 'white' dither */ /* note that if dispDEEP > 8, pic8 will just have '0' and '1' instead of 'black' and 'white' */ pic8 = FSDither(pic24, PIC24, wide, high, NULL, NULL, NULL, (dispDEEP <= 8) ? black : 0, (dispDEEP <= 8) ? white : 1); bwdith = 1; } else { /* do color dither using stdcmap */ pic8 = Do332ColorDither(pic24, NULL, wide, high, NULL, NULL, NULL, stdrdisp, stdgdisp, stdbdisp, 256); } if (!pic8) FatalError("out of memory in Pic24ToXImage()\n"); /* DISPLAY-DEPENDENT code follows... */ switch (dispDEEP) { case 8: { byte *imagedata, *ip, *pp; int j, imWIDE, nullCount; nullCount = (4 - (wide % 4)) & 0x03; /* # of padding bytes per line */ imWIDE = wide + nullCount; /* Now create the image data - pad each scanline as necessary */ imagedata = (byte *) malloc(imWIDE * high); if (!imagedata) FatalError("couldn't malloc imagedata"); for (i=0, pp=pic8, ip=imagedata; i<high; i++) { if ((i&0x7f) == 0) WaitCursor(); if (bwdith) for (j=0; j<wide; j++, ip++, pp++) *ip = *pp; else for (j=0; j<wide; j++, ip++, pp++) *ip = stdcols[*pp]; for (j=0; j<nullCount; j++, ip++) *ip = 0; } xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, (char *) imagedata, wide, high, 32, imWIDE); if (!xim) FatalError("couldn't create xim!"); } break; /*********************************/ case 4: { byte *imagedata, *ip, *pp; byte *lip; int bperline, half, j; unsigned long xcol; xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, wide, high, 32, 0); if (!xim) FatalError("couldn't create xim!"); bperline = xim->bytes_per_line; imagedata = (byte *) malloc(bperline * high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; pp = pic8; if (xim->bits_per_pixel == 4) { for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) { xcol = ((bwdith) ? *pp : stdcols[*pp]) & 0x0f; if (xim->byte_order == LSBFirst) { if (half&1) { *ip = *ip + (xcol<<4); ip++; } else *ip = xcol; } else { if (half&1) { *ip = *ip + xcol; ip++; } else *ip = xcol << 4; } } } } else if (xim->bits_per_pixel == 8) { for (i=0,lip=imagedata; i<high; i++,lip+=bperline) { if ((i&127)==0) WaitCursor(); for (j=0,ip=lip; j<wide; j++,pp++,ip++) { *ip = (bwdith) ? *pp : (byte) stdcols[*pp]; } } } else FatalError("This display's too bizarre. Can't create XImage."); } break; /*********************************/ case 2: { /* by M.Kossa@frec.bull.fr (Marc Kossa) */ /* MSBFirst mods added by dale@ntg.com (Dale Luck) */ /* additional fixes by evol@infko.uni-koblenz.de (Randolf Werner) for NeXT 2bit grayscale with MouseX */ byte *imagedata, *ip, *pp; byte *lip; int bperline, half, j; unsigned long xcol; xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, wide, high, 32, 0); if (!xim) FatalError("couldn't create xim!"); bperline = xim->bytes_per_line; imagedata = (byte *) malloc(bperline * high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; pp = pic8; if (xim->bits_per_pixel == 2) { for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) { xcol = ((bwdith) ? *pp : stdcols[*pp]) & 0x03; if (xim->bitmap_bit_order == LSBFirst) { if (half%4==0) *ip = xcol; else if (half%4==1) *ip |= (xcol<<2); else if (half%4==2) *ip |= (xcol<<4); else { *ip |= (xcol<<6); ip++; } } else { /* MSBFirst. NeXT, among others */ if (half%4==0) *ip = (xcol<<6); else if (half%4==1) *ip |= (xcol<<4); else if (half%4==2) *ip |= (xcol<<2); else { *ip |= xcol; ip++; } } } } } else if (xim->bits_per_pixel == 4) { for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) { xcol = ((bwdith) ? *pp : stdcols[*pp]) & 0x0f; if (xim->bitmap_bit_order == LSBFirst) { if (half&1) { *ip |= (xcol<<4); ip++; } else *ip = xcol; } else { /* MSBFirst */ if (half&1) { *ip |= xcol; ip++; } else *ip = xcol << 4; } } } } else if (xim->bits_per_pixel == 8) { for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip; j<wide; j++,pp++,ip++) { *ip = ((bwdith) ? *pp : stdcols[*pp]) & 0xff; } } } else FatalError("This display's too bizarre. Can't create XImage."); } break; /*********************************/ case 6: { byte *imagedata, *lip, *ip, *pp; int bperline; xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, wide, high, 32, 0); if (!xim) FatalError("couldn't create xim!"); if (xim->bits_per_pixel != 8) FatalError("This display's too bizarre. Can't create XImage."); bperline = xim->bytes_per_line; imagedata = (byte *) malloc(bperline * high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; pp = pic8; for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip; j<wide; j++,pp++,ip++) { *ip = ((bwdith) ? *pp : stdcols[*pp]) & 0x3f; } } } break; /*********************************/ case 16: { short *imagedata, *ip, *lip; byte *pp; int bperline; unsigned long xcol; imagedata = (short *) malloc(2*wide*high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0, (char *) imagedata, wide, high, 32, 0); if (!xim) FatalError("couldn't create xim!"); bperline = xim->bytes_per_line; pp = pic8; if (xim->byte_order == MSBFirst) { for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip; j<wide; j++,pp++) { *ip++ = ((bwdith) ? *pp : stdcols[*pp]) & 0xffff; } } } else { /* LSBFirst */ for (i=0, lip=imagedata; i<high; i++, lip+=bperline) { if ((i&127) == 0) WaitCursor(); for (j=0, ip=lip; j<wide; j++,pp++) { xcol = ((bwdith) ? *pp : stdcols[*pp]) & 0xffff; *ip++ = ((xcol>>8) & 0xff) | ((xcol&0xff) << 8); } } } } break; /*********************************/ /* this wouldn't seem likely to happen, but what the heck... */ case 24: case 32: { byte *imagedata, *ip, *pp; unsigned long xcol; int bperpix; imagedata = (byte *) malloc(4*wide*high); if (!imagedata) FatalError("couldn't malloc imagedata"); xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0, (char *) imagedata, wide, high, 32, 0); if (!xim) FatalError("couldn't create xim!"); bperpix = xim->bits_per_pixel; pp = pic8; if (xim->byte_order == MSBFirst) { for (i=wide*high, ip=imagedata; i>0; i--,pp++) { if ((i&0x1ffff) == 0) WaitCursor(); xcol = (bwdith) ? *pp : stdcols[*pp]; if (bperpix == 32) *ip++ = 0; *ip++ = (xcol>>16) & 0xff; *ip++ = (xcol>>8) & 0xff; *ip++ = xcol & 0xff; } } else { /* LSBFirst */ for (i=wide*high, ip=imagedata; i>0; i--,pp++) { xcol = (bwdith) ? *pp : stdcols[*pp]; if ((i&0x1ffff) == 0) WaitCursor(); *ip++ = xcol & 0xff; *ip++ = (xcol>>8) & 0xff; *ip++ = (xcol>>16) & 0xff; if (bperpix == 32) *ip++ = 0; } } } break; } /* end of the switch */ free(pic8); /* since we ALWAYS make a copy of it into imagedata */ } return xim; } /***********************************************************/ void Set824Menus(mode) int mode; { /* move checkmark */ conv24MB.flags[CONV24_8BIT] = (mode==PIC8); conv24MB.flags[CONV24_24BIT] = (mode==PIC24); if (mode == PIC24) { dispMB.dim[DMB_COLNORM] = 1; dispMB.dim[DMB_COLPERF] = 1; dispMB.dim[DMB_COLOWNC] = 1; /* turn off RAW/DITH/SMOOTH buttons (caused by picType) */ epicMode = EM_RAW; SetEpicMode(); /* turn off autoapply mode */ /* GamSetAutoApply(0); */ /* or not! */ } else if (mode == PIC8) { dispMB.dim[DMB_COLNORM] = 0; dispMB.dim[DMB_COLPERF] = (dispMode == DMB_WINDOW) ? 0 : 1; dispMB.dim[DMB_COLOWNC] = (dispMode == DMB_WINDOW) ? 0 : 1; /* turn on RAW/DITH/SMOOTH buttons */ epicMode = EM_RAW; SetEpicMode(); /* possibly turn autoapply back on */ /* GamSetAutoApply(-1); */ /* -1 means 'back to default setting' */ } SetDirRButt(F_COLORS, -1); /* enable/disable REDUCED COLOR */ } /***********************************************************/ void Change824Mode(mode) int mode; { static int oldcmapmode = -1; if (mode == picType) return; /* same mode, do nothing */ Set824Menus(mode); if (!pic) { /* done all we wanna do when there's no pic */ picType = mode; return; } /* should probably actually *do* something involving colors, regenrating pic's, drawing an Ximage, etc. */ if (mode == PIC24) { byte *pic24; WaitCursor(); pic24 = Conv8to24(pic, pWIDE, pHIGH, rorg,gorg,borg); if (!pic24) FatalError("Ran out of memory in Change824Mode()\n"); KillOldPics(); pic = pic24; picType = PIC24; Set824Menus(picType); /* RAW/DITH/SMOOTH buttons change */ InstallNewPic(); } else if (mode == PIC8) { byte *pic8; WaitCursor(); pic8 = Conv24to8(pic, pWIDE, pHIGH, ncols, rMap,gMap,bMap); if (!pic8) FatalError("Ran out of memory in Change824Mode()\n"); KillOldPics(); pic = pic8; picType = PIC8; Set824Menus(picType); /* RAW/DITH/SMOOTH buttons change */ InstallNewPic(); } /* may have to explicitly redraw image window if not using root */ } /***********************************************************/ void FreeEpic() { if (egampic && egampic != epic) free(egampic); if (epic && epic != cpic) free(epic); epic = egampic = NULL; } /***********************************************************/ void InvertPic24(pic24, w, h) byte *pic24; int w,h; { int i; for (i=w*h*3; i; i--, pic24++) *pic24 = 255 - *pic24; } /***********************/ static int highbit(ul) unsigned long ul; { /* returns position of highest set bit in 'ul' as an integer (0-31), or -1 if none */ int i; for (i=31; ((ul&0x80000000) == 0) && i>=0; i--, ul<<=1); return i; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.