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