1 /*
2  * xvimage.c - image manipulation functions (crop,resize,rotate...) for XV
3  *
4  *  Contains:
5  *            void Resize(int, int)
6  *            void GenerateCpic()
7  *            void GenerateEpic(w,h)
8  *            void Crop()
9  *            void UnCrop()
10  *            void AutoCrop()
11  *            void DoCrop(x,y,w,h)
12  *            void Rotate(int)
13  *            void RotatePic();
14  *            void InstallNewPic(void);
15  *            void DrawEpic(void);
16  *            byte *FSDither()
17  *            void CreateXImage()
18  *            void Set824Menus( pictype );
19  *            void Change824Mode( pictype );
20  *            int  DoPad(mode, str, wide, high, opaque, omode);
21  *            int  LoadPad(pinfo, fname);
22  */
23 
24 /* The following switch should better be provided at runtime for
25  * comparison purposes.
26  * At the moment it's only compile time, unfortunately.
27  * Who can make adaptions for use as a runtime switch by a menu option?
28  * [GRR 19980607:  now via do_fixpix_smooth global; macro renamed to ENABLE_]
29  * [see http://sylvana.net/fixpix/ for home page, further info]
30  */
31 /* #define ENABLE_FIXPIX_SMOOTH */   /* GRR 19980607:  moved into xv.h */
32 
33 #define  NEEDSDIR             /* for S_IRUSR|S_IWUSR */
34 #include "copyright.h"
35 
36 #include "xv.h"
37 
38 
39 static void flipSel           PARM((int));
40 static void do_zoom           PARM((int, int));
41 static void compute_zoom_rect PARM((int, int, int*, int*, int*, int*));
42 static void do_unzoom         PARM((void));
43 static void do_pan            PARM((int, int));
44 static void do_pan_calc       PARM((int, int, int *, int *));
45 static void crop1             PARM((int, int, int, int, int));
46 static int  doAutoCrop24      PARM((void));
47 static void floydDitherize1   PARM((XImage *, byte *, int, int, int,
48 				    byte *, byte *,byte *));
49 #if 0 /* NOTUSED */
50 static int  highbit           PARM((unsigned long));
51 #endif
52 
53 static int  doPadSolid        PARM((char *, int, int, int, int));
54 static int  doPadBggen        PARM((char *, int, int, int, int));
55 static int  doPadLoad         PARM((char *, int, int, int, int));
56 
57 static int  doPadPaste        PARM((byte *, int, int, int, int));
58 static int  ReadImageFile1    PARM((char *, PICINFO *));
59 
60 
61 /* The following array represents the pixel values for each shade
62  * of the primary color components.
63  * If 'p' is a pointer to a source image rgb-byte-triplet, we can
64  * construct the output pixel value simply by 'oring' together
65  * the corresponding components:
66  *
67  *	unsigned char *p;
68  *	unsigned long pixval;
69  *
70  *	pixval  = screen_rgb[0][*p++];
71  *	pixval |= screen_rgb[1][*p++];
72  *	pixval |= screen_rgb[2][*p++];
73  *
74  * This is both efficient and generic, since the only assumption
75  * is that the primary color components have separate bits.
76  * The order and distribution of bits does not matter, and we
77  * don't need additional variables and shifting/masking code.
78  * The array size is 3 KBytes total and thus very reasonable.
79  */
80 
81 static unsigned long screen_rgb[3][256];
82 
83 /* The following array holds the exact color representations
84  * reported by the system.
85  * This is useful for less than 24 bit deep displays as a base
86  * for additional dithering to get smoother output.
87  */
88 
89 static byte screen_set[3][256];
90 
91 /* The following routine initializes the screen_rgb and screen_set
92  * arrays.
93  * Since it is executed only once per program run, it does not need
94  * to be super-efficient.
95  *
96  * The method is to draw points in a pixmap with the specified shades
97  * of primary colors and then get the corresponding XImage pixel
98  * representation.
99  * Thus we can get away with any Bit-order/Byte-order dependencies.
100  *
101  * The routine uses some global X variables: theDisp, theScreen,
102  * and dispDEEP. Adapt these to your application as necessary.
103  * I've not passed them in as parameters, since for other platforms
104  * than X these may be different (see vfixpix.c), and so the
105  * screen_init() interface is unique.
106  *
107  * BUG: I've read in the "Xlib Programming Manual" from O'Reilly &
108  * Associates, that the DefaultColormap in TrueColor might not
109  * provide the full shade representation in XAllocColor.
110  * In this case one had to provide a 'best' colormap instead.
111  * However, my tests with Xaccel on a Linux-Box with a Mach64
112  * card were fully successful, so I leave that potential problem
113  * to you at the moment and would appreciate any suggestions...
114  */
115 
screen_init()116 static void screen_init()
117 {
118   static int init_flag; /* assume auto-init as 0 */
119   Pixmap check_map;
120   GC check_gc;
121   XColor check_col;
122   XImage *check_image;
123   int ci, i;
124 
125   if (init_flag) return;
126   init_flag = 1;
127 
128   check_map = XCreatePixmap(theDisp, RootWindow(theDisp,theScreen),
129 			    1, 1, dispDEEP);
130   check_gc = XCreateGC(theDisp, check_map, 0, NULL);
131   for (ci = 0; ci < 3; ci++) {
132     for (i = 0; i < 256; i++) {
133       check_col.red = 0;
134       check_col.green = 0;
135       check_col.blue = 0;
136       /* Do proper upscaling from unsigned 8 bit (image data values)
137 	 to unsigned 16 bit (X color representation). */
138       ((unsigned short *)&check_col.red)[ci] = (unsigned short)((i << 8) | i);
139       if (theVisual->class == TrueColor)
140 	XAllocColor(theDisp, theCmap, &check_col);
141       else
142 	xvAllocColor(theDisp, theCmap, &check_col);
143       screen_set[ci][i] =
144 	(((unsigned short *)&check_col.red)[ci] >> 8) & 0xff;
145       XSetForeground(theDisp, check_gc, check_col.pixel);
146       XDrawPoint(theDisp, check_map, check_gc, 0, 0);
147       check_image = XGetImage(theDisp, check_map, 0, 0, 1, 1,
148 			      AllPlanes, ZPixmap);
149       if (check_image) {
150 	switch (check_image->bits_per_pixel) {
151 	case 8:
152 	  screen_rgb[ci][i] = *(CARD8 *)check_image->data;
153 	  break;
154 	case 16:
155 	  screen_rgb[ci][i] = *(CARD16 *)check_image->data;
156 	  break;
157 	case 24:
158 	  screen_rgb[ci][i] =
159 	    ((unsigned long)*(CARD8 *)check_image->data << 16) |
160 	    ((unsigned long)*(CARD8 *)(check_image->data + 1) << 8) |
161 	    (unsigned long)*(CARD8 *)(check_image->data + 2);
162 	  break;
163 	case 32:
164 	  screen_rgb[ci][i] = *(CARD32 *)check_image->data;
165 	  break;
166 	}
167 	XDestroyImage(check_image);
168       }
169     }
170   }
171   XFreeGC(theDisp, check_gc);
172   XFreePixmap(theDisp, check_map);
173 }
174 
175 
176 #ifdef ENABLE_FIXPIX_SMOOTH
177 
178 /* The following code is based in part on:
179  *
180  * jquant1.c
181  *
182  * Copyright (C) 1991-1996, Thomas G. Lane.
183  * This file is part of the Independent JPEG Group's software.
184  * For conditions of distribution and use, see the accompanying README file.
185  *
186  * This file contains 1-pass color quantization (color mapping) routines.
187  * These routines provide mapping to a fixed color map using equally spaced
188  * color values.  Optional Floyd-Steinberg or ordered dithering is available.
189  */
190 
191 /* Declarations for Floyd-Steinberg dithering.
192  *
193  * Errors are accumulated into the array fserrors[], at a resolution of
194  * 1/16th of a pixel count.  The error at a given pixel is propagated
195  * to its not-yet-processed neighbors using the standard F-S fractions,
196  *		...	(here)	7/16
197  *		3/16	5/16	1/16
198  * We work left-to-right on even rows, right-to-left on odd rows.
199  *
200  * We can get away with a single array (holding one row's worth of errors)
201  * by using it to store the current row's errors at pixel columns not yet
202  * processed, but the next row's errors at columns already processed.  We
203  * need only a few extra variables to hold the errors immediately around the
204  * current column.  (If we are lucky, those variables are in registers, but
205  * even if not, they're probably cheaper to access than array elements are.)
206  *
207  * We provide (#columns + 2) entries per component; the extra entry at each
208  * end saves us from special-casing the first and last pixels.
209  */
210 
211 typedef INT16 FSERROR;		/* 16 bits should be enough */
212 typedef int LOCFSERROR;		/* use 'int' for calculation temps */
213 
214 typedef struct { byte    *colorset;
215 		 FSERROR *fserrors;
216 	       } FSBUF;
217 
218 /* Floyd-Steinberg initialization function.
219  *
220  * It is called 'fs2_init' since it's specialized for our purpose and
221  * could be embedded in a more general FS-package.
222  *
223  * Returns a malloced FSBUF pointer which has to be passed as first
224  * parameter to subsequent 'fs2_dither' calls.
225  * The FSBUF structure does not need to be referenced by the calling
226  * application, it can be treated from the app like a void pointer.
227  *
228  * The current implementation does only require to free() this returned
229  * pointer after processing.
230  *
231  * Returns NULL if malloc fails.
232  *
233  * NOTE: The FSBUF structure is designed to allow the 'fs2_dither'
234  * function to work with an *arbitrary* number of color components
235  * at runtime! This is an enhancement over the IJG code base :-).
236  * Only fs2_init() specifies the (maximum) number of components.
237  */
238 
fs2_init(width)239 static FSBUF *fs2_init(width)
240 int width;
241 {
242   FSBUF *fs;
243   FSERROR *p;
244 
245   fs = (FSBUF *)
246     malloc(sizeof(FSBUF) * 3 + ((size_t)width + 2) * sizeof(FSERROR) * 3);
247   if (fs == 0) return fs;
248 
249   fs[0].colorset = screen_set[0];
250   fs[1].colorset = screen_set[1];
251   fs[2].colorset = screen_set[2];
252 
253   p = (FSERROR *)(fs + 3);
254   memset(p, 0, ((size_t)width + 2) * sizeof(FSERROR) * 3);
255 
256   fs[0].fserrors = p;
257   fs[1].fserrors = p + 1;
258   fs[2].fserrors = p + 2;
259 
260   return fs;
261 }
262 
263 /* Floyd-Steinberg dithering function.
264  *
265  * NOTE:
266  * (1) The image data referenced by 'ptr' is *overwritten* (input *and*
267  *     output) to allow more efficient implementation.
268  * (2) Alternate FS dithering is provided by the sign of 'nc'. Pass in
269  *     a negative value for right-to-left processing. The return value
270  *     provides the right-signed value for subsequent calls!
271  * (3) This particular implementation assumes *no* padding between lines!
272  *     Adapt this if necessary.
273  */
274 
fs2_dither(fs,ptr,nc,num_rows,num_cols)275 static int fs2_dither(fs, ptr, nc, num_rows, num_cols)
276 FSBUF *fs;
277 byte *ptr;
278 int nc, num_rows, num_cols;
279 {
280   int abs_nc, ci, row, col;
281   LOCFSERROR delta, cur, belowerr, bpreverr;
282   byte *dataptr, *colsetptr;
283   FSERROR *errorptr;
284 
285   if ((abs_nc = nc) < 0) abs_nc = -abs_nc;
286   for (row = 0; row < num_rows; row++) {
287     for (ci = 0; ci < abs_nc; ci++, ptr++) {
288       dataptr = ptr;
289       colsetptr = fs[ci].colorset;
290       errorptr = fs[ci].fserrors;
291       if (nc < 0) {
292 	dataptr += (num_cols - 1) * abs_nc;
293 	errorptr += (num_cols + 1) * abs_nc;
294       }
295       cur = belowerr = bpreverr = 0;
296       for (col = 0; col < num_cols; col++) {
297 	cur += errorptr[nc];
298 	cur += 8; cur >>= 4;
299 	if ((cur += *dataptr) < 0) cur = 0;
300 	else if (cur > 255) cur = 255;
301 	*dataptr = cur & 0xff;
302 	cur -= colsetptr[cur];
303 	delta = cur << 1; cur += delta;
304 	bpreverr += cur; cur += delta;
305 	belowerr += cur; cur += delta;
306 	errorptr[0] = (FSERROR)bpreverr;
307 	bpreverr = belowerr;
308 	belowerr = delta >> 1;
309 	dataptr += nc;
310 	errorptr += nc;
311       }
312       errorptr[0] = (FSERROR)bpreverr;
313     }
314     ptr += (num_cols - 1) * abs_nc;
315     nc = -nc;
316   }
317   return nc;
318 }
319 
320 #endif /* ENABLE_FIXPIX_SMOOTH */
321 
322 
323 #define DO_CROP 0
324 #define DO_ZOOM 1
325 
326 
327 /***********************************/
Resize(w,h)328 void Resize(w,h)
329 int w,h;
330 {
331   RANGE(w,1,maxWIDE);  RANGE(h,1,maxHIGH);
332 
333   if (HaveSelection()) DrawSelection(0);  /* turn off old rect */
334 
335   if (psUp) PSResize();   /* if PSDialog is open, mention size change  */
336 
337   /* if same size, and Ximage created, do nothing */
338   if (w==eWIDE && h==eHIGH && theImage!=NULL) return;
339 
340   if (DEBUG) fprintf(stderr,"Resize(%d,%d)  eSIZE=%d,%d  cSIZE=%d,%d\n",
341 		     w,h,eWIDE,eHIGH,cWIDE,cHIGH);
342 
343   if (epicMode == EM_SMOOTH) {  /* turn off smoothing */
344     epicMode = EM_RAW;  SetEpicMode();
345   }
346 
347   GenerateEpic(w,h);
348   CreateXImage();
349 }
350 
351 
352 
353 /********************************************/
GenerateCpic()354 void GenerateCpic()
355 {
356   /* called when 'pic' has been modified (different contents, *not* different
357      size, orientation, etc.  Rebuilds cpic. */
358 
359   int   i, j, bperpix;
360   byte *pp, *cp;
361 
362   if (cpic == pic) return;     /* no cropping, nothing to do */
363 
364   cp = cpic;
365   bperpix = (picType == PIC8) ? 1 : 3;
366 
367   for (i=0; i<cHIGH; i++) {
368     if ((i&63)==0) WaitCursor();
369     pp = pic + (i+cYOFF) * (pWIDE*bperpix) + (cXOFF * bperpix);
370     for (j=0; j<cWIDE*bperpix; j++)
371       *cp++ = *pp++;
372   }
373 }
374 
375 
376 
377 /***********************************/
GenerateEpic(w,h)378 void GenerateEpic(w,h)
379 int w,h;
380 {
381   int          cy,ex,ey,*cxarr, *cxarrp;
382   byte        *clptr,*elptr,*epptr;
383 
384   WaitCursor();
385   clptr = NULL;  cxarrp = NULL;  cy = 0;  /* shut up compiler */
386 
387   SetISTR(ISTR_EXPAND, "%.5g%% x %.5g%%  (%d x %d)",
388 	  100.0 * ((float) w) / cWIDE,
389 	  100.0 * ((float) h) / cHIGH, w, h);
390 
391   if (DEBUG)
392     fprintf(stderr,"GenerateEpic(%d,%d) eSIZE=%d,%d cSIZE=%d,%d epicode=%d\n",
393 		     w,h,eWIDE,eHIGH,cWIDE,cHIGH, epicMode);
394 
395 
396   FreeEpic();                   /* get rid of the old one */
397   eWIDE = w;  eHIGH = h;
398 
399 
400   if (epicMode == EM_SMOOTH) {
401     if (picType == PIC8) {
402       epic = SmoothResize(cpic, cWIDE, cHIGH, eWIDE, eHIGH,
403 			  rMap,gMap,bMap, rdisp,gdisp,bdisp, numcols);
404     }
405     else {  /* PIC24 */
406       epic = Smooth24(cpic, 1, cWIDE, cHIGH, eWIDE, eHIGH, NULL, NULL, NULL);
407     }
408 
409     if (epic) return;   /* success */
410     else {
411       /* failed.  Try to generate a *raw* image, at least... */
412       epicMode = EM_RAW;  SetEpicMode();
413       /* fall through to rest of code */
414     }
415   }
416 
417 
418   /* generate a 'raw' epic, as we'll need it for ColorDither if EM_DITH */
419 
420   if (eWIDE==cWIDE && eHIGH==cHIGH) {  /* 1:1 expansion.  point epic at cpic */
421     epic = cpic;
422   }
423   else {
424     /* run the rescaling algorithm */
425     int bperpix;
426 
427     bperpix = (picType == PIC8) ? 1 : 3;
428 
429     WaitCursor();
430 
431     /* create a new epic of the appropriate size */
432 
433     epic = (byte *) malloc((size_t) (eWIDE * eHIGH * bperpix));
434     if (!epic) FatalError("GenerateEpic():  unable to malloc 'epic'");
435 
436     /* the scaling routine.  not really all that scary after all... */
437 
438     /* OPTIMIZATON:  Malloc an eWIDE array of ints which will hold the
439        values of the equation px = (pWIDE * ex) / eWIDE.  Faster than doing
440        a mul and a div for every point in picture */
441 
442     cxarr = (int *) malloc(eWIDE * sizeof(int));
443     if (!cxarr) FatalError("unable to allocate cxarr");
444 
445     for (ex=0; ex<eWIDE; ex++)
446       cxarr[ex] = bperpix * ((cWIDE * ex) / eWIDE);
447 
448     elptr = epptr = epic;
449 
450     for (ey=0;  ey<eHIGH;  ey++, elptr+=(eWIDE*bperpix)) {
451       ProgressMeter(0, (eHIGH)-1, ey, "Resize");
452       if ((ey&63) == 0) WaitCursor();
453       cy = (cHIGH * ey) / eHIGH;
454       epptr = elptr;
455       clptr = cpic + (cy * cWIDE * bperpix);
456 
457       if (bperpix == 1) {
458 	for (ex=0, cxarrp = cxarr;  ex<eWIDE;  ex++, epptr++)
459 	  *epptr = clptr[*cxarrp++];
460       }
461       else {
462 	int j;  byte *cp;
463 
464 	for (ex=0, cxarrp = cxarr; ex<eWIDE; ex++,cxarrp++) {
465 	  cp = clptr + *cxarrp;
466 	  for (j=0; j<bperpix; j++)
467 	    *epptr++ = *cp++;
468 	}
469       }
470     }
471     free(cxarr);
472   }
473 
474 
475   /* at this point, we have a raw epic.  Potentially dither it */
476   if (picType == PIC8 && epicMode == EM_DITH) {
477     byte *tmp;
478 
479     tmp = DoColorDither(NULL, epic, eWIDE, eHIGH, rMap,gMap,bMap,
480 			rdisp,gdisp,bdisp, numcols);
481     if (tmp) {  /* success */
482       FreeEpic();
483       epic = tmp;
484     }
485     else {  /* well... just use the raw image. */
486       epicMode = EM_RAW;  SetEpicMode();
487     }
488   }
489 }
490 
491 
492 
493 /***********************************/
DoZoom(x,y,button)494 void DoZoom(x,y,button)
495      int          x, y;
496      unsigned int button;
497 {
498   if      (button == Button1) do_zoom(x,y);
499   else if (button == Button2) do_pan(x,y);
500   else if (button == Button3) do_unzoom();
501   else XBell(theDisp,0);
502 }
503 
504 
505 /***********************************/
do_zoom(mx,my)506 static void do_zoom(mx,my)
507      int mx,my;
508 {
509   int i;
510   int rx,ry,rx2,ry2, orx, ory, orw, orh;
511   int px,py,pw,ph,opx,opy,opw,oph,m;
512   Window rW, cW;  unsigned int mask;  int rtx, rty;
513 
514   m = 0;
515 
516   XSetFunction(theDisp, theGC, GXinvert);
517   XSetPlaneMask(theDisp, theGC, xorMasks[m]);
518 
519   compute_zoom_rect(mx, my, &px, &py, &pw, &ph);
520   CoordP2E(px,    py,    &rx, &ry);
521   CoordP2E(px+pw, py+ph, &rx2,&ry2);
522   opx=px;  opy=py;  opw=pw;  oph=ph;
523   orx = rx;  ory = ry;  orw = (rx2-rx);  orh = (ry2-ry);
524   XDrawRectangle(theDisp,mainW,theGC,orx,ory, (u_int)orw, (u_int)orh);
525 
526   /* track until Button1 is released.  If ctrl is released, cancel */
527   while (1) {
528     if (!XQueryPointer(theDisp,mainW,&rW,&cW,&rtx,&rty,
529 		       &mx,&my,&mask)) continue;
530 
531     if (!(mask & ControlMask)) break;
532     if (!(mask & Button1Mask)) break;  /* button released */
533 
534     compute_zoom_rect(mx, my, &px, &py, &pw, &ph);
535     if (px!=opx || py!=opy) {
536       XDrawRectangle(theDisp,mainW,theGC, orx,ory, (u_int)orw, (u_int)orh);
537       opx = px;  opy = py;  opw = pw;  opy = py;
538       CoordP2E(opx,     opy,     &rx, &ry);
539       CoordP2E(opx+opw, opy+oph, &rx2,&ry2);
540       orx = rx;  ory = ry;  orw = (rx2-rx);  orh = (ry2-ry);
541       XDrawRectangle(theDisp,mainW,theGC, orx,ory, (u_int)orw, (u_int)orh);
542     }
543     else {
544       XDrawRectangle(theDisp,mainW,theGC, orx,ory, (u_int)orw, (u_int)orh);
545       m = (m+1)&7;
546       XSetPlaneMask(theDisp, theGC, xorMasks[m]);
547       XDrawRectangle(theDisp,mainW,theGC, orx,ory, (u_int)orw, (u_int)orh);
548       XFlush(theDisp);
549       Timer(100);
550     }
551   }
552 
553   if (!(mask & ControlMask)) {  /* cancelled */
554     XDrawRectangle(theDisp, mainW, theGC, orx, ory, (u_int) orw, (u_int) orh);
555     XSetFunction(theDisp, theGC, GXcopy);
556     XSetPlaneMask(theDisp, theGC, AllPlanes);
557     return;
558   }
559 
560 
561   for (i=0; i<4; i++) {
562     XDrawRectangle(theDisp, mainW, theGC, orx, ory, (u_int) orw, (u_int) orh);
563     XFlush(theDisp);
564     Timer(100);
565   }
566 
567   XSetFunction(theDisp, theGC, GXcopy);
568   XSetPlaneMask(theDisp, theGC, AllPlanes);
569 
570   /* if rectangle is *completely* outside epic, don't zoom */
571   if (orx+orw<0 || ory+orh<0 || orx>=eWIDE || ory>=eHIGH) return;
572 
573 
574   crop1(opx, opy, opw, oph, DO_ZOOM);
575 }
576 
577 
578 /***********************************/
compute_zoom_rect(x,y,px,py,pw,ph)579 static void compute_zoom_rect(x, y, px, py, pw, ph)
580      int x, y, *px, *py, *pw, *ph;
581 {
582   /* given a mouse pos (in epic coords), return x,y,w,h PIC coords for
583      a 'zoom in by 2x' rectangle to be tracked.  The rectangle stays
584      completely within 'pic' boundaries, and moves in 'pic' increments */
585 
586   CoordE2P(x, y, px, py);
587   *pw = (cWIDE+1)/2;
588   *ph = (cHIGH+1)/2;
589 
590   *px = *px - (*pw)/2;
591   *py = *py - (*ph)/2;
592 
593   RANGE(*px, 0, pWIDE - *pw);
594   RANGE(*py, 0, pHIGH - *ph);
595 }
596 
597 
598 /***********************************/
do_unzoom()599 static void do_unzoom()
600 {
601   int x,y,w,h, x2,y2, ex,ey,ew,eh;
602 
603   /* compute a cropping rectangle (in pic coordinates) that's twice
604      the size of eWIDE,eHIGH, centered around eWIDE/2, eHIGH/2, but no
605      larger than pWIDE,PHIGH */
606 
607   if (!but[BUNCROP].active) {    /* not cropped, can't zoom out */
608     XBell(theDisp, 0);
609     return;
610   }
611 
612   ex = -eWIDE/2;  ey = -eHIGH/2;
613   ew =  eWIDE*2;  eh =  eHIGH*2;
614 
615   CoordE2P(ex, ey, &x, &y);
616   CoordE2P(ex+ew, ey+eh, &x2, &y2);
617   w = x2 - x;  h = y2 - y;
618 
619   RANGE(w, 1, pWIDE);
620   RANGE(h, 1, pHIGH);
621 
622   if (x<0) x = 0;
623   if (y<0) y = 0;
624   if (x+w > pWIDE) x = pWIDE - w;
625   if (y+h > pHIGH) y = pHIGH - h;
626 
627   crop1(x,y,w,h, DO_ZOOM);
628 }
629 
630 
631 /***********************************/
do_pan(mx,my)632 static void do_pan(mx,my)
633      int mx,my;
634 {
635   int i, ox,oy,offx,offy, rw,rh, px, py, dx, dy,m;
636   Window rW, cW;  unsigned int mask;  int rx, ry;
637 
638   offx = ox = mx;
639   offy = oy = my;
640   rw = eWIDE-1;  rh = eHIGH-1;
641   m = 0;
642 
643   XSetFunction(theDisp, theGC, GXinvert);
644   XSetPlaneMask(theDisp, theGC, xorMasks[m]);
645 
646   XDrawRectangle(theDisp,mainW,theGC, mx-offx, my-offy, (u_int)rw, (u_int)rh);
647 
648   /* track until Button2 is released */
649   while (1) {
650     if (!XQueryPointer(theDisp, mainW, &rW, &cW, &rx, &ry,
651 		       &mx, &my, &mask)) continue;
652     if (!(mask & ControlMask)) break;  /* cancelled */
653     if (!(mask & Button2Mask)) break;  /* button released */
654 
655     if (mask & ShiftMask) {    /* constrain mx,my to horiz or vertical */
656       if (abs(mx-offx) > abs(my-offy)) my = offy;
657       else mx = offx;
658     }
659 
660     do_pan_calc(offx, offy, &mx, &my);
661 
662     if (mx!=ox || my!=oy) {
663       XDrawRectangle(theDisp, mainW, theGC, ox-offx, oy-offy,
664 		     (u_int) rw, (u_int) rh);
665       XDrawRectangle(theDisp, mainW, theGC, mx-offx, my-offy,
666 		     (u_int) rw, (u_int) rh);
667       ox = mx;  oy = my;
668     }
669     else {
670       XDrawRectangle(theDisp, mainW, theGC, ox-offx, oy-offy,
671 		     (u_int) rw, (u_int) rh);
672       m = (m+1)&7;
673       XSetPlaneMask(theDisp, theGC, xorMasks[m]);
674       XDrawRectangle(theDisp, mainW, theGC, ox-offx, oy-offy,
675 		     (u_int) rw, (u_int) rh);
676       XFlush(theDisp);
677       Timer(100);
678     }
679   }
680 
681   mx = ox;  my = oy;  /* in case mx,my changed on button release */
682 
683   if (!(mask & ControlMask)) {  /* cancelled */
684     XDrawRectangle(theDisp, mainW, theGC, mx-offx, my-offy,
685 		   (u_int) rw, (u_int) rh);
686     XSetFunction(theDisp, theGC, GXcopy);
687     XSetPlaneMask(theDisp, theGC, AllPlanes);
688     return;
689   }
690 
691 
692   for (i=0; i<4; i++) {
693     XDrawRectangle(theDisp, mainW, theGC, mx-offx, my-offy,
694 		   (u_int) rw, (u_int) rh);
695     XFlush(theDisp);
696     Timer(100);
697   }
698 
699 
700   /* mx-offx, my-offy is top-left corner of pan rect, in epic coords */
701 
702   CoordE2P(mx-offx, my-offy, &px, &py);
703   dx = px - cXOFF;  dy = py - cYOFF;
704 
705   if (dx==0 && dy==0) {  /* didn't pan anywhere */
706     XDrawRectangle(theDisp, mainW, theGC, mx-offx, my-offy,
707 		   (u_int) rw, (u_int) rh);
708     XSetFunction(theDisp, theGC, GXcopy);
709     XSetPlaneMask(theDisp, theGC, AllPlanes);
710     return;
711   }
712 
713 
714   XSetFunction(theDisp, theGC, GXcopy);
715   XSetPlaneMask(theDisp, theGC, AllPlanes);
716 
717   crop1(cXOFF-dx, cYOFF-dy, cWIDE, cHIGH, DO_ZOOM);
718 }
719 
720 
721 /***********************************/
do_pan_calc(offx,offy,xp,yp)722 static void do_pan_calc(offx, offy, xp,yp)
723      int offx, offy, *xp, *yp;
724 {
725   /* given mouse coords (in xp,yp) and original offset, compute 'clipped'
726      coords (returned in xp,yp) such that the 'pan window' remains entirely
727      within the image boundaries */
728 
729   int mx, my, eprx, epry, eprw, eprh, pprx, ppry, pprw, pprh;
730 
731   mx = *xp;  my = *yp;
732 
733   /* compute corners of pan rect in eWIDE,eHIGH coords */
734   eprx = offx - mx;
735   epry = offy - my;
736   eprw = eWIDE;
737   eprh = eHIGH;
738 
739   /* compute corners of pan rect in pWIDE,pHIGH coords */
740   CoordE2P(eprx, epry, &pprx, &ppry);
741   pprw = cWIDE;
742   pprh = cHIGH;
743 
744   /* if pan rect (in p* coords) is outside bounds of pic, move it inside */
745   if (pprx<0) pprx = 0;
746   if (ppry<0) ppry = 0;
747   if (pprx + pprw > pWIDE) pprx = pWIDE-pprw;
748   if (ppry + pprh > pHIGH) ppry = pHIGH-pprh;
749 
750   /* convert clipped pan rect back into eWIDE,eHIGH coords */
751   CoordP2E(pprx, ppry, &eprx, &epry);
752 
753   *xp = offx - eprx;
754   *yp = offy - epry;
755 }
756 
757 
758 /***********************************/
Crop()759 void Crop()
760 {
761   int x, y, w, h;
762 
763   if (!HaveSelection()) return;
764 
765   GetSelRCoords(&x,&y,&w,&h);
766   EnableSelection(0);
767   crop1(x,y,w,h,DO_CROP);
768 }
769 
770 
771 /**********************************/
crop1(x,y,w,h,zm)772 static void crop1(x,y,w,h,zm)
773      int x,y,w,h,zm;
774 {
775   int   oldew,oldeh,oldcx,oldcy;
776 
777   oldcx = cXOFF;  oldcy = cYOFF;
778   oldew = eWIDE;  oldeh = eHIGH;
779   DoCrop(x,y,w,h);
780   if (zm == DO_ZOOM) { eWIDE = oldew;  eHIGH = oldeh; }
781 
782   GenerateEpic(eWIDE, eHIGH);
783 
784   if (useroot) DrawEpic();
785   else {
786     if (zm == DO_CROP) {
787       WCrop(eWIDE, eHIGH, cXOFF-oldcx, cYOFF-oldcy);  /* shrink window */
788       CreateXImage();
789     }
790     else DrawEpic();
791   }
792   SetCursors(-1);
793 }
794 
795 
796 /***********************************/
UnCrop()797 void UnCrop()
798 {
799   int w,h;
800 
801   if (cpic == pic) return;     /* not cropped */
802 
803   BTSetActive(&but[BUNCROP],0);
804 
805   if (epicMode == EM_SMOOTH) {   /* turn off smoothing */
806     epicMode = EM_RAW;  SetEpicMode();
807   }
808 
809   /* dispose of old cpic and epic */
810   FreeEpic();
811   if (cpic && cpic !=  pic) free(cpic);
812   cpic = NULL;
813 
814 
815   w = (pWIDE * eWIDE) / cWIDE;   h = (pHIGH * eHIGH) / cHIGH;
816   if (w>maxWIDE || h>maxHIGH) {
817     /* return to 'normal' size */
818     if (pWIDE>maxWIDE || pHIGH>maxHIGH) {
819       double r,wr,hr;
820       wr = ((double) pWIDE) / maxWIDE;
821       hr = ((double) pHIGH) / maxHIGH;
822 
823       r = (wr>hr) ? wr : hr;   /* r is the max(wr,hr) */
824       w = (int) ((pWIDE / r) + 0.5);
825       h = (int) ((pHIGH / r) + 0.5);
826     }
827     else { w = pWIDE;  h = pHIGH; }
828   }
829 
830   cpic = pic;  cXOFF = cYOFF = 0;  cWIDE = pWIDE;  cHIGH = pHIGH;
831 
832 
833   /* generate an appropriate 'epic' */
834   GenerateEpic(w,h);
835   CreateXImage();
836 
837 
838   WUnCrop();
839   SetCropString();
840 }
841 
842 
843 /***********************************/
AutoCrop()844 void AutoCrop()
845 {
846   /* called when AutoCrop button is pressed */
847   int oldcx, oldcy;
848 
849   oldcx = cXOFF;  oldcy = cYOFF;
850 
851   if (DoAutoCrop()) {
852     if (useroot) DrawEpic();
853     else {
854       CreateXImage();
855       WCrop(eWIDE, eHIGH, cXOFF-oldcx, cYOFF-oldcy);
856     }
857   }
858 
859   SetCursors(-1);
860 }
861 
862 
863 /***********************************/
DoAutoCrop()864 int DoAutoCrop()
865 {
866   /* returns '1' if any cropping was actually done. */
867 
868   byte *cp, *cp1;
869   int  i, ctop, cbot, cleft, cright;
870   byte bgcol;
871 
872   ctop = cbot = cleft = cright = 0;
873 
874   if (picType == PIC24) return( doAutoCrop24() );
875 
876   /* crop the top */
877   cp = cpic;
878   bgcol = cp[0];
879 
880   while (ctop+1 < cHIGH) {
881     /* see if we can delete this line */
882     for (i=0, cp1=cp; i<cWIDE && *cp1==bgcol; i++, cp1++);
883     if (i==cWIDE) { cp += cWIDE;  ctop++; }
884     else break;
885   }
886 
887 
888   /* crop the bottom */
889   cp = cpic + (cHIGH-1) * cWIDE;
890   bgcol = cp[0];
891 
892   while (ctop + cbot + 1 < cHIGH) {
893     /* see if we can delete this line */
894     for (i=0, cp1=cp; i<cWIDE && *cp1==bgcol; i++,cp1++);
895     if (i==cWIDE) { cp -= cWIDE;  cbot++; }
896     else break;
897   }
898 
899 
900   /* crop the left side */
901   cp = cpic;
902   bgcol = cp[0];
903 
904   while (cleft + 1 < cWIDE) {
905     /* see if we can delete this line */
906     for (i=0, cp1=cp; i<cHIGH && *cp1==bgcol; i++, cp1 += cWIDE);
907     if (i==cHIGH) { cp++; cleft++; }
908     else break;
909   }
910 
911 
912   /* crop the right side */
913   cp = cpic + cWIDE-1;
914   bgcol = cp[0];
915 
916   while (cleft + cright + 1 < cWIDE) {
917     /* see if we can delete this line */
918     for (i=0, cp1=cp; i<cHIGH && *cp1==bgcol; i++, cp1 += cWIDE);
919     if (i==cHIGH) { cp--; cright++; }
920     else break;
921   }
922 
923   /* do the actual cropping */
924   if (cleft || ctop || cbot || cright) {
925     DoCrop(cXOFF+cleft, cYOFF+ctop,
926 	    cWIDE-(cleft+cright), cHIGH-(ctop+cbot));
927     return 1;
928   }
929 
930   return 0;
931 }
932 
933 
934 /***********************************/
doAutoCrop24()935 static int doAutoCrop24()
936 {
937   /* returns '1' if any cropping was actually done */
938 
939   byte *cp, *cp1;
940   int  i, ctop, cbot, cleft, cright;
941   byte bgR, bgG, bgB;
942   int maxmiss, misses, half;
943   int r, g, b, R, G, B, oldr, oldg, oldb;
944 # define EPSILON 39		/* up to 15% (39/256ths) variance okay */
945 # define NEIGHBOR 16		/* within 6% of neighboring pixels */
946 # define MISSPCT 6		/* and up to 6% that don't match */
947 # define inabsrange(a,n) ( (a) < n && (a) > -n )
948 
949 
950   if (cHIGH<3 || cWIDE<3) return 0;
951 
952   ctop = cbot = cleft = cright = 0;
953 
954   if (picType != PIC24) FatalError("doAutoCrop24 called when pic!=PIC24");
955 
956   /* crop the top */
957   cp = cpic;
958   half = cWIDE/2 * 3;
959   maxmiss = cWIDE * MISSPCT / 100;
960   bgR = cp[half+0];  bgG = cp[half+1];  bgB = cp[half+2];
961 
962   while (ctop+1 < cHIGH) {  /* see if we can delete this line */
963     oldr = bgR; oldg = bgG; oldb = bgB;
964 
965     for (i=0, misses=0, cp1=cp; i<cWIDE && misses<maxmiss; i++, cp1+=3) {
966       r=cp1[0]-bgR;  g=cp1[1]-bgG;  b=cp1[2]-bgB;
967       R=cp1[0]-oldr; G=cp1[1]-oldg; B=cp1[2]-oldb;
968       if (!inabsrange(r-g, EPSILON) ||
969 	  !inabsrange(r-b, EPSILON) ||
970 	  !inabsrange(b-g, EPSILON) ||
971 	  !inabsrange(R-G, NEIGHBOR) ||
972 	  !inabsrange(R-B, NEIGHBOR) ||
973 	  !inabsrange(B-G, NEIGHBOR)) misses++;
974       oldr=r; oldg=g; oldb=b;
975     }
976 
977     if (i==cWIDE) { cp += cWIDE*3;  ctop++; }   /* OK, we can crop this line */
978     else break;
979   }
980 
981 
982   /* crop the bottom */
983   cp = cpic + (cHIGH-1) * cWIDE*3;
984   bgR = cp[half+0];  bgG = cp[half+1];  bgB = cp[half+2];
985 
986   while (ctop + cbot + 1 < cHIGH) {  /* see if we can delete this line */
987     oldr = bgR; oldg = bgG; oldb = bgB;
988 
989     for (i=0, misses=0, cp1=cp; i<cWIDE && misses<maxmiss; i++, cp1+=3) {
990       r=cp1[0]-bgR;  g=cp1[1]-bgG;  b=cp1[2]-bgB;
991       R=cp1[0]-oldr; G=cp1[1]-oldg; B=cp1[2]-oldb;
992       if (!inabsrange(r-g, EPSILON) ||
993 	  !inabsrange(r-b, EPSILON) ||
994 	  !inabsrange(b-g, EPSILON) ||
995 	  !inabsrange(R-G, NEIGHBOR) ||
996 	  !inabsrange(R-B, NEIGHBOR) ||
997 	  !inabsrange(B-G, NEIGHBOR)) misses++;
998     }
999 
1000     if (i==cWIDE) { cp -= cWIDE*3;  cbot++; }
1001     else break;
1002   }
1003 
1004 
1005   /* crop the left side */
1006   cp = cpic;
1007   half = (cHIGH/2) * cWIDE * 3;
1008   maxmiss = cHIGH * MISSPCT / 100;
1009   bgR = cp[half+0];  bgG = cp[half+1];  bgB = cp[half+2];
1010 
1011   while (cleft + 1 < cWIDE) {  /* see if we can delete this line */
1012     oldr = bgR; oldg = bgG; oldb = bgB;
1013 
1014     for (i=0, misses=0, cp1=cp; i<cHIGH && misses<maxmiss;
1015 	 i++, cp1 += (cWIDE * 3)) {
1016       r=cp1[0]-bgR;  g=cp1[1]-bgG;  b=cp1[2]-bgB;
1017       R=cp1[0]-oldr; G=cp1[1]-oldg; B=cp1[2]-oldb;
1018       if (!inabsrange(r-g, EPSILON) ||
1019 	  !inabsrange(r-b, EPSILON) ||
1020 	  !inabsrange(b-g, EPSILON) ||
1021 	  !inabsrange(R-G, NEIGHBOR) ||
1022 	  !inabsrange(R-B, NEIGHBOR) ||
1023 	  !inabsrange(B-G, NEIGHBOR)) misses++;
1024     }
1025 
1026     if (i==cHIGH) { cp+=3; cleft++; }
1027     else break;
1028   }
1029 
1030 
1031   /* crop the right side */
1032   cp = cpic + (cWIDE-1) * 3;
1033   bgR = cp[half+0];  bgG = cp[half+1];  bgB = cp[half+2];
1034 
1035   while (cleft + cright + 1 < cWIDE) {  /* see if we can delete this line */
1036     oldr = bgR; oldg = bgG; oldb = bgB;
1037 
1038     for (i=0, misses=0, cp1=cp; i<cHIGH && misses<maxmiss;
1039 	 i++, cp1 += (cWIDE*3)) {
1040       r=cp1[0]-bgR;  g=cp1[1]-bgG;  b=cp1[2]-bgB;
1041       R=cp1[0]-oldr; G=cp1[1]-oldg; B=cp1[2]-oldb;
1042       if (!inabsrange(r-g, EPSILON) ||
1043 	  !inabsrange(r-b, EPSILON) ||
1044 	  !inabsrange(b-g, EPSILON) ||
1045 	  !inabsrange(R-G, NEIGHBOR) ||
1046 	  !inabsrange(R-B, NEIGHBOR) ||
1047 	  !inabsrange(B-G, NEIGHBOR)) misses++;
1048     }
1049 
1050     if (i==cHIGH) { cp-=3; cright++; }
1051     else break;
1052   }
1053 
1054 
1055   /* do the actual cropping */
1056   if (cleft || ctop || cbot || cright) {
1057     if (cWIDE - (cleft + cright) < 1 ||
1058 	cHIGH - (ctop  + cbot  ) < 1) return 0;    /* sanity check */
1059 
1060     DoCrop(cXOFF+cleft, cYOFF+ctop,
1061 	   cWIDE-(cleft+cright), cHIGH-(ctop+cbot));
1062     return 1;
1063   }
1064 
1065   return 0;
1066 }
1067 
1068 
1069 /*******************************/
DoCrop(x,y,w,h)1070 void DoCrop(x,y,w,h)
1071      int x,y,w,h;
1072 {
1073   /* given a cropping rectangle in PIC coordinates, it regens cpic
1074      and sticks likely values into eWIDE,eHIGH, assuming you wanted to
1075      crop.  epic is not regnerated (but is freed) */
1076 
1077   int     i, j, bperpix;
1078   byte   *cp, *pp;
1079   double  expw, exph;
1080 
1081 
1082   bperpix = (picType == PIC8) ? 1 : 3;
1083 
1084   /* get the cropping rectangle inside pic, if it isn't... */
1085   RANGE(x, 0, pWIDE-1);
1086   RANGE(y, 0, pHIGH-1);
1087   if (w<1) w=1;
1088   if (h<1) h=1;
1089   if (x+w > pWIDE) w = pWIDE-x;
1090   if (y+h > pHIGH) h = pHIGH-y;
1091 
1092 
1093   FreeEpic();
1094   if (cpic && cpic !=  pic) free(cpic);
1095   cpic = NULL;
1096 
1097   expw = (double) eWIDE / (double) cWIDE;
1098   exph = (double) eHIGH / (double) cHIGH;
1099 
1100   cXOFF = x;  cYOFF = y;  cWIDE = w;  cHIGH = h;
1101 
1102   if (DEBUG) fprintf(stderr,"DoCrop(): cropping to %dx%d rectangle at %d,%d\n",
1103 		     cWIDE, cHIGH, cXOFF, cYOFF);
1104 
1105   if (cWIDE == pWIDE && cHIGH == pHIGH) {   /* not really cropping */
1106     cpic = pic;
1107     cXOFF = cYOFF = 0;
1108   }
1109   else {
1110     /* at this point, we want to generate cpic, which will contain a
1111        cWIDE*cHIGH subsection of 'pic', top-left at cXOFF,cYOFF */
1112 
1113     cpic = (byte *) malloc((size_t) (cWIDE * cHIGH * bperpix));
1114 
1115     if (cpic == NULL) {
1116       fprintf(stderr,"%s: unable to allocate memory for cropped image\n", cmd);
1117       WUnCrop();
1118       cpic = pic;  cXOFF = cYOFF = 0;  cWIDE = pWIDE;  cHIGH = pHIGH;
1119       SetCropString();
1120       return;
1121     }
1122 
1123     /* copy relevant pixels from pic to cpic */
1124     cp = cpic;
1125     for (i=0; i<cHIGH; i++) {
1126       pp = pic + (i+cYOFF) * (pWIDE*bperpix) + (cXOFF * bperpix);
1127       for (j=0; j<cWIDE*bperpix; j++)
1128 	*cp++ = *pp++;
1129     }
1130   }
1131 
1132 
1133   SetCropString();
1134   BTSetActive(&but[BUNCROP], (cpic!=pic));
1135 
1136   eWIDE = (int) (cWIDE * expw);
1137   eHIGH = (int) (cHIGH * exph);
1138 
1139   if (eWIDE>maxWIDE || eHIGH>maxHIGH) {  /* make 'normal' size */
1140     if (cWIDE>maxWIDE || cHIGH>maxHIGH) {
1141       double r,wr,hr;
1142       wr = ((double) cWIDE) / maxWIDE;
1143       hr = ((double) cHIGH) / maxHIGH;
1144 
1145       r = (wr>hr) ? wr : hr;   /* r is the max(wr,hr) */
1146       eWIDE = (int) ((cWIDE / r) + 0.5);
1147       eHIGH = (int) ((cHIGH / r) + 0.5);
1148     }
1149     else { eWIDE = cWIDE;  eHIGH = cHIGH; }
1150   }
1151 
1152 
1153   if (eWIDE<1) eWIDE = 1;
1154   if (eHIGH<1) eHIGH = 1;
1155 
1156   SetCursors(-1);
1157 }
1158 
1159 
1160 
1161 /***********************************/
Rotate(dir)1162 void Rotate(dir)
1163      int dir;
1164 {
1165   /* called when rotate CW and rotate CCW controls are clicked */
1166   /* dir=0: clockwise, else counter-clockwise */
1167 
1168   if (HaveSelection()) EnableSelection(0);
1169 
1170   DoRotate(dir);
1171   CreateXImage();
1172   WRotate();
1173 }
1174 
1175 
1176 /***********************************/
DoRotate(dir)1177 void DoRotate(dir)
1178      int dir;
1179 {
1180   int i;
1181 
1182   /* dir=0: 90 degrees clockwise, else 90 degrees counter-clockwise */
1183   WaitCursor();
1184 
1185   RotatePic(pic, picType, &pWIDE, &pHIGH, dir);
1186 
1187   /* rotate clipped version and modify 'clip' coords */
1188   if (cpic != pic && cpic != NULL) {
1189     if (!dir) {
1190       i = pWIDE - (cYOFF + cHIGH);      /* have to rotate offsets */
1191       cYOFF = cXOFF;
1192       cXOFF = i;
1193     }
1194     else {
1195       i = pHIGH - (cXOFF + cWIDE);
1196       cXOFF = cYOFF;
1197       cYOFF = i;
1198     }
1199     WaitCursor();
1200     RotatePic(cpic, picType, &cWIDE, &cHIGH,dir);
1201   }
1202   else { cWIDE = pWIDE;  cHIGH = pHIGH; }
1203 
1204   /* rotate expanded version */
1205   if (epic != cpic && epic != NULL) {
1206     WaitCursor();
1207     RotatePic(epic, picType, &eWIDE, &eHIGH,dir);
1208   }
1209   else { eWIDE = cWIDE;  eHIGH = cHIGH; }
1210 
1211 
1212   SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH);
1213 
1214   SetISTR(ISTR_EXPAND, "%.5g%% x %.5g%%  (%d x %d)",
1215 	  100.0 * ((float) eWIDE) / cWIDE,
1216 	  100.0 * ((float) eHIGH) / cHIGH, eWIDE, eHIGH);
1217 }
1218 
1219 
1220 /************************/
RotatePic(pic,ptype,wp,hp,dir)1221 void RotatePic(pic, ptype, wp, hp, dir)
1222      byte *pic;
1223      int  *wp, *hp;
1224      int   ptype, dir;
1225 {
1226   /* rotates a w*h array of bytes 90 deg clockwise (dir=0)
1227      or counter-clockwise (dir != 0).  swaps w and h */
1228 
1229   byte        *pic1, *pix1, *pix;
1230   int          i,j,bperpix;
1231   unsigned int w,h;
1232 
1233   bperpix = (ptype == PIC8) ? 1 : 3;
1234 
1235   w = *wp;  h = *hp;
1236   pix1 = pic1 = (byte *) malloc((size_t) (w*h*bperpix));
1237   if (!pic1) FatalError("Not enough memory to rotate!");
1238 
1239   /* do the rotation */
1240   if (dir==0) {
1241     for (i=0; i<w; i++) {       /* CW */
1242       if (bperpix == 1) {
1243 	for (j=h-1, pix=pic+(h-1)*w + i;  j>=0;  j--, pix1++, pix-=w)
1244 	  *pix1 = *pix;
1245       }
1246       else {
1247 	int bperlin = w*bperpix;
1248 	int k;
1249 
1250 	for (j=h-1, pix=pic+(h-1)*w*bperpix + i*bperpix;
1251 	     j>=0;  j--, pix -= bperlin)
1252 	  for (k=0; k<bperpix; k++) *pix1++ = pix[k];
1253       }
1254     }
1255   }
1256   else {
1257     for (i=w-1; i>=0; i--) {    /* CCW */
1258       if (bperpix == 1) {
1259 	for (j=0, pix=pic+i; j<h; j++, pix1++, pix+=w)
1260 	  *pix1 = *pix;
1261       }
1262       else {
1263 	int k;
1264 	int bperlin = w*bperpix;
1265 
1266 	for (j=0, pix=pic+i*bperpix; j<h; j++, pix+=bperlin)
1267 	  for (k=0; k<bperpix; k++) *pix1++ = pix[k];
1268       }
1269     }
1270   }
1271 
1272 
1273   /* copy the rotated buffer into the original buffer */
1274   xvbcopy((char *) pic1, (char *) pic, (size_t) (w*h*bperpix));
1275 
1276   free(pic1);
1277 
1278   /* swap w and h */
1279   *wp = h;  *hp = w;
1280 }
1281 
1282 
1283 
1284 /***********************************/
Flip(dir)1285 void Flip(dir)
1286      int dir;
1287 {
1288   /* dir=0: flip horizontally, else vertically
1289    *
1290    * Note:  flips pic, cpic, and epic.  Doesn't touch Ximage, nor does it draw
1291    */
1292 
1293   WaitCursor();
1294 
1295   if (HaveSelection()) {            /* only flip selection region */
1296     flipSel(dir);
1297     return;
1298   }
1299 
1300   FlipPic(pic, pWIDE, pHIGH, dir);
1301 
1302   /* flip clipped version */
1303   if (cpic && cpic != pic) {
1304     WaitCursor();
1305     FlipPic(cpic, cWIDE, cHIGH, dir);
1306   }
1307 
1308   /* flip expanded version */
1309   if (epic && epic != cpic) {
1310     WaitCursor();
1311     FlipPic(epic, eWIDE, eHIGH, dir);
1312   }
1313 }
1314 
1315 
1316 /************************/
FlipPic(pic,w,h,dir)1317 void FlipPic(pic, w, h, dir)
1318      byte *pic;
1319      int w, h;
1320      int dir;
1321 {
1322   /* flips a w*h array of bytes horizontally (dir=0) or vertically (dir!=0) */
1323 
1324   byte *plin;
1325   int   i,j,k,l,bperpix,bperlin;
1326 
1327   bperpix = (picType == PIC8) ? 1 : 3;
1328   bperlin = w * bperpix;
1329 
1330   if (dir==0) {                /* horizontal flip */
1331     byte *leftp, *rightp;
1332 
1333     for (i=0; i<h; i++) {
1334       plin   = pic + i*bperlin;
1335       leftp  = plin;
1336       rightp = plin + (w-1)*bperpix;
1337 
1338       for (j=0; j<w/2; j++, rightp -= (2*bperpix)) {
1339 	for (l=0; l<bperpix; l++, leftp++, rightp++) {
1340 	  k = *leftp;  *leftp = *rightp;  *rightp = k;
1341 	}
1342       }
1343     }
1344   }
1345 
1346   else {                      /* vertical flip */
1347     byte *topp, *botp;
1348 
1349     for (i=0; i<w; i++) {
1350       topp = pic + i*bperpix;
1351       botp = pic + (h-1)*bperlin + i*bperpix;
1352 
1353       for (j=0; j<h/2; j++, topp+=(w-1)*bperpix, botp-=(w+1)*bperpix) {
1354 	for (l=0; l<bperpix; l++, topp++, botp++) {
1355 	  k = *topp;  *topp = *botp;  *botp = k;
1356 	}
1357       }
1358     }
1359   }
1360 }
1361 
1362 
1363 /************************/
flipSel(dir)1364 static void flipSel(dir)
1365      int dir;
1366 {
1367   /* flips selected area in 'pic', regens cpic and epic appropriately */
1368 
1369   int   x,y,w,h;
1370   byte *plin;
1371   int   i,j,k,l,bperpix;
1372 
1373   GetSelRCoords(&x,&y,&w,&h);
1374   CropRect2Rect(&x,&y,&w,&h, 0,0,pWIDE,pHIGH);
1375   if (w<1) w=1;
1376   if (h<1) h=1;
1377 
1378   bperpix = (picType == PIC8) ? 1 : 3;
1379 
1380   if (dir==0) {                /* horizontal flip */
1381     byte *leftp, *rightp;
1382 
1383     for (i=y; i<y+h; i++) {
1384       plin   = pic + (i*pWIDE + x) * bperpix;
1385       leftp  = plin;
1386       rightp = plin + (w-1)*bperpix;
1387 
1388       for (j=0; j<w/2; j++, rightp -= (2*bperpix)) {
1389 	for (l=0; l<bperpix; l++, leftp++, rightp++) {
1390 	  k = *leftp;  *leftp = *rightp;  *rightp = k;
1391 	}
1392       }
1393     }
1394   }
1395 
1396   else {                      /* vertical flip */
1397     byte *topp, *botp;
1398 
1399     for (i=x; i<x+w; i++) {
1400       topp = pic + ( y      * pWIDE + i) * bperpix;
1401       botp = pic + ((y+h-1) * pWIDE + i) * bperpix;
1402 
1403       for (j=0; j<h/2; j++, topp+=(pWIDE-1)*bperpix, botp-=(pWIDE+1)*bperpix) {
1404 	for (l=0; l<bperpix; l++, topp++, botp++) {
1405 	  k = *topp;  *topp = *botp;  *botp = k;
1406 	}
1407       }
1408     }
1409   }
1410 
1411   GenerateCpic();
1412   GenerateEpic(eWIDE,eHIGH);
1413 }
1414 
1415 
1416 /************************/
InstallNewPic()1417 void InstallNewPic()
1418 {
1419   /* given a new pic and colormap, (or new 24-bit pic) installs everything,
1420      regens cpic and epic, and redraws image */
1421 
1422   /* toss old cpic and epic, if any */
1423   FreeEpic();
1424   if (cpic && cpic != pic) free(cpic);
1425   cpic = NULL;
1426 
1427   /* toss old colors, and allocate new ones */
1428   NewPicGetColors(0,0);
1429 
1430   /* generate cpic,epic,theImage from new 'pic' */
1431   crop1(cXOFF, cYOFF, cWIDE, cHIGH, DO_ZOOM);
1432   HandleDispMode();
1433 }
1434 
1435 
1436 
1437 /***********************************/
DrawEpic()1438 void DrawEpic()
1439 {
1440   /* given an 'epic', builds a new Ximage, and draws it.  Basically
1441      called whenever epic is changed, or whenever color allocation
1442      changes (ie, the created X image will look different for the
1443      same epic) */
1444 
1445   CreateXImage();
1446 
1447   if (useroot) MakeRootPic();
1448   else DrawWindow(0,0,eWIDE,eHIGH);
1449 
1450   if (HaveSelection()) DrawSelection(0);
1451 }
1452 
1453 
1454 /************************************/
KillOldPics()1455 void KillOldPics()
1456 {
1457   /* throw away all previous images */
1458 
1459   FreeEpic();
1460   if (cpic && cpic != pic) free(cpic);
1461   if (pic) free(pic);
1462   xvDestroyImage(theImage);   theImage = NULL;
1463   pic = egampic = epic = cpic = NULL;
1464 
1465   if (picComments) free(picComments);
1466   picComments = (char *) NULL;
1467   ChangeCommentText();
1468 }
1469 
1470 
1471 
1472 /************************/
floydDitherize1(ximage,pic824,ptype,wide,high,rmap,gmap,bmap)1473 static void floydDitherize1(ximage,pic824,ptype, wide, high, rmap, gmap, bmap)
1474      XImage *ximage;
1475      byte   *pic824, *rmap, *gmap, *bmap;
1476      int     ptype, wide, high;
1477 {
1478   /* does floyd-steinberg ditherizing algorithm.
1479    *
1480    * takes a wide*high input image, of type 'ptype' (PIC8, PIC24)
1481    *     (if PIC8, colormap is specified by rmap,gmap,bmap)
1482    *
1483    * output is a 1-bit per pixel XYBitmap, packed 8 pixels per byte
1484    *
1485    * Note: this algorithm is *only* used when running on a 1-bit display
1486    */
1487 
1488   register byte   pix8, bit;
1489   int            *thisline, *nextline;
1490   int            *thisptr, *nextptr, *tmpptr;
1491   int             i, j, err, bperpix, bperln, order;
1492   byte           *pp, *image, w1, b1, w8, b8, rgb[256];
1493 
1494 
1495   if (ptype == PIC8) {   /* monoify colormap */
1496     for (i=0; i<256; i++)
1497       rgb[i] = MONO(rmap[i], gmap[i], bmap[i]);
1498   }
1499 
1500 
1501   image   = (byte *) ximage->data;
1502   bperln  = ximage->bytes_per_line;
1503   order   = ximage->bitmap_bit_order;
1504   bperpix = (ptype == PIC8) ? 1 : 3;
1505 
1506 
1507   thisline = (int *) malloc(wide * sizeof(int));
1508   nextline = (int *) malloc(wide * sizeof(int));
1509   if (!thisline || !nextline)
1510     FatalError("ran out of memory in floydDitherize1()\n");
1511 
1512 
1513   /* load up first line of picture */
1514   pp = pic824;
1515   if (ptype == PIC24) {
1516     for (j=0, tmpptr = nextline; j<wide; j++, pp+=3)
1517       *tmpptr++ = fsgamcr[MONO(pp[0], pp[1], pp[2])];
1518   }
1519   else {
1520     for (j=0, tmpptr = nextline; j<wide; j++, pp++)
1521       *tmpptr++ = fsgamcr[rgb[*pp]];
1522   }
1523 
1524 
1525   w1 = white&0x1;  b1=black&0x1;
1526   w8 = w1<<7;  b8 = b1<<7;        /* b/w bit in high bit */
1527 
1528 
1529   for (i=0; i<high; i++) {
1530     if ((i&0x3f) == 0) WaitCursor();
1531 
1532     /* get next line of image */
1533     tmpptr = thisline;  thisline = nextline;  nextline = tmpptr;  /* swap */
1534     if (i!=high-1) {
1535       pp = pic824 + (i+1) * wide * bperpix;
1536       if (ptype == PIC24) {
1537 	for (j=0, tmpptr = nextline; j<wide; j++, pp+=3)
1538 	  *tmpptr++ = fsgamcr[MONO(pp[0], pp[1], pp[2])];
1539       }
1540       else {
1541 	for (j=0, tmpptr = nextline; j<wide; j++, pp++)
1542 	  *tmpptr++ = fsgamcr[rgb[*pp]];
1543       }
1544     }
1545 
1546     thisptr = thisline;  nextptr = nextline;
1547 
1548     pp  = image + i*bperln;
1549 
1550 
1551     if (order==LSBFirst) {
1552       bit = pix8 = 0;
1553       for (j=0; j<wide; j++, thisptr++, nextptr++) {
1554 	if (*thisptr<128) { err = *thisptr;     pix8 |= b8; }
1555 	             else { err = *thisptr-255; pix8 |= w8; }
1556 
1557 	if (bit==7) { *pp++ = pix8;  bit=pix8=0; }
1558 	       else { pix8 >>= 1;  bit++; }
1559 
1560 	if (j<wide-1) thisptr[1] += ((err*7)/16);
1561 
1562 	if (i<high-1) {
1563 	  nextptr[0] += ((err*5)/16);
1564 	  if (j>0)      nextptr[-1] += ((err*3)/16);
1565 	  if (j<wide-1) nextptr[ 1] += (err/16);
1566 	}
1567       }
1568       if (bit) *pp++ = pix8>>(7-bit);  /* write partial byte at end of line */
1569     }
1570 
1571     else {   /* order==MSBFirst */
1572       bit = pix8 = 0;
1573       for (j=0; j<wide; j++, thisptr++, nextptr++) {
1574 	if (*thisptr<128) { err = *thisptr;     pix8 |= b1; }
1575 	             else { err = *thisptr-255; pix8 |= w1; }
1576 
1577 	if (bit==7) { *pp++ = pix8;  bit=pix8=0; }
1578  	       else { pix8 <<= 1; bit++; }
1579 
1580 	if (j<wide-1) thisptr[1] += ((err*7)/16);
1581 
1582 	if (i<high-1) {
1583 	  nextptr[0] += ((err*5)/16);
1584 	  if (j>0)       nextptr[-1] += ((err*3)/16);
1585 	  if (j<wide-1)  nextptr[ 1] += (err/16);
1586 	}
1587       }
1588       if (bit) *pp++ = pix8<<(7-bit);  /* write partial byte at end of line */
1589     }
1590   }
1591 
1592 
1593   free(thisline);  free(nextline);
1594 }
1595 
1596 
1597 
1598 
1599 
1600 /************************/
FSDither(inpic,intype,w,h,rmap,gmap,bmap,bval,wval)1601 byte *FSDither(inpic, intype, w, h, rmap, gmap, bmap,
1602 	      bval, wval)
1603      byte *inpic, *rmap, *gmap, *bmap;
1604      int   w,h, intype, bval, wval;
1605 {
1606   /* takes an input pic of size w*h, and type 'intype' (PIC8 or PIC24),
1607    *                (if PIC8, colormap specified by rmap,gmap,bmap)
1608    * and does the floyd-steinberg dithering algorithm on it.
1609    * generates (mallocs) a w*h 1-byte-per-pixel 'outpic', using 'bval'
1610    * and 'wval' as the 'black' and 'white' pixel values, respectively
1611    */
1612 
1613   int    i, j, err, w1, h1, npixels, linebufsize;
1614   byte  *pp, *outpic, rgb[256];
1615   int   *thisline, *nextline, *thisptr, *nextptr, *tmpptr;
1616 
1617 
1618   npixels = w * h;
1619   linebufsize = w * sizeof(int);
1620   if (w <= 0 || h <= 0 || npixels/w != h || linebufsize/w != sizeof(int)) {
1621     SetISTR(ISTR_WARNING, "Invalid image dimensions for dithering");
1622     return (byte *)NULL;
1623   }
1624 
1625   outpic = (byte *) malloc((size_t) npixels);
1626   if (!outpic) return outpic;
1627 
1628 
1629   if (intype == PIC8) {       /* monoify colormap */
1630     for (i=0; i<256; i++)
1631       rgb[i] = MONO(rmap[i], gmap[i], bmap[i]);
1632   }
1633 
1634 
1635   thisline = (int *) malloc(linebufsize);
1636   nextline = (int *) malloc(linebufsize);
1637   if (!thisline || !nextline)
1638     FatalError("ran out of memory in FSDither()\n");
1639 
1640 
1641   w1 = w-1;  h1 = h-1;
1642 
1643   /* load up first line of picture */
1644   pp = inpic;
1645   if (intype == PIC24) {
1646     for (j=0, tmpptr=nextline; j<w; j++, pp+=3)
1647       *tmpptr++ = fsgamcr[MONO(pp[0], pp[1], pp[2])];
1648   }
1649   else {
1650     for (j=0, tmpptr=nextline; j<w; j++, pp++)
1651       *tmpptr++ = fsgamcr[rgb[*pp]];
1652   }
1653 
1654 
1655   for (i=0; i<h; i++) {
1656     if ((i&0x3f) == 0) WaitCursor();
1657 
1658     /* get next line of picture */
1659     tmpptr = thisline;  thisline = nextline;  nextline = tmpptr;  /* swap */
1660     if (i!=h1) {
1661       if (intype == PIC24) {
1662 	pp = inpic + (i+1) * w * 3;
1663 	for (j=0, tmpptr=nextline; j<w; j++, pp+=3)
1664 	  *tmpptr++ = fsgamcr[MONO(pp[0], pp[1], pp[2])];
1665       }
1666       else {
1667 	pp = inpic + (i+1) * w;
1668 	for (j=0, tmpptr = nextline; j<w; j++, pp++)
1669 	  *tmpptr++ = fsgamcr[rgb[*pp]];
1670       }
1671     }
1672 
1673     pp  = outpic + i * w;
1674     thisptr = thisline;  nextptr = nextline;
1675 
1676     if ((i&1) == 0) {  /* go right */
1677       for (j=0; j<w; j++, pp++, thisptr++, nextptr++) {
1678 	if (*thisptr<128) { err = *thisptr;     *pp = (byte) bval; }
1679 	             else { err = *thisptr-255; *pp = (byte) wval; }
1680 
1681 	if (j<w1) thisptr[1] += ((err*7)/16);
1682 
1683 	if (i<h1) {
1684 	  nextptr[0] += ((err*5)/16);
1685 	  if (j>0)  nextptr[-1] += ((err*3)/16);
1686 	  if (j<w1) nextptr[ 1] += (err/16);
1687 	}
1688       }
1689     }
1690 
1691     else {   /* go left */
1692       pp += (w-1);  thisptr += (w-1);  nextptr += (w-1);
1693       for (j=w-1; j>=0; j--, pp--, thisptr--, nextptr--) {
1694 	if (*thisptr<128) { err = *thisptr;     *pp = (byte) bval; }
1695 	             else { err = *thisptr-255; *pp = (byte) wval; }
1696 
1697 	if (j>0) thisptr[-1] += ((err*7)/16);
1698 
1699 	if (i<h1) {
1700 	  nextptr[0] += ((err*5)/16);
1701 	  if (j>0)  nextptr[-1] += (err/16);
1702 	  if (j<w1) nextptr[ 1] += ((err*3)/16);
1703 	}
1704       }
1705     }
1706   }
1707 
1708   free(thisline);  free(nextline);
1709   return outpic;
1710 }
1711 
1712 
1713 
1714 
1715 
1716 
1717 /***********************************/
CreateXImage()1718 void CreateXImage()
1719 {
1720   xvDestroyImage(theImage);   theImage = NULL;
1721 
1722   if (!epic) GenerateEpic(eWIDE, eHIGH);  /* shouldn't happen... */
1723 
1724   if (picType == PIC24) {  /* generate egampic */
1725     if (egampic && egampic != epic) free(egampic);
1726     egampic = GammifyPic24(epic, eWIDE, eHIGH);
1727     if (!egampic) egampic = epic;
1728   }
1729 
1730 
1731   if (picType == PIC8)
1732     theImage = Pic8ToXImage(epic,     (u_int) eWIDE, (u_int) eHIGH,
1733 			    cols, rMap, gMap, bMap);
1734   else if (picType == PIC24)
1735     theImage = Pic24ToXImage(egampic, (u_int) eWIDE, (u_int) eHIGH);
1736 }
1737 
1738 
1739 
1740 
1741 /***********************************/
Pic8ToXImage(pic8,wide,high,xcolors,rmap,gmap,bmap)1742 XImage *Pic8ToXImage(pic8, wide, high, xcolors, rmap, gmap, bmap)
1743      byte          *pic8, *rmap, *gmap, *bmap;
1744      unsigned int   wide, high;
1745      unsigned long *xcolors;
1746 {
1747   /*
1748    * this has to do the tricky bit of converting the data in 'pic8'
1749    * into something usable for X.
1750    *
1751    */
1752 
1753 
1754   int     i;
1755   unsigned long xcol;
1756   XImage *xim;
1757   byte   *dithpic;
1758 
1759   xim = (XImage *) NULL;
1760   dithpic = (byte *) NULL;
1761 
1762   if (!pic8) return xim;  /* shouldn't happen */
1763 
1764   if (DEBUG > 1)
1765     fprintf(stderr,"Pic8ToXImage(): creating a %dx%d Ximage, %d bits deep\n",
1766 	    wide, high, dispDEEP);
1767 
1768 
1769   /* special case: 1-bit display */
1770   if (dispDEEP == 1) {
1771     byte  *imagedata;
1772 
1773     xim = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL,
1774 		       wide, high, 32, 0);
1775     if (!xim) FatalError("couldn't create xim!");
1776 
1777     imagedata = (byte *) malloc((size_t) (xim->bytes_per_line * high));
1778     if (!imagedata) FatalError("couldn't malloc imagedata");
1779 
1780     xim->data = (char *) imagedata;
1781     floydDitherize1(xim, pic8, PIC8, (int) wide, (int) high, rmap, gmap, bmap);
1782     return xim;
1783   }
1784 
1785 
1786   /* if ncols==0, do a 'black' and 'white' dither */
1787   if (ncols == 0) {
1788     /* note that if dispDEEP > 8, dithpic will just have '0' and '1' instead
1789        of 'black' and 'white' */
1790 
1791     dithpic = FSDither(pic8, PIC8, (int) wide, (int) high, rmap, gmap, bmap,
1792 		       (int) ((dispDEEP <= 8) ? black : 0),
1793 		       (int) ((dispDEEP <= 8) ? white : 1));
1794   }
1795 
1796 
1797 
1798   switch (dispDEEP) {
1799 
1800   case 8: {
1801     byte  *imagedata, *ip, *pp;
1802     int   j, imWIDE, nullCount;
1803 
1804     nullCount = (4 - (wide % 4)) & 0x03;  /* # of padding bytes per line */
1805     imWIDE = wide + nullCount;
1806 
1807     /* Now create the image data - pad each scanline as necessary */
1808     imagedata = (byte *) malloc((size_t) (imWIDE * high));
1809     if (!imagedata) FatalError("couldn't malloc imagedata");
1810 
1811     pp = (dithpic) ? dithpic : pic8;
1812 
1813     for (i=0, ip=imagedata; i<high; i++) {
1814       if (((i+1)&0x7f) == 0) WaitCursor();
1815 
1816       if (dithpic) {
1817 	for (j=0; j<wide; j++, ip++, pp++) *ip = *pp;  /* pp already is Xval */
1818       }
1819       else {
1820 	for (j=0; j<wide; j++, ip++, pp++) *ip = (byte) xcolors[*pp];
1821       }
1822 
1823       for (j=0; j<nullCount; j++, ip++) *ip = 0;
1824     }
1825 
1826     xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
1827 		       (char *) imagedata,  wide,  high,
1828 		       32, imWIDE);
1829     if (!xim) FatalError("couldn't create xim!");
1830   }
1831     break;
1832 
1833 
1834 
1835     /*********************************/
1836 
1837   case 4: {
1838     byte  *imagedata, *ip, *pp;
1839     byte *lip;
1840     int  bperline, half, j;
1841 
1842     xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
1843 		        wide,  high, 8, 0);
1844     if (!xim) FatalError("couldn't create xim!");
1845 
1846     bperline = xim->bytes_per_line;
1847     imagedata = (byte *) malloc((size_t) (bperline * high));
1848     if (!imagedata) FatalError("couldn't malloc imagedata");
1849     xim->data = (char *) imagedata;
1850 
1851 
1852     pp = (dithpic) ? dithpic : pic8;
1853 
1854     if (xim->bits_per_pixel == 4) {
1855       for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
1856 	if (((i+1)&0x7f) == 0) WaitCursor();
1857 
1858 	for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) {
1859 	  xcol = ((dithpic) ? *pp : xcolors[*pp]) & 0x0f;
1860 
1861 	  if (ImageByteOrder(theDisp) == LSBFirst) {
1862 	    if (half&1) { *ip = *ip + (xcol<<4);  ip++; }
1863 	    else *ip = xcol;
1864 	  }
1865 	  else {
1866 	    if (half&1) { *ip = *ip + xcol;  ip++; }
1867 	    else *ip = xcol << 4;
1868 	  }
1869 	}
1870       }
1871     }
1872 
1873     else if (xim->bits_per_pixel == 8) {
1874       for (i=wide*high, ip=imagedata; i>0; i--,pp++,ip++) {
1875 	if (((i+1)&0x1ffff) == 0) WaitCursor();
1876 	*ip = (dithpic) ? *pp : (byte) xcolors[*pp];
1877       }
1878     }
1879 
1880     else FatalError("This display's too bizarre.  Can't create XImage.");
1881   }
1882     break;
1883 
1884 
1885     /*********************************/
1886 
1887   case 2: {  /* by M.Kossa@frec.bull.fr (Marc Kossa) */
1888              /* MSBFirst mods added by dale@ntg.com (Dale Luck) */
1889              /* additional fixes by  evol@infko.uni-koblenz.de
1890 		(Randolf Werner) for NeXT 2bit grayscale with MouseX */
1891 
1892     byte  *imagedata, *ip, *pp;
1893     byte *lip;
1894     int  bperline, half, j;
1895 
1896     xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
1897 		        wide,  high, 8, 0);
1898     if (!xim) FatalError("couldn't create xim!");
1899 
1900     bperline = xim->bytes_per_line;
1901     imagedata = (byte *) malloc((size_t) (bperline * high));
1902     if (!imagedata) FatalError("couldn't malloc imagedata");
1903     xim->data = (char *) imagedata;
1904 
1905     pp = (dithpic) ? dithpic : pic8;
1906 
1907     if (xim->bits_per_pixel == 2) {
1908       for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
1909 	if (((i+1)&0x7f) == 0) WaitCursor();
1910 	for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) {
1911 	  xcol = ((dithpic) ? *pp : xcolors[*pp]) & 0x03;
1912 
1913 	  if (xim->bitmap_bit_order == LSBFirst) {
1914 	    if      (half%4==0) *ip  = xcol;
1915 	    else if (half%4==1) *ip |= (xcol<<2);
1916 	    else if (half%4==2) *ip |= (xcol<<4);
1917 	    else              { *ip |= (xcol<<6); ip++; }
1918 	  }
1919 
1920 	  else {  /* MSBFirst.  NeXT, among others */
1921 	    if      (half%4==0) *ip  = (xcol<<6);
1922 	    else if (half%4==1) *ip |= (xcol<<4);
1923 	    else if (half%4==2) *ip |= (xcol<<2);
1924 	    else              { *ip |=  xcol;     ip++; }
1925 	  }
1926 	}
1927       }
1928     }
1929 
1930     else if (xim->bits_per_pixel == 4) {
1931       for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
1932 	if (((i+1)&0x7f) == 0) WaitCursor();
1933 
1934 	for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) {
1935 	  xcol = ((dithpic) ? *pp : xcolors[*pp]) & 0x0f;
1936 
1937 	  if (xim->bitmap_bit_order == LSBFirst) {
1938 	    if (half&1) { *ip |= (xcol<<4);  ip++; }
1939 	    else *ip = xcol;
1940 	  }
1941 
1942 	  else { /* MSBFirst */
1943 	    if (half&1) { *ip |= xcol;  ip++; }
1944 	    else *ip = xcol << 4;
1945 	  }
1946 	}
1947       }
1948     }
1949 
1950     else if (xim->bits_per_pixel == 8) {
1951       for (i=wide*high, ip=imagedata; i>0; i--,pp++,ip++) {
1952 	if (((i+1)&0x1ffff) == 0) WaitCursor();
1953 	*ip = (dithpic) ? *pp : (byte) xcolors[*pp];
1954       }
1955     }
1956 
1957     else FatalError("This display's too bizarre.  Can't create XImage.");
1958   }
1959     break;
1960 
1961 
1962   /*********************************/
1963 
1964   case 5:
1965   case 6: {
1966     byte  *imagedata, *ip, *pp;
1967     int  bperline;
1968 
1969     xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
1970 		        wide,  high, 8, 0);
1971     if (!xim) FatalError("couldn't create xim!");
1972 
1973     if (xim->bits_per_pixel != 8)
1974       FatalError("This display's too bizarre.  Can't create XImage.");
1975 
1976     bperline = xim->bytes_per_line;
1977     imagedata = (byte *) malloc((size_t) (bperline * high));
1978     if (!imagedata) FatalError("couldn't malloc imagedata");
1979     xim->data = (char *) imagedata;
1980 
1981     pp = (dithpic) ? dithpic : pic8;
1982 
1983     for (i=wide*high, ip=imagedata; i>0; i--,pp++,ip++) {
1984       if (((i+1)&0x1ffff) == 0) WaitCursor();
1985       *ip = (dithpic) ? *pp : (byte) xcolors[*pp];
1986     }
1987   }
1988     break;
1989 
1990 
1991   /*********************************/
1992 
1993   case 12:
1994   case 15:
1995   case 16: {
1996     byte  *imagedata, *ip, *pp;
1997 
1998     imagedata = (byte *) malloc((size_t) (2*wide*high));
1999     if (!imagedata) FatalError("couldn't malloc imagedata");
2000 
2001     xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
2002 		       (char *) imagedata,  wide,  high, 16, 0);
2003     if (!xim) FatalError("couldn't create xim!");
2004 
2005     if (dispDEEP == 12 && xim->bits_per_pixel != 16) {
2006       char buf[128];
2007       sprintf(buf,"No code for this type of display (depth=%d, bperpix=%d)",
2008 	      dispDEEP, xim->bits_per_pixel);
2009       FatalError(buf);
2010     }
2011 
2012     pp = (dithpic) ? dithpic : pic8;
2013 
2014     if (xim->byte_order == MSBFirst) {
2015       for (i=wide*high, ip=imagedata; i>0; i--,pp++) {
2016 	if (((i+1)&0x1ffff) == 0) WaitCursor();
2017 
2018 	if (dithpic) xcol = ((*pp) ? white : black) & 0xffff;
2019 		else xcol = xcolors[*pp] & 0xffff;
2020 
2021 	*ip++ = (xcol>>8) & 0xff;
2022 	*ip++ = (xcol) & 0xff;
2023       }
2024     }
2025     else {   /* LSBFirst */
2026       for (i=wide*high, ip=imagedata; i>0; i--,pp++) {
2027 	if (((i+1)&0x1ffff) == 0) WaitCursor();
2028 
2029 	if (dithpic) xcol = ((*pp) ? white : black) & 0xffff;
2030 	        else xcol = xcolors[*pp];
2031 
2032 	*ip++ = (xcol) & 0xff;
2033 	*ip++ = (xcol>>8) & 0xff;
2034       }
2035     }
2036   }
2037     break;
2038 
2039 
2040     /*********************************/
2041 
2042   case 24:
2043   case 32: {
2044     byte  *imagedata, *ip, *pp, *tip;
2045     int    j, do32;
2046 
2047     imagedata = (byte *) malloc((size_t) (4*wide*high));
2048     if (!imagedata) FatalError("couldn't malloc imagedata");
2049 
2050     xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
2051 		       (char *) imagedata,  wide,  high, 32, 0);
2052     if (!xim) FatalError("couldn't create xim!");
2053 
2054     do32 = (xim->bits_per_pixel == 32);
2055 
2056     pp = (dithpic) ? dithpic : pic8;
2057 
2058     if (xim->byte_order == MSBFirst) {
2059       for (i=0, ip=imagedata; i<high; i++) {
2060 	if (((i+1)&0x7f) == 0) WaitCursor();
2061 	for (j=0, tip=ip; j<wide; j++, pp++) {
2062 	  xcol = (dithpic) ? ((*pp) ? white : black) : xcolors[*pp];
2063 
2064 	  if (do32) *tip++ = 0;
2065 	  *tip++ = (xcol>>16) & 0xff;
2066 	  *tip++ = (xcol>>8) & 0xff;
2067 	  *tip++ =  xcol & 0xff;
2068 	}
2069 	ip += xim->bytes_per_line;
2070       }
2071     }
2072 
2073     else {  /* LSBFirst */
2074       for (i=0, ip=imagedata; i<high; i++) {
2075 	if (((i+1)&0x7f) == 0) WaitCursor();
2076 	for (j=0, tip=ip; j<wide; j++, pp++) {
2077 	  xcol = (dithpic) ? ((*pp) ? white : black) : xcolors[*pp];
2078 
2079 	  *tip++ =  xcol & 0xff;
2080 	  *tip++ = (xcol>>8) & 0xff;
2081 	  *tip++ = (xcol>>16) & 0xff;
2082 	  if (do32) *tip++ = 0;
2083 	}
2084 	ip += xim->bytes_per_line;
2085       }
2086     }
2087   }
2088     break;
2089 
2090 
2091     /*********************************/
2092 
2093   default:
2094     sprintf(dummystr,"no code to handle this display type (%d bits deep)",
2095 	    dispDEEP);
2096     FatalError(dummystr);
2097     break;
2098   }
2099 
2100 
2101   if (dithpic) free(dithpic);
2102 
2103   return(xim);
2104 }
2105 
2106 
2107 
2108 /***********************************/
Pic24ToXImage(pic24,wide,high)2109 XImage *Pic24ToXImage(pic24, wide, high)
2110      byte          *pic24;
2111      unsigned int   wide, high;
2112 {
2113   /*
2114    * This has to do the none-too-simple bit of converting the data in 'pic24'
2115    * into something usable by X.
2116    *
2117    * There are two major approaches:  if we're displaying on a TrueColor
2118    * or DirectColor display, we've got all the colors we're going to need,
2119    * and 'all we have to do' is convert 24-bit RGB pixels into whatever
2120    * variation of RGB the X device in question wants.  No color allocation
2121    * is involved.
2122    *
2123    * Alternately, if we're on a PseudoColor, GrayScale, StaticColor or
2124    * StaticGray display, we're going to continue to operate in an 8-bit
2125    * mode.  (In that by this point, a 3/3/2 standard colormap has been
2126    * created for our use (though all 256 colors may not be unique...), and
2127    * we're just going to display the 24-bit picture by dithering with those
2128    * colors.)
2129    *
2130    */
2131 
2132   int     i,j;
2133   XImage *xim;
2134 
2135   xim     = (XImage *) NULL;
2136 
2137   if (!pic24) return xim;  /* shouldn't happen */
2138 
2139 
2140   /* special case: 1-bit display.  Doesn't much matter *what* the visual is */
2141   if (dispDEEP == 1) {
2142     byte  *imagedata;
2143 
2144     xim = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL,
2145 		        wide,  high, 32, 0);
2146     if (!xim) FatalError("couldn't create xim!");
2147 
2148     imagedata = (byte *) malloc((size_t) (xim->bytes_per_line * high));
2149     if (!imagedata) FatalError("couldn't malloc imagedata");
2150 
2151     xim->data = (char *) imagedata;
2152     floydDitherize1(xim, pic24,PIC24, (int) wide, (int) high, NULL,NULL,NULL);
2153 
2154     return xim;
2155   }
2156 
2157 
2158 
2159 
2160   if (theVisual->class == TrueColor || theVisual->class == DirectColor) {
2161 
2162     /************************************************************************/
2163     /* Non-ColorMapped Visuals:  TrueColor, DirectColor                     */
2164     /************************************************************************/
2165 
2166     unsigned long xcol;
2167     int           bperpix, bperline;
2168     byte         *imagedata, *lip, *ip, *pp;
2169 
2170 
2171     xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
2172 		        wide,  high, 32, 0);
2173     if (!xim) FatalError("couldn't create X image!");
2174 
2175     bperline = xim->bytes_per_line;
2176     bperpix  = xim->bits_per_pixel;
2177 
2178     imagedata = (byte *) malloc((size_t) (high * bperline));
2179     if (!imagedata) FatalError("couldn't malloc imagedata");
2180 
2181     xim->data = (char *) imagedata;
2182 
2183     if (bperpix != 8 && bperpix != 16 && bperpix != 24 && bperpix != 32) {
2184       char buf[128];
2185       sprintf(buf,"Sorry, no code written to handle %d-bit %s",
2186 	      bperpix, "TrueColor/DirectColor displays!");
2187       FatalError(buf);
2188     }
2189 
2190     screen_init();
2191 
2192 #ifdef ENABLE_FIXPIX_SMOOTH
2193     if (do_fixpix_smooth) {
2194 #if 0
2195       /* If we wouldn't have to save the original pic24 image data,
2196        * the following code would do the dither job by overwriting
2197        * the image data, and the normal render code would then work
2198        * without any change on that data.
2199        * Unfortunately, this approach would hurt the xv assumptions...
2200        */
2201       if (bperpix < 24) {
2202         FSBUF *fs = fs2_init(wide);
2203         if (fs) {
2204 	  fs2_dither(fs, pic24, 3, high, wide);
2205 	  free(fs);
2206         }
2207       }
2208 #else
2209       /* ...so we have to take a different approach with linewise
2210        * dithering/rendering in a loop using a temporary line buffer.
2211        */
2212       if (bperpix < 24) {
2213         FSBUF *fs = fs2_init(wide);
2214         if (fs) {
2215 	  byte *row_buf = malloc((size_t)wide * 3);
2216 	  if (row_buf) {
2217 	    int nc = 3;
2218 	    byte *picp = pic24;  lip = imagedata;
2219 
2220 	    switch (bperpix) {
2221 	      case 8:
2222 	        for (i=0; i<high; i++, lip+=bperline, picp+=(size_t)wide*3) {
2223 	          memcpy(row_buf, picp, (size_t)wide * 3);
2224 	          nc = fs2_dither(fs, row_buf, nc, 1, wide);
2225 	          for (j=0, ip=lip, pp=row_buf; j<wide; j++) {
2226 	            xcol  = screen_rgb[0][*pp++];
2227 	            xcol |= screen_rgb[1][*pp++];
2228 	            xcol |= screen_rgb[2][*pp++];
2229 		    *ip++ = xcol & 0xff;
2230 	          }
2231 	        }
2232 		break;
2233 
2234 	      case 16:
2235 	        for (i=0; i<high; i++, lip+=bperline, picp+=(size_t)wide*3) {
2236 	          CARD16 *ip16 = (CARD16 *)lip;
2237 	          memcpy(row_buf, picp, (size_t)wide * 3);
2238 	          nc = fs2_dither(fs, row_buf, nc, 1, wide);
2239 	          for (j=0, pp=row_buf; j<wide; j++) {
2240 	            xcol  = screen_rgb[0][*pp++];
2241 	            xcol |= screen_rgb[1][*pp++];
2242 	            xcol |= screen_rgb[2][*pp++];
2243 		    *ip16++ = (CARD16)xcol;
2244 	          }
2245 	        }
2246 		break;
2247 	    } /* end switch */
2248 
2249 	    free(row_buf);
2250 	    free(fs);
2251 
2252 	    return xim;
2253 	  }
2254 	  free(fs);
2255         }
2256       }
2257 #endif /* 0? */
2258     }
2259 #endif /* ENABLE_FIXPIX_SMOOTH */
2260 
2261     lip = imagedata;  pp = pic24;
2262 
2263     switch (bperpix) {
2264       case 8:
2265         for (i=0; i<high; i++, lip+=bperline) {
2266           for (j=0, ip=lip; j<wide; j++) {
2267 	    xcol  = screen_rgb[0][*pp++];
2268 	    xcol |= screen_rgb[1][*pp++];
2269 	    xcol |= screen_rgb[2][*pp++];
2270 	    *ip++ = xcol & 0xff;
2271           }
2272         }
2273         break;
2274 
2275       case 16:
2276         for (i=0; i<high; i++, lip+=bperline) {
2277           CARD16 *ip16 = (CARD16 *)lip;
2278           for (j=0; j<wide; j++) {
2279 	    xcol  = screen_rgb[0][*pp++];
2280 	    xcol |= screen_rgb[1][*pp++];
2281 	    xcol |= screen_rgb[2][*pp++];
2282 	    *ip16++ = (CARD16)xcol;
2283           }
2284         }
2285         break;
2286 
2287       case 24:
2288         for (i=0; i<high; i++, lip+=bperline) {
2289           for (j=0, ip=lip; j<wide; j++) {
2290 	    xcol  = screen_rgb[0][*pp++];
2291 	    xcol |= screen_rgb[1][*pp++];
2292 	    xcol |= screen_rgb[2][*pp++];
2293 #ifdef USE_24BIT_ENDIAN_FIX
2294 	    if (border == MSBFirst) {
2295 	      *ip++ = (xcol>>16) & 0xff;
2296 	      *ip++ = (xcol>>8)  & 0xff;
2297 	      *ip++ =  xcol      & 0xff;
2298 	    }
2299 	    else {  /* LSBFirst */
2300 	      *ip++ =  xcol      & 0xff;
2301 	      *ip++ = (xcol>>8)  & 0xff;
2302 	      *ip++ = (xcol>>16) & 0xff;
2303 	    }
2304 #else /* GRR:  this came with the FixPix patch, but I don't think it's right */
2305 	    *ip++ = (xcol >> 16) & 0xff;    /* (no way to test, however, so  */
2306 	    *ip++ = (xcol >> 8)  & 0xff;    /* it's left enabled by default) */
2307 	    *ip++ =  xcol        & 0xff;
2308 #endif
2309           }
2310         }
2311         break;
2312 
2313       case 32:
2314         for (i=0; i<high; i++, lip+=bperline) {
2315           CARD32 *ip32 = (CARD32 *)lip;
2316           for (j=0; j<wide; j++) {
2317 	    xcol  = screen_rgb[0][*pp++];
2318 	    xcol |= screen_rgb[1][*pp++];
2319 	    xcol |= screen_rgb[2][*pp++];
2320 	    *ip32++ = (CARD32)xcol;
2321           }
2322         }
2323         break;
2324     } /* end switch */
2325   }
2326 
2327   else {
2328 
2329     /************************************************************************/
2330     /* CMapped Visuals:  PseudoColor, GrayScale, StaticGray, StaticColor... */
2331     /************************************************************************/
2332 
2333     byte *pic8;
2334     int   bwdith;
2335 
2336     /* in all cases, make an 8-bit version of the image, either using
2337        'black' and 'white', or the stdcmap */
2338 
2339     bwdith = 0;
2340 
2341     if (ncols == 0 && dispDEEP != 1) {   /* do 'black' and 'white' dither */
2342       /* note that if dispDEEP > 8, pic8 will just have '0' and '1' instead
2343 	 of 'black' and 'white' */
2344 
2345       pic8 = FSDither(pic24, PIC24, (int) wide, (int) high, NULL, NULL, NULL,
2346 		      (int) ((dispDEEP <= 8) ? black : 0),
2347 		      (int) ((dispDEEP <= 8) ? white : 1));
2348       bwdith = 1;
2349     }
2350 
2351     else {                               /* do color dither using stdcmap */
2352       pic8 = Do332ColorDither(pic24, NULL, (int) wide, (int) high,
2353 			      NULL, NULL, NULL,
2354 			      stdrdisp, stdgdisp, stdbdisp, 256);
2355     }
2356 
2357     if (!pic8) FatalError("out of memory in Pic24ToXImage()\n");
2358 
2359 
2360     /* DISPLAY-DEPENDENT code follows... */
2361 
2362 
2363     switch (dispDEEP) {
2364 
2365 
2366     case 8: {
2367       byte  *imagedata, *ip, *pp;
2368       int   j, imWIDE, nullCount;
2369 
2370       nullCount = (4 - (wide % 4)) & 0x03;  /* # of padding bytes per line */
2371       imWIDE = wide + nullCount;
2372 
2373       /* Now create the image data - pad each scanline as necessary */
2374       imagedata = (byte *) malloc((size_t) (imWIDE * high));
2375       if (!imagedata) FatalError("couldn't malloc imagedata");
2376 
2377       for (i=0, pp=pic8, ip=imagedata; i<high; i++) {
2378 	if (((i+1)&0x7f) == 0) WaitCursor();
2379 
2380 	if (bwdith)
2381 	  for (j=0; j<wide; j++, ip++, pp++) *ip = *pp;
2382 	else
2383 	  for (j=0; j<wide; j++, ip++, pp++) *ip = stdcols[*pp];
2384 
2385 	for (j=0; j<nullCount; j++, ip++)  *ip = 0;
2386       }
2387 
2388       xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0,
2389 			 (char *) imagedata,  wide,  high,
2390 			 32, imWIDE);
2391       if (!xim) FatalError("couldn't create xim!");
2392     }
2393       break;
2394 
2395 
2396       /*********************************/
2397 
2398     case 4: {
2399       byte         *imagedata, *ip, *pp;
2400       byte         *lip;
2401       int           bperline, half, j;
2402       unsigned long xcol;
2403 
2404       xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
2405 			  wide,  high, 32, 0);
2406       if (!xim) FatalError("couldn't create xim!");
2407 
2408       bperline = xim->bytes_per_line;
2409       imagedata = (byte *) malloc((size_t) (bperline * high));
2410       if (!imagedata) FatalError("couldn't malloc imagedata");
2411       xim->data = (char *) imagedata;
2412 
2413       pp = pic8;
2414 
2415       if (xim->bits_per_pixel == 4) {
2416 	for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
2417 	  if (((i+1)&0x7f) == 0) WaitCursor();
2418 
2419 	  for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) {
2420 	    xcol = ((bwdith) ? *pp : stdcols[*pp]) & 0x0f;
2421 
2422 	    if (xim->byte_order == LSBFirst) {
2423 	      if (half&1) { *ip = *ip + (xcol<<4);  ip++; }
2424 	      else *ip = xcol;
2425 	    }
2426 	    else {
2427 	      if (half&1) { *ip = *ip + xcol;  ip++; }
2428 	      else *ip = xcol << 4;
2429 	    }
2430 	  }
2431 	}
2432       }
2433 
2434       else if (xim->bits_per_pixel == 8) {
2435 	for (i=0,lip=imagedata; i<high; i++,lip+=bperline) {
2436 	  if (((i+1)&0x7f)==0) WaitCursor();
2437 	  for (j=0,ip=lip; j<wide; j++,pp++,ip++) {
2438 	    *ip = (bwdith) ? *pp : (byte) stdcols[*pp];
2439 	  }
2440 	}
2441       }
2442 
2443       else FatalError("This display's too bizarre.  Can't create XImage.");
2444     }
2445       break;
2446 
2447 
2448 
2449       /*********************************/
2450 
2451     case 2: {  /* by M.Kossa@frec.bull.fr (Marc Kossa) */
2452                /* MSBFirst mods added by dale@ntg.com (Dale Luck) */
2453                /* additional fixes by  evol@infko.uni-koblenz.de
2454 		  (Randolf Werner) for NeXT 2bit grayscale with MouseX */
2455 
2456       byte  *imagedata, *ip, *pp;
2457       byte *lip;
2458       int  bperline, half, j;
2459       unsigned long xcol;
2460 
2461       xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
2462 			  wide,  high, 32, 0);
2463       if (!xim) FatalError("couldn't create xim!");
2464 
2465       bperline = xim->bytes_per_line;
2466       imagedata = (byte *) malloc((size_t) (bperline * high));
2467       if (!imagedata) FatalError("couldn't malloc imagedata");
2468       xim->data = (char *) imagedata;
2469 
2470       pp = pic8;
2471 
2472       if (xim->bits_per_pixel == 2) {
2473 	for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
2474 	  if (((i+1)&0x7f) == 0) WaitCursor();
2475 	  for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) {
2476 	    xcol = ((bwdith) ? *pp : stdcols[*pp]) & 0x03;
2477 
2478 	    if (xim->bitmap_bit_order == LSBFirst) {
2479 	      if      (half%4==0) *ip  = xcol;
2480 	      else if (half%4==1) *ip |= (xcol<<2);
2481 	      else if (half%4==2) *ip |= (xcol<<4);
2482 	      else              { *ip |= (xcol<<6); ip++; }
2483 	    }
2484 
2485 	    else {  /* MSBFirst.  NeXT, among others */
2486 	      if      (half%4==0) *ip  = (xcol<<6);
2487 	      else if (half%4==1) *ip |= (xcol<<4);
2488 	      else if (half%4==2) *ip |= (xcol<<2);
2489 	      else              { *ip |=  xcol;     ip++; }
2490 	    }
2491 	  }
2492 	}
2493       }
2494 
2495       else if (xim->bits_per_pixel == 4) {
2496 	for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
2497 	  if (((i+1)&0x7f) == 0) WaitCursor();
2498 
2499 	  for (j=0, ip=lip, half=0; j<wide; j++,pp++,half++) {
2500 	    xcol = ((bwdith) ? *pp : stdcols[*pp]) & 0x0f;
2501 
2502 	    if (xim->bitmap_bit_order == LSBFirst) {
2503 	      if (half&1) { *ip |= (xcol<<4);  ip++; }
2504 	      else *ip = xcol;
2505 	    }
2506 
2507 	    else { /* MSBFirst */
2508 	      if (half&1) { *ip |= xcol;  ip++; }
2509 	      else *ip = xcol << 4;
2510 	    }
2511 	  }
2512 	}
2513       }
2514 
2515       else if (xim->bits_per_pixel == 8) {
2516 	for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
2517 	  if (((i+1)&0x7f) == 0) WaitCursor();
2518 
2519 	  for (j=0, ip=lip; j<wide; j++,pp++,ip++) {
2520 	    *ip = ((bwdith) ? *pp : stdcols[*pp]) & 0xff;
2521 	  }
2522 	}
2523       }
2524 
2525       else FatalError("This display's too bizarre.  Can't create XImage.");
2526     }
2527       break;
2528 
2529 
2530       /*********************************/
2531 
2532     case 6: {
2533       byte  *imagedata, *lip, *ip, *pp;
2534       int  bperline;
2535 
2536       xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
2537 			  wide,  high, 32, 0);
2538       if (!xim) FatalError("couldn't create xim!");
2539 
2540       if (xim->bits_per_pixel != 8)
2541 	FatalError("This display's too bizarre.  Can't create XImage.");
2542 
2543       bperline = xim->bytes_per_line;
2544       imagedata = (byte *) malloc((size_t) (bperline * high));
2545       if (!imagedata) FatalError("couldn't malloc imagedata");
2546       xim->data = (char *) imagedata;
2547 
2548       pp = pic8;
2549 
2550       for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
2551 	if (((i+1)&0x7f) == 0) WaitCursor();
2552 
2553 	for (j=0, ip=lip; j<wide; j++,pp++,ip++) {
2554 	  *ip = ((bwdith) ? *pp : stdcols[*pp]) & 0x3f;
2555 
2556 	}
2557       }
2558     }
2559       break;
2560 
2561 
2562       /*********************************/
2563 
2564     case 15:
2565     case 16: {
2566       unsigned short  *imagedata, *ip, *lip;
2567       byte   *pp;
2568       int     bperline;
2569       unsigned long xcol;
2570 
2571       imagedata = (unsigned short *) malloc((size_t) (2*wide*high));
2572       if (!imagedata) FatalError("couldn't malloc imagedata");
2573 
2574       xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
2575 			 (char *) imagedata, wide, high, 32, 0);
2576       if (!xim) FatalError("couldn't create xim!");
2577       bperline = xim->bytes_per_line;
2578 
2579       pp = pic8;
2580 
2581       if (xim->byte_order == MSBFirst) {
2582 	for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
2583 	  if (((i+1)&0x7f) == 0) WaitCursor();
2584 
2585 	  for (j=0, ip=lip; j<wide; j++,pp++) {
2586 	    *ip++ = ((bwdith) ? *pp : stdcols[*pp]) & 0xffff;
2587 	  }
2588 	}
2589       }
2590 
2591       else {   /* LSBFirst */
2592 	for (i=0, lip=imagedata; i<high; i++, lip+=bperline) {
2593 	  if (((i+1)&0x7f) == 0) WaitCursor();
2594 
2595 	  for (j=0, ip=lip; j<wide; j++,pp++) {
2596 	    xcol = ((bwdith) ? *pp : stdcols[*pp]) & 0xffff;
2597 	    /* WAS *ip++ = ((xcol>>8) & 0xff) | ((xcol&0xff) << 8);  */
2598 	    *ip++ = (unsigned short) (xcol);
2599 	  }
2600 	}
2601       }
2602     }
2603       break;
2604 
2605 
2606       /*********************************/
2607 
2608       /* this wouldn't seem likely to happen, but what the heck... */
2609 
2610     case 24:
2611     case 32: {
2612       byte  *imagedata, *ip, *pp;
2613       unsigned long xcol;
2614       int bperpix;
2615 
2616       imagedata = (byte *) malloc((size_t) (4*wide*high));
2617       if (!imagedata) FatalError("couldn't malloc imagedata");
2618 
2619       xim = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
2620 			 (char *) imagedata, wide, high, 32, 0);
2621       if (!xim) FatalError("couldn't create xim!");
2622 
2623       bperpix = xim->bits_per_pixel;
2624 
2625       pp = pic8;
2626 
2627       if (xim->byte_order == MSBFirst) {
2628 	for (i=wide*high, ip=imagedata; i>0; i--,pp++) {
2629 	  if (((i+1)&0x1ffff) == 0) WaitCursor();
2630 	  xcol = (bwdith) ? *pp : stdcols[*pp];
2631 
2632 	  if (bperpix == 32) *ip++ = 0;
2633 	  *ip++ = (xcol>>16) & 0xff;
2634 	  *ip++ = (xcol>>8)  & 0xff;
2635 	  *ip++ =  xcol      & 0xff;
2636 	}
2637       }
2638 
2639       else {  /* LSBFirst */
2640 	for (i=wide*high, ip=imagedata; i>0; i--,pp++) {
2641 	  xcol = (bwdith) ? *pp : stdcols[*pp];
2642 
2643 	  if (((i+1)&0x1ffff) == 0) WaitCursor();
2644 	  *ip++ =  xcol      & 0xff;
2645 	  *ip++ = (xcol>>8)  & 0xff;
2646 	  *ip++ = (xcol>>16) & 0xff;
2647 	  if (bperpix == 32) *ip++ = 0;
2648 	}
2649       }
2650     }
2651       break;
2652 
2653     }   /* end of the switch */
2654 
2655     free(pic8);  /* since we ALWAYS make a copy of it into imagedata */
2656   }
2657 
2658 
2659   return xim;
2660 }
2661 
2662 
2663 
2664 /***********************************************************/
Set824Menus(mode)2665 void Set824Menus(mode)
2666      int mode;
2667 {
2668   /* move checkmark */
2669   conv24MB.flags[CONV24_8BIT]  = (mode==PIC8);
2670   conv24MB.flags[CONV24_24BIT] = (mode==PIC24);
2671 
2672   if (mode == PIC24) {
2673     dispMB.dim[DMB_COLNORM] = 1;
2674     dispMB.dim[DMB_COLPERF] = 1;
2675     dispMB.dim[DMB_COLOWNC] = 1;
2676 
2677     /* turn off RAW/DITH/SMOOTH buttons (caused by picType) */
2678     epicMode = EM_RAW;
2679     SetEpicMode();
2680 
2681     /* turn off autoapply mode */
2682     /* GamSetAutoApply(0); */       /* or not! */
2683   }
2684 
2685   else if (mode == PIC8) {
2686     dispMB.dim[DMB_COLNORM] = 0;
2687     dispMB.dim[DMB_COLPERF] = (dispMode == RMB_WINDOW) ? 0 : 1;
2688     dispMB.dim[DMB_COLOWNC] = (dispMode == RMB_WINDOW) ? 0 : 1;
2689 
2690     /* turn on RAW/DITH/SMOOTH buttons */
2691     epicMode = EM_RAW;
2692     SetEpicMode();
2693 
2694     /* possibly turn autoapply back on */
2695     /* GamSetAutoApply(-1); */  /* -1 means 'back to default setting' */
2696   }
2697 
2698   SetDirSaveMode(F_COLORS, -1);    /* enable/disable REDUCED COLOR */
2699 }
2700 
2701 
2702 /***********************************************************/
Change824Mode(mode)2703 void Change824Mode(mode)
2704      int mode;
2705 {
2706   if (mode == picType) return;   /* same mode, do nothing */
2707 
2708   Set824Menus(mode);
2709 
2710   if (!pic) {  /* done all we wanna do when there's no pic */
2711     picType = mode;
2712     return;
2713   }
2714 
2715   /* should probably actually *do* something involving colors, regenrating
2716      pic's, drawing an Ximage, etc. */
2717 
2718   if (mode == PIC24) {
2719     byte *pic24;
2720 
2721     WaitCursor();
2722     pic24 = Conv8to24(pic, pWIDE, pHIGH, rorg,gorg,borg);
2723     if (!pic24) FatalError("Ran out of memory in Change824Mode()\n");
2724 
2725     KillOldPics();
2726     pic = pic24;  picType = PIC24;
2727 
2728     Set824Menus(picType);            /* RAW/DITH/SMOOTH buttons change */
2729     InstallNewPic();
2730   }
2731 
2732 
2733   else if (mode == PIC8) {
2734     byte *pic8;
2735 
2736     WaitCursor();
2737     pic8 = Conv24to8(pic, pWIDE, pHIGH, ncols, rMap,gMap,bMap);
2738     if (!pic8) FatalError("Ran out of memory in Change824Mode()\n");
2739 
2740     KillOldPics();
2741     pic = pic8;  picType = PIC8;
2742 
2743     Set824Menus(picType);            /* RAW/DITH/SMOOTH buttons change */
2744     InstallNewPic();
2745   }
2746 
2747   /* may have to explicitly redraw image window if not using root */
2748 }
2749 
2750 
2751 /***********************************************************/
FreeEpic()2752 void FreeEpic()
2753 {
2754   if (egampic && egampic != epic) free(egampic);
2755   if (epic && epic != cpic) free(epic);
2756   epic = egampic = NULL;
2757 }
2758 
2759 
2760 /***********************************************************/
InvertPic24(pic24,w,h)2761 void InvertPic24(pic24, w, h)
2762      byte *pic24;
2763      int   w,h;
2764 {
2765   int i;
2766 
2767   for (i=w*h*3; i; i--, pic24++) *pic24 = 255 - *pic24;
2768 }
2769 
2770 
2771 
2772 
2773 /***********************/
2774 #if 0 /* NOTUSED */
2775 static int highbit(ul)
2776 unsigned long ul;
2777 {
2778   /* returns position of highest set bit in 'ul' as an integer (0-31),
2779    or -1 if none */
2780 
2781   int i;  unsigned long hb;
2782 
2783   hb = 0x80;  hb = hb << 24;   /* hb = 0x80000000UL */
2784   for (i=31; ((ul & hb) == 0) && i>=0;  i--, ul<<=1);
2785   return i;
2786 }
2787 #endif /* 0 - NOTUSED */
2788 
2789 
2790 
2791 /***********************************************************/
XVGetSubImage(pic,ptype,w,h,sx,sy,sw,sh)2792 byte *XVGetSubImage(pic, ptype, w,h, sx,sy,sw,sh)
2793      byte *pic;
2794      int   ptype, w,h, sx,sy,sw,sh;
2795 {
2796   /* mallocs and returns the selected subimage (sx,sy,sw,sh) of pic.
2797      selection is guaranteed to be within pic boundaries.
2798      NEVER RETURNS NULL */
2799 
2800   byte *rpic, *sp, *dp;
2801   int   bperpix,x,y;
2802 
2803   /* sanity check: */
2804   if (sx<0 || sy<0 || sx+sw > w || sy+sh > h || sw<1 || sh<1) {
2805     fprintf(stderr,"XVGetSubImage:  w,h=%d,%d  sel = %d,%d %dx%d\n",
2806 	    w, h, sx, sy, sw, sh);
2807     FatalError("XVGetSubImage:  value out of range (shouldn't happen!)");
2808   }
2809 
2810 
2811   bperpix = (ptype==PIC8) ? 1 : 3;
2812   rpic = (byte *) malloc((size_t) bperpix * sw * sh);
2813   if (!rpic) FatalError("out of memory in XVGetSubImage");
2814 
2815   for (y=0; y<sh; y++) {
2816     sp = pic  + ((y+sy)*w + sx) * bperpix;
2817     dp = rpic + (y * sw) * bperpix;
2818     for (x=0; x<(sw*bperpix); x++, dp++, sp++) *dp = *sp;
2819   }
2820 
2821   return rpic;
2822 }
2823 
2824 
2825 
2826 
2827 static byte *padPic = (byte *) NULL;
2828 static byte  padmapR[256], padmapG[256], padmapB[256];
2829 static int   padType, padWide, padHigh;
2830 
2831 static char *holdcomment = (char *) NULL;
2832 static char *holdfname   = (char *) NULL;
2833 
2834 /***********************************/
DoPad(mode,str,wide,high,opaque,omode)2835 int DoPad(mode, str, wide, high, opaque, omode)
2836      int   mode, wide, high, opaque, omode;
2837      char *str;
2838 {
2839   /* parses/verifies user-entered string.  If valid, does the thing, and
2840      installs the new pic and all that...  Returns '0' on failure */
2841 
2842   int   rv;
2843 
2844   if (padPic)      free(padPic);
2845   if (holdcomment) free(holdcomment);
2846   if (holdfname)   free(holdcomment);
2847   padPic = (byte *) NULL;
2848   holdcomment = holdfname = (char *) NULL;
2849 
2850   rv = 1;
2851 
2852   if ((mode != PAD_LOAD) && (wide == cWIDE && high == cHIGH && opaque==100)) {
2853     ErrPopUp("Padding to same size as pic while fully opaque has no effect.",
2854 	     "\nI see");
2855     return 0;
2856   }
2857 
2858   WaitCursor();
2859 
2860   if      (mode == PAD_SOLID) rv = doPadSolid(str, wide, high, opaque,omode);
2861   else if (mode == PAD_BGGEN) rv = doPadBggen(str, wide, high, opaque,omode);
2862   else if (mode == PAD_LOAD)  rv = doPadLoad (str, wide, high, opaque,omode);
2863 
2864   SetCursors(-1);
2865 
2866   if (!rv) return 0;
2867 
2868   if (picComments) {
2869     holdcomment = (char *) malloc(strlen(picComments) + 1);
2870     if (holdcomment) strcpy(holdcomment, picComments);
2871   }
2872 
2873   holdfname = (char *) malloc(strlen(fullfname) + 1);
2874   if (holdfname) strcpy(holdfname, fullfname);
2875 
2876   return 1;
2877 }
2878 
2879 
2880 /***********************************/
LoadPad(pinfo,fname)2881 int LoadPad(pinfo, fname)
2882      PICINFO *pinfo;
2883      char    *fname;
2884 {
2885   /* loads up into XV structures results of last 'pad' command.
2886      returns 0 on failure, 1 on success */
2887 
2888   int i;
2889 
2890   if (!padPic) return 0;
2891   pinfo->type = padType;
2892 
2893   for (i=0; i<256; i++) {
2894     pinfo->r[i] = padmapR[i];
2895     pinfo->g[i] = padmapG[i];
2896     pinfo->b[i] = padmapB[i];
2897   }
2898 
2899   pinfo->pic = padPic;
2900   pinfo->w   = padWide;
2901   pinfo->h   = padHigh;
2902   pinfo->frmType = -1;
2903   pinfo->colType = -1;
2904 
2905   sprintf(pinfo->fullInfo, "<%s internal>",
2906 	  (pinfo->type == PIC8) ? "8-bit" : "24-bit");
2907 
2908   sprintf(pinfo->shrtInfo, "%dx%d image", padWide, padHigh);
2909 
2910   pinfo->comment = holdcomment;
2911 
2912   if (holdfname) {
2913     strcpy(fname, holdfname);
2914     free(holdfname);
2915     holdfname = (char *) NULL;
2916   }
2917   else strcpy(fname, "");
2918 
2919   padPic      = (byte *) NULL;
2920   holdcomment = (char *) NULL;
2921 
2922   return 1;
2923 }
2924 
2925 
2926 
2927 /*******************************/
doPadSolid(str,wide,high,opaque,omode)2928 static int doPadSolid(str, wide, high, opaque,omode)
2929      char *str;
2930      int   wide, high, opaque,omode;
2931 {
2932   /* returns 0 on error, 1 if successful */
2933 
2934   byte *pic24, *pp;
2935   int   i, solidRGB, r,g,b,rgb;
2936   char  errstr[256];
2937 
2938   solidRGB = 0;
2939 
2940 
2941   /* PARSE STRING:  'r,g,b'  'r g b'  '0xrrggbb' or <name> */
2942 
2943   if ((sscanf(str, "%d,%d,%d", &r,&g,&b) == 3) &&
2944       (r>=0 && r<=255 && g>=0 && g<=255 && b>=0 && b<=255)) {
2945     solidRGB = ((r&0xff)<<16) | ((g&0xff)<<8) | (b&0xff);
2946   }
2947   else if ((sscanf(str, "%d %d %d", &r,&g,&b) == 3) &&
2948 	   (r>=0 && r<=255 && g>=0 && g<=255 && b>=0 && b<=255)) {
2949     solidRGB = ((r&0xff)<<16) | ((g&0xff)<<8) | (b&0xff);
2950   }
2951   else if (sscanf(str, "0x%x", &rgb) && rgb>=0 && rgb<=0xffffff) {
2952     solidRGB = rgb;
2953   }
2954   else {   /* assume a colorname */
2955     XColor ecdef, sdef;
2956     if (XLookupColor(theDisp, theCmap, str, &ecdef, &sdef)) {
2957       solidRGB = (((ecdef.red  >>8)&0xff) << 16) |
2958 	         (((ecdef.green>>8)&0xff) <<  8) |
2959 	         (((ecdef.blue >>8)&0xff));
2960     }
2961     else {
2962       sprintf(errstr, "Error:  Color specification '%s' not recognized.",str);
2963       ErrPopUp(errstr, "\nOk");
2964       return 0;
2965     }
2966   }
2967 
2968 
2969 
2970   pic24 = (byte *) malloc(wide * high * 3 * sizeof(byte));
2971   if (!pic24) {
2972     sprintf(errstr,"Error:  Can't alloc memory for %d x %d image.",
2973 	    wide, high);
2974     ErrPopUp(errstr, "\n:-(");
2975     return 0;
2976   }
2977 
2978 
2979   /* fill pic24 with solidRGB */
2980   for (i=0,pp=pic24; i<wide*high; i++, pp+=3) {
2981     pp[0] = (solidRGB>>16) & 0xff;
2982     pp[1] = (solidRGB>>8)  & 0xff;
2983     pp[2] = (solidRGB)     & 0xff;
2984   }
2985 
2986   i = doPadPaste(pic24, wide, high, opaque,omode);
2987 
2988   return i;
2989 }
2990 
2991 
2992 
2993 /*******************************/
doPadBggen(str,wide,high,opaque,omode)2994 static int doPadBggen(str, wide, high, opaque,omode)
2995      char *str;
2996      int   wide, high, opaque,omode;
2997 {
2998 #ifndef USE_MKSTEMP
2999   int tmpfd;
3000 #endif
3001   int i;
3002   byte *bgpic24;
3003   char syscmd[512], fname[128], errstr[512];
3004   PICINFO pinfo;
3005 
3006   /* returns 0 on error, 1 if successful */
3007 
3008   if (xv_strstr(str, "-h") || xv_strstr(str, "-w") || xv_strstr(str,"-g") ||
3009       xv_strstr(str, ">")) {
3010     ErrPopUp(
3011 	 "Error:  No redirection or '-h', '-w' or '-g' options are allowed.",
3012 	     "\nOk");
3013     return 0;
3014   }
3015 
3016 
3017 #ifndef VMS
3018   sprintf(fname, "%s/xvXXXXXX", tmpdir);
3019 #else
3020   strcpy(fname, "Sys$Disk:[]xvuXXXXXX");
3021 #endif
3022 #ifdef USE_MKSTEMP
3023   close(mkstemp(fname));
3024 #else
3025   mktemp(fname);
3026   tmpfd = open(fname, O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR);
3027   if (tmpfd < 0) {
3028     sprintf(errstr, "Error: can't create temporary file %s", fname);
3029     ErrPopUp(errstr, "\nDoh!");
3030     return 0;
3031   }
3032   close(tmpfd);
3033 #endif
3034 
3035   /* run bggen to generate the background */
3036   sprintf(syscmd, "bggen -g %dx%d %s > %s", wide, high, str, fname);
3037   SetISTR(ISTR_INFO, "Running 'bggen %s'...", str);
3038 
3039   i = system(syscmd);
3040 #ifdef VMS
3041   i = !i;       /* VMS returns 1 on success */
3042 #endif
3043   if (i) {
3044     unlink(fname);
3045     sprintf(errstr, "Error:  Running '%s' failed, for some reason.", syscmd);
3046     ErrPopUp(errstr, "\nDoh!");
3047     return 0;
3048   }
3049 
3050 
3051   /* read the file that's been created */
3052   if (!ReadImageFile1(fname, &pinfo)) {
3053     unlink(fname);
3054     return 0;
3055   }
3056 
3057   unlink(fname);
3058 
3059   if (pinfo.comment) free(pinfo.comment);
3060   pinfo.comment = (char *) NULL;
3061 
3062   if (pinfo.type == PIC24) bgpic24 = pinfo.pic;
3063   else {
3064     bgpic24 = Conv8to24(pinfo.pic,pinfo.w,pinfo.h, pinfo.r,pinfo.g,pinfo.b);
3065     free(pinfo.pic);  pinfo.pic = (byte *) NULL;
3066   }
3067 
3068   if (!bgpic24) {
3069     ErrPopUp("Couldn't generate background image.  malloc() failure?", "\nOk");
3070     return 0;
3071   }
3072 
3073 
3074   i = doPadPaste(bgpic24, pinfo.w, pinfo.h, opaque,omode);
3075 
3076   return i;
3077 }
3078 
3079 
3080 /*******************************/
doPadLoad(str,wide,high,opaque,omode)3081 static int doPadLoad(str, wide, high, opaque,omode)
3082      char *str;
3083      int   wide, high, opaque,omode;
3084 {
3085   int i;
3086   byte *bgpic24;
3087   char loadName[256];
3088   PICINFO pinfo;
3089 
3090   /* returns 0 on error, 1 if successful */
3091 
3092   /* use first word as filename to load. */
3093   if (sscanf(str, "%s", loadName) != 1) {
3094     ErrPopUp("Error:  The entered string is not valid.", "\nOk");
3095     return 0;
3096   }
3097 
3098   if (!ReadImageFile1(loadName, &pinfo)) return 0;
3099 
3100   if (pinfo.comment) free(pinfo.comment);
3101   pinfo.comment = (char *) NULL;
3102 
3103   if (pinfo.type == PIC24) bgpic24 = pinfo.pic;
3104   else {
3105     bgpic24 = Conv8to24(pinfo.pic,pinfo.w,pinfo.h, pinfo.r,pinfo.g,pinfo.b);
3106     free(pinfo.pic);  pinfo.pic = (byte *) NULL;
3107   }
3108 
3109   if (!bgpic24) {
3110     ErrPopUp("Couldn't generate background image.  malloc() failure?", "\nOk");
3111     return 0;
3112   }
3113 
3114 
3115   i = doPadPaste(bgpic24, pinfo.w, pinfo.h, opaque,omode);
3116 
3117   return i;
3118 }
3119 
3120 
3121 /*******************************/
doPadPaste(pic24,wide,high,opaque,omode)3122 static int doPadPaste(pic24, wide, high, opaque,omode)
3123      byte *pic24;
3124      int   wide, high, opaque,omode;
3125 {
3126   /* copies 'pic' onto the given 24-bit background image, converts back to
3127      8-bit (if necessary), and loads up pad* variables.
3128      frees pic24 if necessary */
3129 
3130   byte *pp, *p24;
3131   int py,px, p24y,p24x, sx,sy;
3132   int fg, bg;
3133   int rval,gval,bval, r, g, b;
3134 
3135 
3136   fg = opaque;
3137   bg = 100 - opaque;
3138 
3139 
3140   /* copy 'pic' centered onto pic24.  */
3141 
3142   sx = (wide - cWIDE) / 2;
3143   sy = (high - cHIGH) / 2;
3144 
3145   for (py = 0; py<cHIGH; py++) {
3146     ProgressMeter(0, cHIGH-1, py, "Pad");
3147     if ((py & 0x1f)==0) WaitCursor();
3148 
3149     p24y = sy + py;
3150     if (p24y >= 0 && p24y < high) {
3151       for (px=0; px<cWIDE; px++) {
3152 	p24x = sx + px;
3153 	if (p24x >= 0 && p24x < wide) {
3154 	  p24 = pic24 + (p24y*wide  + p24x)*3;
3155 
3156 
3157 	  if (picType == PIC24) {                       /* src is PIC24 */
3158 	    pp  = cpic + (py * cWIDE + px)  *3;
3159 	    r = pp[0];  g = pp[1];  b = pp[2];
3160 	  }
3161 	  else {                                        /* src is PIC8 */
3162 	    pp  = cpic + (py*cWIDE + px);
3163 	    r = rMap[*pp];  g = gMap[*pp];  b = bMap[*pp];
3164 	  }
3165 
3166 	  if (omode == PAD_ORGB) {
3167 	    rval = (r * fg) / 100 + ((int) p24[0] * bg) / 100;
3168 	    gval = (g * fg) / 100 + ((int) p24[1] * bg) / 100;
3169 	    bval = (b * fg) / 100 + ((int) p24[2] * bg) / 100;
3170 	  }
3171 	  else {       /* one of the HSV modes */
3172 	    double fh,fs,fv,fw, bh,bs,bv,bw, h,s,v;
3173 	    fw = fg / 100.0;  bw = bg / 100.0;
3174 	    rgb2hsv(r,g,b, &fh,&fs,&fv);
3175 	    rgb2hsv((int) p24[0], (int) p24[1], (int) p24[2], &bh,&bs,&bv);
3176 
3177 	    h = s = v = 0.0;
3178 
3179 	    if (omode == PAD_OINT) {
3180 	      h = fh;
3181 	      s = fs;
3182 	      /* v = (fv * fg) / 100.0 + (bv * bg) / 100.0; */
3183 	      v = (fv * bv * bw) + (fv * fw);
3184 	    }
3185 	    else if (omode == PAD_OSAT) {
3186 	      if (fh<0) fs = 0.0;   /* NOHUE is unsaturated */
3187 	      if (bh<0) bs = 0.0;
3188 	      h = fh;
3189 	      /* s = (fs * fg) / 100.0 + (bs * bg) / 100.0; */
3190 	      s = (fs * bs * bw) + (fs * fw);
3191 	      v = fv;
3192 	    }
3193 	    else if (omode == PAD_OHUE) {   /* the hard one! */
3194 	      int fdeg,bdeg;
3195 
3196 	      fdeg = (fh<0) ? -1 : (int) floor(fh + 0.5);
3197 	      bdeg = (bh<0) ? -1 : (int) floor(bh + 0.5);
3198 
3199 	      if (fdeg>=0 && bdeg>=0) {           /* both are colors */
3200 		/* convert H,S onto x,y coordinates on the colorwheel for
3201 		   constant V */
3202 
3203 		double fx,fy, bx,by, ox,oy;
3204 
3205 		if (fg == 100 || bg == 100) {   /* E-Z special case */
3206 		  if (fg==100) { h = fh;  s = fs;  v=fv; }
3207 		  else         { h = bh;  s = fs;  v=fv; }
3208 		}
3209 		else {  /* general case */
3210 
3211 		  fh *= (3.14159 / 180.0);    /* -> radians */
3212 		  bh *= (3.14159 / 180.0);
3213 
3214 		  fx = fs * cos(fh);  fy = fs * sin(fh);
3215 		  bx = bs * cos(bh);  by = bs * sin(bh);
3216 
3217 		  /* compute pt. on line between fx,fy and bx,by */
3218 		  ox = (fx * (fg/100.0)) + (bx * (bg/100.0));
3219 		  oy = (fy * (fg/100.0)) + (by * (bg/100.0));
3220 
3221 		  /* convert ox,oy back into hue,sat */
3222 		  s = sqrt((ox * ox) + (oy * oy));
3223 		  if (ox == 0.0) {
3224 		    h = (oy>=0.0) ? 90.0 : 270.0;
3225 		  }
3226 		  else {
3227 		    h = atan(oy / ox);
3228 		    h *= (180.0 / 3.14159);
3229 		    if (ox<0.0) h += 180.0;
3230 		    while (h<0.0) h += 360.0;
3231 		    while (h>=360.0) h -= 360.0;
3232 		  }
3233 
3234 		  v = fv;
3235 		}
3236 	      }
3237 
3238 	      else if (fdeg<0 && bdeg<0) {        /* both are NOHUE */
3239 		h = -1.0;
3240 		s = fs;
3241 		v = fv;
3242 	      }
3243 
3244 	      else if (bdeg<0) {                  /* backgrnd is white */
3245 		h = fh;
3246 		v = fv;
3247 		s = (fs * fg) / 100.0;
3248 	      }
3249 
3250 	      else {                              /* foregrnd is white */
3251 		h = bh;
3252 		v = fv;
3253 		s = (bs * bg) / 100.0;
3254 	      }
3255 	    }
3256 
3257 	    v = (fv * bv * bw) + (fv * fw);
3258 	    hsv2rgb(h,s,v, &rval,&gval,&bval);
3259 	  }
3260 
3261 	  RANGE(rval, 0, 255);  RANGE(gval, 0, 255);  RANGE(bval, 0, 255);
3262 	  *p24++ = rval;  *p24++ = gval;  *p24++ = bval;
3263 	}
3264       }
3265     }
3266   }
3267 
3268 
3269   /* build 'padPic' appropriately */
3270   if (picType == PIC8) {   /* put back to 8-bit */
3271     padPic = Conv24to8(pic24, wide, high, ncols, padmapR, padmapG, padmapB);
3272     free(pic24);
3273     if (!padPic) {
3274       SetCursors(-1);
3275       ErrPopUp("Failure occured in 24to8 conversion\n","\nDamn!");
3276       return 0;
3277     }
3278     padType = PIC8;
3279     padWide = wide;
3280     padHigh = high;
3281   }
3282   else {                    /* PIC24 */
3283     padPic  = pic24;
3284     padType = PIC24;
3285     padWide = wide;
3286     padHigh = high;
3287   }
3288 
3289   return 1;
3290 }
3291 
3292 
3293 /*******************************/
ReadImageFile1(name,pinfo)3294 static int ReadImageFile1(name, pinfo)
3295      char    *name;
3296      PICINFO *pinfo;
3297 {
3298   int  i, ftype;
3299   char uncompname[128], errstr[256], *uncName, *readname;
3300 #ifdef VMS
3301   char basefname[128];
3302 #endif
3303 
3304   ftype = ReadFileType(name);
3305 
3306   if ((ftype == RFT_COMPRESS) || (ftype == RFT_BZIP2)) {  /* handle .Z,gz,bz2 */
3307 #ifdef VMS
3308     basefname[0] = '\0';
3309     strcpy(basefname, name);     /* remove trailing .Z */
3310     *rindex(basefname, '.') = '\0';
3311     uncName = basefname;
3312 #else
3313     uncName = name;
3314 #endif
3315 
3316     if (UncompressFile(uncName, uncompname, ftype)) {
3317       ftype = ReadFileType(uncompname);
3318       readname = uncompname;
3319     }
3320     else {
3321       sprintf(errstr, "Error:  Couldn't uncompress file '%s'", name);
3322       ErrPopUp(errstr, "\nOk");
3323       return 0;
3324     }
3325   }
3326 
3327 
3328   if (ftype == RFT_ERROR) {
3329     sprintf(errstr, "Couldn't open file '%s'\n\n  %s.", name, ERRSTR(errno));
3330     ErrPopUp(errstr, "\nOk");
3331     return 0;
3332   }
3333   else if (ftype == RFT_UNKNOWN) {
3334     sprintf(errstr, "Error:  File '%s' not in a recognized format.", name);
3335     ErrPopUp(errstr, "\nOk");
3336     return 0;
3337   }
3338   else {                         /* try to read it */
3339     i = ReadPicFile(name, ftype, pinfo, 1);
3340     KillPageFiles(pinfo->pagebname, pinfo->numpages);
3341 
3342     if (!i || (i && (pinfo->w<=0 || pinfo->h<=0))) {
3343       if (i) {
3344 	if (pinfo->pic)     free(pinfo->pic);
3345 	if (pinfo->comment) free(pinfo->comment);
3346       }
3347       sprintf(errstr, "Couldn't load file '%s'.", name);
3348       ErrPopUp(errstr, "\nOk");
3349       return 0;
3350     }
3351 
3352     /* got it! */
3353   }
3354 
3355   return 1;
3356 }
3357