/* * xvimage.c - image manipulation functions (crop,resize,rotate...) for XV * * Contains: * void Resize(int, int) * void GenerateCpic() * 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 ); * int DoPad(mode, str, wide, high, opaque, omode); * int LoadPad(pinfo, fname); */ #define NEEDSDIR /* for S_IRUSR|S_IWUSR */ #include "copyright.h" #include "xv.h" static void flipSel PARM((int)); static void do_zoom PARM((int, int)); static void compute_zoom_rect PARM((int, int, int*, int*, int*, int*)); static void do_unzoom PARM((void)); static void do_pan PARM((int, int)); static void do_pan_calc PARM((int, int, int *, int *)); static void crop1 PARM((int, int, int, int, int)); static int doAutoCrop24 PARM((void)); static void floydDitherize1 PARM((XImage *, byte *, int, int, int, byte *, byte *,byte *)); static int highbit PARM((unsigned long)); static int doPadSolid PARM((char *, int, int, int, int)); static int doPadBggen PARM((char *, int, int, int, int)); static int doPadLoad PARM((char *, int, int, int, int)); static int doPadPaste PARM((byte *, int, int, int, int)); static int ReadImageFile1 PARM((char *, PICINFO *)); /* The following array represents the pixel values for each shade * of the primary color components. * If 'p' is a pointer to a source image rgb-byte-triplet, we can * construct the output pixel value simply by 'oring' together * the corresponding components: * * unsigned char *p; * unsigned long pixval; * * pixval = screen_rgb[0][*p++]; * pixval |= screen_rgb[1][*p++]; * pixval |= screen_rgb[2][*p++]; * * This is both efficient and generic, since the only assumption * is that the primary color components have separate bits. * The order and distribution of bits does not matter, and we * don't need additional variables and shifting/masking code. * The array size is 3 KBytes total and thus very reasonable. */ static unsigned long screen_rgb[3][256]; /* The following array holds the exact color representations * reported by the system. * This is useful for less than 24 bit deep displays as a base * for additional dithering to get smoother output. */ static byte screen_set[3][256]; /* The following routine initializes the screen_rgb and screen_set * arrays. * Since it is executed only once per program run, it does not need * to be super-efficient. * * The method is to draw points in a pixmap with the specified shades * of primary colors and then get the corresponding XImage pixel * representation. * Thus we can get away with any Bit-order/Byte-order dependencies. * * The routine uses some global X variables: * theDisp, theScreen, dispDEEP, and theCmap. * Adapt these to your application as necessary. * I've not passed them in as parameters, since for other platforms * than X these may be different (see vfixpix.c), and so the * screen_init() interface is unique. */ static void screen_init() { static int init_flag; /* assume auto-init as 0 */ Pixmap check_map; GC check_gc; XColor check_col; XImage *check_image; int ci, i; if (init_flag) return; init_flag = 1; check_map = XCreatePixmap(theDisp, RootWindow(theDisp,theScreen), 1, 1, dispDEEP); check_gc = XCreateGC(theDisp, check_map, 0, NULL); for (ci = 0; ci < 3; ci++) { for (i = 0; i < 256; i++) { check_col.red = 0; check_col.green = 0; check_col.blue = 0; /* Do proper upscaling from unsigned 8 bit (image data values) to unsigned 16 bit (X color representation). */ ((unsigned short *)&check_col.red)[ci] = (unsigned short)((i << 8) | i); if (theVisual->class == TrueColor) XAllocColor(theDisp, theCmap, &check_col); else xvAllocColor(theDisp, theCmap, &check_col); screen_set[ci][i] = (((unsigned short *)&check_col.red)[ci] >> 8) & 0xff; XSetForeground(theDisp, check_gc, check_col.pixel); XDrawPoint(theDisp, check_map, check_gc, 0, 0); check_image = XGetImage(theDisp, check_map, 0, 0, 1, 1, AllPlanes, ZPixmap); if (check_image) { switch (check_image->bits_per_pixel) { case 8: screen_rgb[ci][i] = *(CARD8 *)check_image->data; break; case 16: screen_rgb[ci][i] = *(CARD16 *)check_image->data; break; case 24: screen_rgb[ci][i] = ((unsigned long)*(CARD8 *)check_image->data << 16) | ((unsigned long)*(CARD8 *)(check_image->data + 1) << 8) | (unsigned long)*(CARD8 *)(check_image->data + 2); break; case 32: screen_rgb[ci][i] = *(CARD32 *)check_image->data; break; } XDestroyImage(check_image); } } } XFreeGC(theDisp, check_gc); XFreePixmap(theDisp, check_map); } /* The following switch should better be provided at runtime for * comparison purposes. * At the moment it's only compile time, unfortunately. * Who can make adaptions for use as a runtime switch by a menu option? */ #define DO_FIXPIX_SMOOTH #ifdef DO_FIXPIX_SMOOTH /* The following code is based in part on: * * jquant1.c * * Copyright (C) 1991-1996, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains 1-pass color quantization (color mapping) routines. * These routines provide mapping to a fixed color map using equally spaced * color values. Optional Floyd-Steinberg or ordered dithering is available. */ /* Declarations for Floyd-Steinberg dithering. * * Errors are accumulated into the array fserrors[], at a resolution of * 1/16th of a pixel count. The error at a given pixel is propagated * to its not-yet-processed neighbors using the standard F-S fractions, * ... (here) 7/16 * 3/16 5/16 1/16 * We work left-to-right on even rows, right-to-left on odd rows. * * We can get away with a single array (holding one row's worth of errors) * by using it to store the current row's errors at pixel columns not yet * processed, but the next row's errors at columns already processed. We * need only a few extra variables to hold the errors immediately around the * current column. (If we are lucky, those variables are in registers, but * even if not, they're probably cheaper to access than array elements are.) * * We provide (#columns + 2) entries per component; the extra entry at each * end saves us from special-casing the first and last pixels. */ typedef INT16 FSERROR; /* 16 bits should be enough */ typedef int LOCFSERROR; /* use 'int' for calculation temps */ typedef struct { byte *colorset; FSERROR *fserrors; } FSBUF; /* Floyd-Steinberg initialization function. * * It is called 'fs2_init' since it's specialized for our purpose and * could be embedded in a more general FS-package. * * Returns a malloced FSBUF pointer which has to be passed as first * parameter to subsequent 'fs2_dither' calls. * The FSBUF structure does not need to be referenced by the calling * application, it can be treated from the app like a void pointer. * * The current implementation does only require to free() this returned * pointer after processing. * * Returns NULL if malloc fails. * * NOTE: The FSBUF structure is designed to allow the 'fs2_dither' * function to work with an *arbitrary* number of color components * at runtime! This is an enhancement over the IJG code base :-). * Only fs2_init() specifies the (maximum) number of components. */ static FSBUF *fs2_init(width) int width; { FSBUF *fs; FSERROR *p; fs = (FSBUF *) malloc(sizeof(FSBUF) * 3 + ((size_t)width + 2) * sizeof(FSERROR) * 3); if (fs == 0) return fs; fs[0].colorset = screen_set[0]; fs[1].colorset = screen_set[1]; fs[2].colorset = screen_set[2]; p = (FSERROR *)(fs + 3); memset(p, 0, ((size_t)width + 2) * sizeof(FSERROR) * 3); fs[0].fserrors = p; fs[1].fserrors = p + 1; fs[2].fserrors = p + 2; return fs; } /* Floyd-Steinberg dithering function. * * NOTE: * (1) The image data referenced by 'ptr' is *overwritten* (input *and* * output) to allow more efficient implementation. * (2) Alternate FS dithering is provided by the sign of 'nc'. Pass in * a negative value for right-to-left processing. The return value * provides the right-signed value for subsequent calls! * (3) This particular implementation assumes *no* padding between lines! * Adapt this if necessary. */ static int fs2_dither(fs, ptr, nc, num_rows, num_cols) FSBUF *fs; byte *ptr; int nc, num_rows, num_cols; { int abs_nc, ci, row, col; LOCFSERROR delta, cur, belowerr, bpreverr; byte *dataptr, *colsetptr; FSERROR *errorptr; if ((abs_nc = nc) < 0) abs_nc = -abs_nc; for (row = 0; row < num_rows; row++) { for (ci = 0; ci < abs_nc; ci++, ptr++) { dataptr = ptr; colsetptr = fs[ci].colorset; errorptr = fs[ci].fserrors; if (nc < 0) { dataptr += (num_cols - 1) * abs_nc; errorptr += (num_cols + 1) * abs_nc; } cur = belowerr = bpreverr = 0; for (col = 0; col < num_cols; col++) { cur += errorptr[nc]; cur += 8; cur >>= 4; if ((cur += *dataptr) < 0) cur = 0; else if (cur > 255) cur = 255; *dataptr = cur & 0xff; cur -= colsetptr[cur]; delta = cur << 1; cur += delta; bpreverr += cur; cur += delta; belowerr += cur; cur += delta; errorptr[0] = (FSERROR)bpreverr; bpreverr = belowerr; belowerr = delta >> 1; dataptr += nc; errorptr += nc; } errorptr[0] = (FSERROR)bpreverr; } ptr += (num_cols - 1) * abs_nc; nc = -nc; } return nc; } #endif /* DO_FIXPIX_SMOOTH */ #define DO_CROP 0 #define DO_ZOOM 1 /***********************************/ void Resize(w,h) int w,h; { RANGE(w,1,maxWIDE); RANGE(h,1,maxHIGH); if (HaveSelection()) DrawSelection(0); /* turn off old rect */ 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); if (epicMode == EM_SMOOTH) { /* turn off smoothing */ epicMode = EM_RAW; SetEpicMode(); } GenerateEpic(w,h); CreateXImage(); } /********************************************/ void GenerateCpic() { /* called when 'pic' has been modified (different contents, *not* different size, orientation, etc. Rebuilds cpic. */ int i, j, bperpix; byte *pp, *cp; if (cpic == pic) return; /* no cropping, nothing to do */ cp = cpic; bperpix = (picType == PIC8) ? 1 : 3; for (i=0; i=eWIDE || ory>=eHIGH) return; crop1(opx, opy, opw, oph, DO_ZOOM); } /***********************************/ static void compute_zoom_rect(x, y, px, py, pw, ph) int x, y, *px, *py, *pw, *ph; { /* given a mouse pos (in epic coords), return x,y,w,h PIC coords for a 'zoom in by 2x' rectangle to be tracked. The rectangle stays completely within 'pic' boundaries, and moves in 'pic' increments */ CoordE2P(x, y, px, py); *pw = (cWIDE+1)/2; *ph = (cHIGH+1)/2; *px = *px - (*pw)/2; *py = *py - (*ph)/2; RANGE(*px, 0, pWIDE - *pw); RANGE(*py, 0, pHIGH - *ph); } /***********************************/ static void do_unzoom() { int x,y,w,h, x2,y2, ex,ey,ew,eh; /* compute a cropping rectangle (in pic 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; } ex = -eWIDE/2; ey = -eHIGH/2; ew = eWIDE*2; eh = eHIGH*2; CoordE2P(ex, ey, &x, &y); CoordE2P(ex+ew, ey+eh, &x2, &y2); w = x2 - x; h = y2 - y; 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); } /***********************************/ static void do_pan(mx,my) int mx,my; { int i, ox,oy,offx,offy, rw,rh, px, py, dx, dy,m; Window rW, cW; unsigned int mask; int rx, ry; offx = ox = mx; offy = oy = my; rw = eWIDE-1; rh = eHIGH-1; m = 0; XSetFunction(theDisp, theGC, GXinvert); XSetPlaneMask(theDisp, theGC, xorMasks[m]); XDrawRectangle(theDisp,mainW,theGC, mx-offx, my-offy, (u_int)rw, (u_int)rh); /* track until Button2 is released */ while (1) { if (!XQueryPointer(theDisp, mainW, &rW, &cW, &rx, &ry, &mx, &my, &mask)) continue; if (!(mask & ControlMask)) break; /* cancelled */ if (!(mask & Button2Mask)) break; /* button released */ if (mask & ShiftMask) { /* constrain mx,my to horiz or vertical */ if (abs(mx-offx) > abs(my-offy)) my = offy; else mx = offx; } do_pan_calc(offx, offy, &mx, &my); if (mx!=ox || my!=oy) { XDrawRectangle(theDisp, mainW, theGC, ox-offx, oy-offy, (u_int) rw, (u_int) rh); XDrawRectangle(theDisp, mainW, theGC, mx-offx, my-offy, (u_int) rw, (u_int) rh); ox = mx; oy = my; } else { XDrawRectangle(theDisp, mainW, theGC, ox-offx, oy-offy, (u_int) rw, (u_int) rh); m = (m+1)&7; XSetPlaneMask(theDisp, theGC, xorMasks[m]); XDrawRectangle(theDisp, mainW, theGC, ox-offx, oy-offy, (u_int) rw, (u_int) rh); XFlush(theDisp); Timer(100); } } mx = ox; my = oy; /* in case mx,my changed on button release */ if (!(mask & ControlMask)) { /* cancelled */ XDrawRectangle(theDisp, mainW, theGC, mx-offx, my-offy, (u_int) rw, (u_int) rh); XSetFunction(theDisp, theGC, GXcopy); XSetPlaneMask(theDisp, theGC, AllPlanes); return; } for (i=0; i<4; i++) { XDrawRectangle(theDisp, mainW, theGC, mx-offx, my-offy, (u_int) rw, (u_int) rh); XFlush(theDisp); Timer(100); } /* mx-offx, my-offy is top-left corner of pan rect, in epic coords */ CoordE2P(mx-offx, my-offy, &px, &py); dx = px - cXOFF; dy = py - cYOFF; if (dx==0 && dy==0) { /* didn't pan anywhere */ XDrawRectangle(theDisp, mainW, theGC, mx-offx, my-offy, (u_int) rw, (u_int) rh); XSetFunction(theDisp, theGC, GXcopy); XSetPlaneMask(theDisp, theGC, AllPlanes); return; } XSetFunction(theDisp, theGC, GXcopy); XSetPlaneMask(theDisp, theGC, AllPlanes); crop1(cXOFF-dx, cYOFF-dy, cWIDE, cHIGH, DO_ZOOM); } /***********************************/ static void do_pan_calc(offx, offy, xp,yp) int offx, offy, *xp, *yp; { /* given mouse coords (in xp,yp) and original offset, compute 'clipped' coords (returned in xp,yp) such that the 'pan window' remains entirely within the image boundaries */ int mx, my, eprx, epry, eprw, eprh, pprx, ppry, pprw, pprh; mx = *xp; my = *yp; /* compute corners of pan rect in eWIDE,eHIGH coords */ eprx = offx - mx; epry = offy - my; eprw = eWIDE; eprh = eHIGH; /* compute corners of pan rect in pWIDE,pHIGH coords */ CoordE2P(eprx, epry, &pprx, &ppry); pprw = cWIDE; pprh = cHIGH; /* if pan rect (in p* coords) is outside bounds of pic, move it inside */ if (pprx<0) pprx = 0; if (ppry<0) ppry = 0; if (pprx + pprw > pWIDE) pprx = pWIDE-pprw; if (ppry + pprh > pHIGH) ppry = pHIGH-pprh; /* convert clipped pan rect back into eWIDE,eHIGH coords */ CoordP2E(pprx, ppry, &eprx, &epry); *xp = offx - eprx; *yp = offy - epry; } /***********************************/ void Crop() { int i, x, y, w, h; if (!HaveSelection()) return; GetSelRCoords(&x,&y,&w,&h); EnableSelection(0); 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,oldcx,oldcy; byte *cp, *pp; oldcx = cXOFF; oldcy = cYOFF; 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, cXOFF-oldcx, cYOFF-oldcy); /* 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(); } /***********************************/ void AutoCrop() { /* called when AutoCrop button is pressed */ int oldcx, oldcy; oldcx = cXOFF; oldcy = cYOFF; if (DoAutoCrop()) { if (useroot) DrawEpic(); else { CreateXImage(); WCrop(eWIDE, eHIGH, cXOFF-oldcx, cYOFF-oldcy); } } SetCursors(-1); } /***********************************/ int DoAutoCrop() { /* returns '1' if any cropping was actually done. */ byte *cp, *cp1; int i, ctop, cbot, cleft, cright; byte bgcol; ctop = cbot = cleft = cright = 0; 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 -n ) if (cHIGH<3 || cWIDE<3) return 0; ctop = cbot = cleft = cright = 0; if (picType != PIC24) FatalError("doAutoCrop24 called when pic!=PIC24"); /* crop the top */ cp = cpic; half = cWIDE/2 * 3; maxmiss = cWIDE * MISSPCT / 100; bgR = cp[half+0]; bgG = cp[half+1]; bgB = cp[half+2]; while (ctop+1 < cHIGH) { /* see if we can delete this line */ oldr = bgR; oldg = bgG; oldb = bgB; for (i=0, misses=0, cp1=cp; i 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; 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((size_t) (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(); return; } /* copy relevant pixels from pic to cpic */ cp = cpic; for (i=0; imaxWIDE || eHIGH>maxHIGH) { /* make 'normal' size */ if (cWIDE>maxWIDE || cHIGH>maxHIGH) { double r,wr,hr; wr = ((double) cWIDE) / maxWIDE; hr = ((double) cHIGH) / maxHIGH; r = (wr>hr) ? wr : hr; /* r is the max(wr,hr) */ eWIDE = (int) ((cWIDE / r) + 0.5); eHIGH = (int) ((cHIGH / r) + 0.5); } else { eWIDE = cWIDE; eHIGH = cHIGH; } } if (eWIDE<1) eWIDE = 1; if (eHIGH<1) eHIGH = 1; SetCursors(-1); } /***********************************/ void Rotate(dir) int dir; { /* called when rotate CW and rotate CCW controls are clicked */ /* dir=0: clockwise, else counter-clockwise */ if (HaveSelection()) EnableSelection(0); 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; } SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH); SetISTR(ISTR_EXPAND, "%.5g%% x %.5g%% (%d x %d)", 100.0 * ((float) eWIDE) / cWIDE, 100.0 * ((float) eHIGH) / cHIGH, eWIDE, eHIGH); } /************************/ 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((size_t) (w*h*bperpix)); if (!pic1) FatalError("Not enough memory to rotate!"); /* do the rotation */ if (dir==0) { for (i=0; i=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=0; i--) { /* CCW */ if (bperpix == 1) { for (j=0, pix=pic+i; jdata; 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>= 1; bit++; } if (j0) nextptr[-1] += ((err*3)/16); if (j>(7-bit); /* write partial byte at end of line */ } else { /* order==MSBFirst */ bit = pix8 = 0; for (j=0; j0) nextptr[-1] += ((err*3)/16); if (j0) nextptr[-1] += ((err*3)/16); if (j=0; j--, pp--, thisptr--, nextptr--) { if (*thisptr<128) { err = *thisptr; *pp = (byte) bval; } else { err = *thisptr-255; *pp = (byte) wval; } if (j>0) thisptr[-1] += ((err*7)/16); if (i0) nextptr[-1] += (err/16); if (j 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((size_t) (xim->bytes_per_line * high)); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; floydDitherize1(xim, pic8, PIC8, (int) wide, (int) 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, (int) wide, (int) high, rmap, gmap, bmap, (int) ((dispDEEP <= 8) ? black : 0), (int) ((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((size_t) (imWIDE * high)); if (!imagedata) FatalError("couldn't malloc imagedata"); pp = (dithpic) ? dithpic : pic8; for (i=0, ip=imagedata; ibytes_per_line; imagedata = (byte *) malloc((size_t) (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; ibits_per_pixel == 8) { for (i=wide*high, ip=imagedata; i>0; i--,pp++,ip++) { if (((i+1)&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((size_t) (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; ibitmap_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; ibitmap_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+1)&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((size_t) (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+1)&0x1ffff) == 0) WaitCursor(); *ip = (dithpic) ? *pp : (byte) xcolors[*pp]; } } break; /*********************************/ case 12: case 15: case 16: { byte *imagedata, *ip; byte *pp; imagedata = (byte *) malloc((size_t) (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+1)&0x1ffff) == 0) WaitCursor(); if (dithpic) xcol = ((*pp) ? white : black) & 0xffff; else xcol = xcolors[*pp] & 0xffff; *(ip++) = (xcol>>8) & 0xff; *(ip++) = (xcol) & 0xff; } } else { /* LSBFirst */ for (i=wide*high, ip=imagedata; i>0; i--,pp++) { if (((i+1)&0x1ffff) == 0) WaitCursor(); if (dithpic) xcol = ((*pp) ? white : black) & 0xffff; else xcol = xcolors[*pp]; *(ip++) = (xcol) & 0xff; *(ip++) = (xcol>>8) & 0xff; } } } break; /*********************************/ case 24: case 32: { byte *imagedata, *ip, *pp, *tip; int j, do32; imagedata = (byte *) malloc((size_t) (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!"); do32 = (xim->bits_per_pixel == 32); pp = (dithpic) ? dithpic : pic8; if (xim->byte_order == MSBFirst) { for (i=0, ip=imagedata; i>16) & 0xff; *tip++ = (xcol>>8) & 0xff; *tip++ = xcol & 0xff; } ip += xim->bytes_per_line; } } else { /* LSBFirst */ for (i=0, ip=imagedata; i>8) & 0xff; *tip++ = (xcol>>16) & 0xff; if (do32) *tip++ = 0; } ip += xim->bytes_per_line; } } } break; /*********************************/ default: sprintf(str,"no code to handle this display type (%d bits deep)", dispDEEP); FatalError(str); break; } if (dithpic) free(dithpic); return(xim); } static int foo = 0; /***********************************/ XImage *Pic24ToXImage(pic24, wide, high) byte *pic24; unsigned 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((size_t) (xim->bytes_per_line * high)); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; floydDitherize1(xim, pic24,PIC24, (int) wide, (int) high, NULL,NULL,NULL); return xim; } if (theVisual->class == TrueColor || theVisual->class == DirectColor) { /************************************************************************/ /* Non-ColorMapped Visuals: TrueColor, DirectColor */ /************************************************************************/ unsigned long xcol; int bperpix, bperline; byte *imagedata, *lip, *ip, *pp; 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; imagedata = (byte *) malloc((size_t) (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); } screen_init(); #ifdef DO_FIXPIX_SMOOTH #if 0 /* If we wouldn't have to save the original pic24 image data, * the following code would do the dither job by overwriting * the image data, and the normal render code would then work * without any change on that data. * Unfortunately, this approach would hurt the xv assumptions... */ if (bperpix < 24) { FSBUF *fs = fs2_init(wide); if (fs) { fs2_dither(fs, pic24, 3, high, wide); free(fs); } } #else /* ...so we have to take a different approach with linewise * dithering/rendering in a loop using a temporary line buffer. */ if (bperpix < 24) { FSBUF *fs = fs2_init(wide); if (fs) { byte *row_buf = malloc((size_t)wide * 3); if (row_buf) { int nc = 3; byte *picp = pic24; lip = imagedata; for (i=0; i> 16) & 0xff; *ip++ = (xcol >> 8) & 0xff; *ip++ = xcol & 0xff; break; case 32: *((CARD32 *)ip) = (CARD32)xcol; ip += 4; break; } } } } 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, (int) wide, (int) high, NULL, NULL, NULL, (int) ((dispDEEP <= 8) ? black : 0), (int) ((dispDEEP <= 8) ? white : 1)); bwdith = 1; } else { /* do color dither using stdcmap */ pic8 = Do332ColorDither(pic24, NULL, (int) wide, (int) 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((size_t) (imWIDE * high)); if (!imagedata) FatalError("couldn't malloc imagedata"); for (i=0, pp=pic8, ip=imagedata; ibytes_per_line; imagedata = (byte *) malloc((size_t) (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; ibyte_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; ibytes_per_line; imagedata = (byte *) malloc((size_t) (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; ibitmap_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; ibitmap_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; ibits_per_pixel != 8) FatalError("This display's too bizarre. Can't create XImage."); bperline = xim->bytes_per_line; imagedata = (byte *) malloc((size_t) (bperline * high)); if (!imagedata) FatalError("couldn't malloc imagedata"); xim->data = (char *) imagedata; pp = pic8; for (i=0, lip=imagedata; ibytes_per_line; pp = pic8; if (xim->byte_order == MSBFirst) { for (i=0, lip=imagedata; i>8) & 0xff) | ((xcol&0xff) << 8); */ *ip++ = (unsigned short) (xcol); } } } } 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((size_t) (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+1)&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+1)&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 == RMB_WINDOW) ? 0 : 1; dispMB.dim[DMB_COLOWNC] = (dispMode == RMB_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' */ } SetDirSaveMode(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; unsigned long hb; hb = 0x80; hb = hb << 24; /* hb = 0x80000000UL */ for (i=31; ((ul & hb) == 0) && i>=0; i--, ul<<=1); return i; } /***********************************************************/ byte *XVGetSubImage(pic, ptype, w,h, sx,sy,sw,sh) byte *pic; int ptype, w,h, sx,sy,sw,sh; { /* mallocs and returns the selected subimage (sx,sy,sw,sh) of pic. selection is guaranteed to be within pic boundaries. NEVER RETURNS NULL */ byte *rpic, *sp, *dp; int bperpix,x,y; /* sanity check: */ if (sx<0 || sy<0 || sx+sw > w || sy+sh > h || sw<1 || sh<1) { fprintf(stderr,"XVGetSubImage: w,h=%d,%d sel = %d,%d %dx%d\n", w, h, sx, sy, sw, sh); FatalError("XVGetSubImage: value out of range (shouldn't happen!)"); } bperpix = (ptype==PIC8) ? 1 : 3; rpic = (byte *) malloc((size_t) bperpix * sw * sh); if (!rpic) FatalError("out of memory in XVGetSubImage"); for (y=0; ytype = padType; for (i=0; i<256; i++) { pinfo->r[i] = padmapR[i]; pinfo->g[i] = padmapG[i]; pinfo->b[i] = padmapB[i]; } pinfo->pic = padPic; pinfo->w = padWide; pinfo->h = padHigh; pinfo->frmType = -1; pinfo->colType = -1; sprintf(pinfo->fullInfo, "<%s internal>", (pinfo->type == PIC8) ? "8-bit" : "24-bit"); sprintf(pinfo->shrtInfo, "%dx%d image", padWide, padHigh); pinfo->comment = holdcomment; if (holdfname) { strcpy(fname, holdfname); free(holdfname); holdfname = (char *) NULL; } else strcpy(fname, ""); padPic = (byte *) NULL; holdcomment = (char *) NULL; return 1; } /*******************************/ static int doPadSolid(str, wide, high, opaque,omode) char *str; int wide, high, opaque,omode; { /* returns 0 on error, 1 if successful */ byte *pic24, *pp; int i, solidRGB, r,g,b,rgb; char errstr[256]; solidRGB = 0; /* PARSE STRING: 'r,g,b' 'r g b' '0xrrggbb' or */ if ((sscanf(str, "%d,%d,%d", &r,&g,&b) == 3) && (r>=0 && r<=255 && g>=0 && g<=255 && b>=0 && b<=255)) { solidRGB = ((r&0xff)<<16) | ((g&0xff)<<8) | (b&0xff); } else if ((sscanf(str, "%d %d %d", &r,&g,&b) == 3) && (r>=0 && r<=255 && g>=0 && g<=255 && b>=0 && b<=255)) { solidRGB = ((r&0xff)<<16) | ((g&0xff)<<8) | (b&0xff); } else if (sscanf(str, "0x%x", &rgb) && rgb>=0 && rgb<=0xffffff) { solidRGB = rgb; } else { /* assume a colorname */ XColor ecdef, sdef; if (XLookupColor(theDisp, theCmap, str, &ecdef, &sdef)) { solidRGB = (((ecdef.red >>8)&0xff) << 16) | (((ecdef.green>>8)&0xff) << 8) | (((ecdef.blue >>8)&0xff)); } else { sprintf(errstr, "Error: Color specification '%s' not recognized.",str); ErrPopUp(errstr, "\nOk"); return 0; } } pic24 = (byte *) malloc(wide * high * 3 * sizeof(byte)); if (!pic24) { sprintf(errstr,"Error: Can't alloc memory for %d x %d image.", wide, high); ErrPopUp(errstr, "\n:-("); return 0; } /* fill pic24 with solidRGB */ for (i=0,pp=pic24; i>16) & 0xff; pp[1] = (solidRGB>>8) & 0xff; pp[2] = (solidRGB) & 0xff; } i = doPadPaste(pic24, wide, high, opaque,omode); return i; } /*******************************/ static int doPadBggen(str, wide, high, opaque,omode) char *str; int wide, high, opaque,omode; { int i, tmpfd; byte *bgpic24; char syscmd[512], fname[128], errstr[512]; PICINFO pinfo; /* returns 0 on error, 1 if successful */ if (xv_strstr(str, "-h") || xv_strstr(str, "-w") || xv_strstr(str,"-g") || xv_strstr(str, ">")) { ErrPopUp( "Error: No redirection or '-h', '-w' or '-g' options are allowed.", "\nOk"); return 0; } #ifndef VMS sprintf(fname, "%s/xvXXXXXX", tmpdir); #else strcpy(fname, "Sys$Disk:[]xvuXXXXXX"); #endif mktemp(fname); tmpfd = open(fname, O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR); if (tmpfd < 0) { sprintf(errstr, "Error: can't create temporary file %s", fname); ErrPopUp(errstr, "\nDoh!"); return 0; } close(tmpfd); /* run bggen to generate the background */ sprintf(syscmd, "bggen -g %dx%d %s > %s", wide, high, str, fname); SetISTR(ISTR_INFO, "Running 'bggen %s'...", str); i = system(syscmd); #ifdef VMS i = !i; /* VMS returns 1 on success */ #endif if (i) { unlink(fname); sprintf(errstr, "Error: Running '%s' failed, for some reason.", syscmd); ErrPopUp(errstr, "\nDoh!"); return 0; } /* read the file that's been created */ if (!ReadImageFile1(fname, &pinfo)) { unlink(fname); return 0; } unlink(fname); if (pinfo.comment) free(pinfo.comment); pinfo.comment = (char *) NULL; if (pinfo.type == PIC24) bgpic24 = pinfo.pic; else { bgpic24 = Conv8to24(pinfo.pic,pinfo.w,pinfo.h, pinfo.r,pinfo.g,pinfo.b); free(pinfo.pic); pinfo.pic = (byte *) NULL; } if (!bgpic24) { ErrPopUp("Couldn't generate background image. malloc() failure?", "\nOk"); return 0; } i = doPadPaste(bgpic24, pinfo.w, pinfo.h, opaque,omode); return i; } /*******************************/ static int doPadLoad(str, wide, high, opaque,omode) char *str; int wide, high, opaque,omode; { int i; byte *bgpic24; char loadName[256]; PICINFO pinfo; /* returns 0 on error, 1 if successful */ /* use first word as filename to load. */ if (sscanf(str, "%s", loadName) != 1) { ErrPopUp("Error: The entered string is not valid.", "\nOk"); return 0; } if (!ReadImageFile1(loadName, &pinfo)) return 0; if (pinfo.comment) free(pinfo.comment); pinfo.comment = (char *) NULL; if (pinfo.type == PIC24) bgpic24 = pinfo.pic; else { bgpic24 = Conv8to24(pinfo.pic,pinfo.w,pinfo.h, pinfo.r,pinfo.g,pinfo.b); free(pinfo.pic); pinfo.pic = (byte *) NULL; } if (!bgpic24) { ErrPopUp("Couldn't generate background image. malloc() failure?", "\nOk"); return 0; } i = doPadPaste(bgpic24, pinfo.w, pinfo.h, opaque,omode); return i; } /*******************************/ static int doPadPaste(pic24, wide, high, opaque,omode) byte *pic24; int wide, high, opaque,omode; { /* copies 'pic' onto the given 24-bit background image, converts back to 8-bit (if necessary), and loads up pad* variables. frees pic24 if necessary */ byte *pp, *p24; int py,px, p24y,p24x, sx,sy; int fg, bg; int rval,gval,bval, r, g, b; fg = opaque; bg = 100 - opaque; /* copy 'pic' centered onto pic24. */ sx = (wide - cWIDE) / 2; sy = (high - cHIGH) / 2; for (py = 0; py= 0 && p24y < high) { for (px=0; px= 0 && p24x < wide) { p24 = pic24 + (p24y*wide + p24x)*3; if (picType == PIC24) { /* src is PIC24 */ pp = cpic + (py * cWIDE + px) *3; r = pp[0]; g = pp[1]; b = pp[2]; } else { /* src is PIC8 */ pp = cpic + (py*cWIDE + px); r = rMap[*pp]; g = gMap[*pp]; b = bMap[*pp]; } if (omode == PAD_ORGB) { rval = (r * fg) / 100 + ((int) p24[0] * bg) / 100; gval = (g * fg) / 100 + ((int) p24[1] * bg) / 100; bval = (b * fg) / 100 + ((int) p24[2] * bg) / 100; } else { /* one of the HSV modes */ double fh,fs,fv,fw, bh,bs,bv,bw, h,s,v; fw = fg / 100.0; bw = bg / 100.0; rgb2hsv(r,g,b, &fh,&fs,&fv); rgb2hsv((int) p24[0], (int) p24[1], (int) p24[2], &bh,&bs,&bv); h = s = v = 0.0; if (omode == PAD_OINT) { h = fh; s = fs; /* v = (fv * fg) / 100.0 + (bv * bg) / 100.0; */ v = (fv * bv * bw) + (fv * fw); } else if (omode == PAD_OSAT) { if (fh<0) fs = 0.0; /* NOHUE is unsaturated */ if (bh<0) bs = 0.0; h = fh; /* s = (fs * fg) / 100.0 + (bs * bg) / 100.0; */ s = (fs * bs * bw) + (fs * fw); v = fv; } else if (omode == PAD_OHUE) { /* the hard one! */ int fdeg,bdeg,len1,len2; fdeg = (fh<0) ? -1 : (int) floor(fh + 0.5); bdeg = (bh<0) ? -1 : (int) floor(bh + 0.5); if (fdeg>=0 && bdeg>=0) { /* both are colors */ /* convert H,S onto x,y coordinates on the colorwheel for constant V */ double fx,fy, bx,by, ox,oy; if (fg == 100 || bg == 100) { /* E-Z special case */ if (fg==100) { h = fh; s = fs; v=fv; } else { h = bh; s = fs; v=fv; } } else { /* general case */ fh *= (3.14159 / 180.0); /* -> radians */ bh *= (3.14159 / 180.0); fx = fs * cos(fh); fy = fs * sin(fh); bx = bs * cos(bh); by = bs * sin(bh); /* compute pt. on line between fx,fy and bx,by */ ox = (fx * (fg/100.0)) + (bx * (bg/100.0)); oy = (fy * (fg/100.0)) + (by * (bg/100.0)); /* convert ox,oy back into hue,sat */ s = sqrt((ox * ox) + (oy * oy)); if (ox == 0.0) { h = (oy>=0.0) ? 90.0 : 270.0; } else { h = atan(oy / ox); h *= (180.0 / 3.14159); if (ox<0.0) h += 180.0; while (h<0.0) h += 360.0; while (h>=360.0) h -= 360.0; } v = fv; } } else if (fdeg<0 && bdeg<0) { /* both are NOHUE */ h = -1.0; s = fs; v = fv; } else if (bdeg<0) { /* backgrnd is white */ h = fh; v = fv; s = (fs * fg) / 100.0; } else { /* foregrnd is white */ h = bh; v = fv; s = (bs * bg) / 100.0; } } v = (fv * bv * bw) + (fv * fw); hsv2rgb(h,s,v, &rval,&gval,&bval); } RANGE(rval, 0, 255); RANGE(gval, 0, 255); RANGE(bval, 0, 255); *p24++ = rval; *p24++ = gval; *p24++ = bval; } } } } /* build 'padPic' appropriately */ if (picType == PIC8) { /* put back to 8-bit */ padPic = Conv24to8(pic24, wide, high, ncols, padmapR, padmapG, padmapB); free(pic24); if (!padPic) { SetCursors(-1); ErrPopUp("Failure occured in 24to8 conversion\n","\nDamn!"); return 0; } padType = PIC8; padWide = wide; padHigh = high; } else { /* PIC24 */ padPic = pic24; padType = PIC24; padWide = wide; padHigh = high; } return 1; } /*******************************/ static int ReadImageFile1(name, pinfo) char *name; PICINFO *pinfo; { int i, ftype; char basefname[128], uncompname[128], errstr[256], *uncName, *readname; ftype = ReadFileType(name); if ((ftype == RFT_COMPRESS) || (ftype == RFT_BZIP2)) { /* handle compressed/gzipped files */ #ifdef VMS basefname[0] = '\0'; strcpy(basefname, name); /* remove trailing .Z */ *rindex(basefname, '.') = '\0'; uncName = basefname; #else uncName = name; #endif if (UncompressFile(uncName, uncompname, ftype)) { ftype = ReadFileType(uncompname); readname = uncompname; } else { sprintf(errstr, "Error: Couldn't uncompress file '%s'", name); ErrPopUp(errstr, "\nOk"); return 0; } } if (ftype == RFT_ERROR) { sprintf(errstr, "Couldn't open file '%s'\n\n %s.", name, ERRSTR(errno)); ErrPopUp(errstr, "\nOk"); return 0; } else if (ftype == RFT_UNKNOWN) { sprintf(errstr, "Error: File '%s' not in a recognized format.", name); ErrPopUp(errstr, "\nOk"); return 0; } else { /* try to read it */ i = ReadPicFile(name, ftype, pinfo, 1); KillPageFiles(pinfo->pagebname, pinfo->numpages); if (!i || (i && (pinfo->w<=0 || pinfo->h<=0))) { if (i) { if (pinfo->pic) free(pinfo->pic); if (pinfo->comment) free(pinfo->comment); } sprintf(errstr, "Couldn't load file '%s'.", name); ErrPopUp(errstr, "\nOk"); return 0; } /* got it! */ } return 1; }