/* ******************************************************************************* * * File: xrlc.c * Description: Display large images onto X11 window * Author: Peter H. Michalicka * Copyright: AIC Software, Austria * ******************************************************************************* */ #include #include #include #include #include #include #undef SUN #undef SUN5 /* GXinvert trouble ? */ #undef TEST #ifdef MULTIBUFFER //#include /* HCL - file name changed for NT FAT */ #include #endif /* MULTIBUFFER */ #ifdef WIN32 #include /* HCL - atoi and exit prototypes */ #include /* HCL - HCLXmInit prototype */ #include /* HCL - Xmalloc prototype */ #endif /* #define DEMO -> White Strip */ typedef unsigned short WORD; #include "vma.h" /* PreDefined */ #define BORDERWIDTH 2 #define MIN_W 200 #define MIN_H 200 char defgeo[20]; Display *dpy; Window win; GC gc; int screen; long background, foreground; Font mfont; XFontStruct *mfinfo; int textH, textW; int max_menu; int pfun = 0; char *m_str[11] = { "Zoom", "Pan", "Previous", "50 %", "200 %", "All", "Turn", "Invers", "File+", "File-", "Quit" }; int x = 0, y = 0; int width, height; int width1, height1; int reverse = 0; int hw1; vma *v; double xofs = 1.0; double yofs = 1.0; double xp = 800.0; double yp = 800.0; double scale; int xmin, xmax; int mp_file, mp_act; typedef struct _FileStack { char *imgfile; char *extension; int reverse; int turn; struct _FileStack *next; } FileStack; FileStack *fsroot = NULL; FileStack *fsprv, *fsact, *fsnxt; typedef struct _ZoomStack { double xofs, yofs; double xp, yp; struct _ZoomStack *next; } ZoomStack; ZoomStack *zs = NULL; #define xic(ix) (xofs + (double)(ix) / scale) #define yic(iy) (yofs + (double)(iy) / scale) #define ixc(ix) (int)(xofs + (double)(ix) / scale) #define iyc(iy) (int)(yofs + (double)(iy) / scale) #define xci(ix) (int)(((double)(ix) - xofs) * scale) #define yci(iy) (int)(((double)(iy) - yofs) * scale) /* Externals */ vma *open_image(); WORD *image_ptr(); void close_image(); int error(); extern char *msg_malloc; /* Code */ drawline0(iy) int iy; { int i, rn, rs, re; register WORD *rb; rb = image_ptr(v); rn = (int)*rb; rb++; for (i = 1; i <= rn; i++) { rs = (int)*rb++; re = (int)*rb++; if (re < xmin) continue; if (rs > xmax) return; if (rs < xmin) rs = xmin; if (re > xmax) re = xmax; XDrawLine(dpy, win, gc, xci(rs), iy, xci(re), iy); } } drawline180(iy) int iy; { int i, rn, rs, re; register WORD *rb; rb = image_ptr(v); rn = (int)*rb; rb++; for (i = 1; i <= rn; i++) { rs = (int)*rb++; re = (int)*rb++; if (re < xmin) continue; if (rs > xmax) return; if (rs < xmin) rs = xmin; if (re > xmax) re = xmax; XDrawLine(dpy, win, gc, width1 - xci(rs), iy, width1 - xci(re), iy); } } drawline90(ix) int ix; { int i, rn, rs, re; register WORD *rb; rb = image_ptr(v); rn = (int)*rb; rb++; for (i = 1; i <= rn; i++) { rs = (int)*rb++; re = (int)*rb++; if (re < xmin) continue; if (rs > xmax) return; if (rs < xmin) rs = xmin; if (re > xmax) re = xmax; XDrawLine(dpy, win, gc, ix, height1 - xci(rs), ix, height1 - xci(re)); } } drawline270(ix) int ix; { int i, rn, rs, re; register WORD *rb; rb = image_ptr(v); rn = (int)*rb; rb++; for (i = 1; i <= rn; i++) { rs = (int)*rb++; re = (int)*rb++; if (re < xmin) continue; if (rs > xmax) return; if (rs < xmin) rs = xmin; if (re > xmax) re = xmax; XDrawLine(dpy, win, gc, ix, xci(rs), ix, xci(re)); } } DrawWin() { int j; register int i; #ifdef DEMO int ds, de; #endif XClearWindow(dpy, win); switch (fsact->turn) { case 0: xmin = ixc(0); /* (int)(xofs + (double)(ix) / scale) */ xmax = ixc(width1); #ifdef DEMO ds = (3 * height) >> 3; de = (5 * height) >> 3; #endif for (i = 0; i < height; i++) { #ifdef DEMO if (i > ds && i < de) continue; #endif v->LineNo = iyc(i); if (v->LineNo < 1) continue; if (v->LineNo > v->ImageLength) return; drawline0(i); } break; case 90: xmin = ixc(0); /* (int)(xofs + (double)(ix) / scale) */ xmax = ixc(height1); #ifdef DEMO ds = (3 * width) >> 3; de = (5 * width) >> 3; #endif for (i = 0; i < width; i++) { #ifdef DEMO if (i > ds && i < de) continue; #endif v->LineNo = iyc(i); if (v->LineNo < 1) continue; if (v->LineNo > v->ImageLength) return; drawline90(i); } break; case 180: xmin = ixc(0); /* (int)(xofs + (double)(ix) / scale) */ xmax = ixc(width1); #ifdef DEMO ds = (3 * height) >> 3; de = (5 * height) >> 3; #endif for (i = 0, j = height1; i < height; i++, j--) { #ifdef DEMO if (i > ds && i < de) continue; #endif v->LineNo = iyc(i); if (v->LineNo < 1) continue; if (v->LineNo > v->ImageLength) return; drawline180(j); } break; case 270: xmin = ixc(0); /* (int)(xofs + (double)(ix) / scale) */ xmax = ixc(height1); #ifdef DEMO ds = (3 * width) >> 3; de = (5 * width) >> 3; #endif for (i = 0, j = width1; i < width; i++, j--) { #ifdef DEMO if (i > ds && i < de) continue; #endif v->LineNo = iyc(i); if (v->LineNo < 1) continue; if (v->LineNo > v->ImageLength) return; drawline270(j); } break; } /* esac */ } usage(cmd) char *cmd; { fprintf(stderr, "Programm: %s -f Datei [Optionen]\n", cmd); fputs("Optionen:\n", stderr); fputs(" -t {0,90,180,270} ... Drehwinkel\n", stderr); fputs(" -r ... Invers Video\n", stderr); fputs(" -e {rlc,tif,gp4} ... Kompremierung\n", stderr); fputs(" -g Geometrie ... X-Geometrie\n", stderr); fputs(" -d Display ... X-Displayname\n", stderr); fputs(" -n ... weitere Datei mit Optionen\n", stderr); } calc_scale(xi, yi) double xi, yi; { double fac2; scale = xi / xp; fac2 = yi / yp; if (fac2 < scale) scale = fac2; } calc_defgeo(xi, yi) double xi, yi; { double fac2; scale = xp / xi; fac2 = yp / yi; if (fac2 < scale) scale = fac2; xp = xi; width = (int)(xp * scale); width1 = width - 1; yp = yi; height = (int)(yp * scale); height1 = height - 1; sprintf(defgeo, "%dx%d+10+10", width, height); } main(argc,argv) int argc; char **argv; { extern int optind; extern char *optarg; XSizeHints size_hints; char *fontname = "variable"; char *display = NULL; char *geo = NULL; char *cmd; int flags; int c; cmd = argv[0]; fsact = (FileStack *)malloc(sizeof(FileStack)); fsact->extension = fsact->imgfile = NULL; fsact->reverse = fsact->turn = 0; fsact->next = NULL; while ((c = getopt(argc, argv, "d:e:f:g:nrt:")) != EOF) { switch(c) { case 'd': display = optarg; break; case 'e': fsact->extension = optarg; break; case 'f': fsact->imgfile = optarg; mp_file = 1; break; case 'g': geo = optarg; break; case 'n': fsroot = fsact; mp_file++; fsact = (FileStack *)malloc(sizeof(FileStack)); fsact->extension = fsact->imgfile = NULL; fsact->reverse = fsact->turn = 0; fsact->next = fsroot; break; case 'r': fsact->reverse = 1; break; case 't': if (! sscanf(optarg, "%d", &fsact->turn)) fsact->turn = 0; switch (fsact->turn) { case 0: case 90: case 180: case 270: break; default: usage(cmd); exit(1); } break; case '?': usage(cmd); exit(1); } } if (fsact->next == NULL) { fsroot = fsact; /* one file only */ fsprv = fsnxt = NULL; if (fsact->imgfile == NULL) { usage(cmd); exit(1); } } else { fsroot = NULL; /* reverse single linked file list */ while (fsact != NULL) { if (fsact->imgfile == NULL) { usage(cmd); exit(1); } fsnxt = fsact->next; fsact->next = fsroot; fsroot = fsact; fsact = fsnxt; } fsprv = NULL; fsact = fsroot; fsnxt = fsroot->next; } mp_file--; reverse = fsact->reverse; v = open_image(fsact->imgfile, "./", 1507282L, 32767, fsact->extension); if (v == NULL) { usage(cmd); exit(1); } if (mp_file) { if (fsnxt == NULL && fsprv == NULL) fsnxt = fsprv = fsact; else mp_act = -1; } else mp_act = -1; if (! fsact->turn || fsact->turn == 180) calc_defgeo((double)v->ImageWidth, (double)v->ImageLength); else calc_defgeo((double)v->ImageLength, (double)v->ImageWidth); if ((dpy = XOpenDisplay(display)) == NULL) { fprintf(stderr, "%s: Can\'t open display: %s\n", cmd, XDisplayName(display)); exit(1); } screen = DefaultScreen(dpy); flags = XGeometry (dpy, DefaultScreen(dpy), geo, defgeo, 2, 1, 1, 0, 0, &x, &y, &width, &height); calc_scale((double)width, (double)height); if (reverse) { background = BlackPixel(dpy, screen); foreground = WhitePixel(dpy, screen); } else { background = WhitePixel(dpy, screen); foreground = BlackPixel(dpy, screen); } win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), x, y, width, height, BORDERWIDTH, 1, background); /* printf("win = %ld\n", win); xev -id %ld */ /* set_maze_sizes(width, height); */ XSelectInput(dpy, win, ExposureMask | ButtonPressMask | KeyPressMask); gc = XCreateGC(dpy, win, 0, 0); XSetForeground(dpy, gc, foreground); XSetBackground(dpy, gc, background); #ifdef SUN XSetWindowBackground(dpy, win, background); #else XSetPlaneMask(dpy, gc, WhitePixel(dpy, screen)); #endif if ((mfinfo = XLoadQueryFont(dpy, fontname)) == NULL) fatal("Kann Font '%s' nicht verwenden", fontname); textW = 0; for (c = 0; c < 11; c++) { textH = XTextWidth(mfinfo, m_str[c], strlen(m_str[c])); if (textH > textW) textW = textH; } textH = mfinfo->ascent + mfinfo->descent; mfont = mfinfo->fid; XSetFont(dpy, gc, mfont); size_hints.flags = flags | PMinSize ; size_hints.x = x; size_hints.y = y; size_hints.width = width; size_hints.height = height; size_hints.min_width = (MIN_W < width) ? MIN_W : width; size_hints.min_height = (MIN_H < height) ? MIN_H : height; XSetStandardProperties(dpy, win, "Xrlc", "Xrlc", NULL, argv, argc, &size_hints); XMapWindow(dpy, win); XClearWindow(dpy, win); for (;;) { if (XPending(dpy)) check_events(); } } Rect(x1, y1, x2, y2) int x1, y1, x2, y2; { int x0, y0, w, h; if (x1 > x2) { x0 = x2; w = x1 - x2; } else { x0 = x1; w = x2 - x1; } if (y1 > y2) { y0 = y2; h = y1 - y2; } else { y0 = y1; h = y2 - y1; } if (w > 1 && h > 1) XDrawRectangle(dpy, win, gc, x0, y0, w, h); } int Push() { ZoomStack *new = (ZoomStack *)malloc(sizeof(ZoomStack)); if (new == NULL) return error(msg_malloc, NULL); new->next = zs; new->xofs = xofs; new->yofs = yofs; new->xp = xp; new->yp = yp; zs = new; return 1; } Pop() { ZoomStack *old; if (zs != NULL) { old = zs; zs = zs->next; xofs = old->xofs; yofs = old->yofs; xp = old->xp; yp = old->yp; free(old); calc_scale((double)width, (double)height); DrawWin(); XFlush(dpy); } } ZoomAll() { Push(); xofs = yofs = 1.0; if (fsact->turn == 0 || fsact->turn == 180) { xp = (double)v->ImageWidth; yp = (double)v->ImageLength; } else { xp = (double)v->ImageLength; yp = (double)v->ImageWidth; } calc_scale((double)width, (double)height); DrawWin(); XFlush(dpy); } DoTurn() { switch (fsact->turn) { case 0: fsact->turn = 90; xp = (double)v->ImageLength; yp = (double)v->ImageWidth; break; case 90: fsact->turn = 180; xp = (double)v->ImageWidth; yp = (double)v->ImageLength; break; case 180: fsact->turn = 270; xp = (double)v->ImageLength; yp = (double)v->ImageWidth; break; case 270: fsact->turn = 0; xp = (double)v->ImageWidth; yp = (double)v->ImageLength; break; } xofs = yofs = 1.0; calc_scale((double)width, (double)height); DrawWin(); XFlush(dpy); } calc_zoom(mx, my, ox, oy) int mx, my, ox, oy; { switch (fsact->turn) { case 0: xp = (double)(ox - mx) / scale; yp = (double)(oy - my) / scale; xofs = xic(mx); yofs = yic(my); break; case 90: xp = (double)(oy - my) / scale; yp = (double)(ox - mx) / scale; xofs = xic(height1 - oy); yofs = yic(mx); break; case 180: xp = (double)(ox - mx) / scale; yp = (double)(oy - my) / scale; xofs = xic(width1 - ox); yofs = yic(height1 - oy); break; case 270: xp = (double)(oy - my) / scale; yp = (double)(ox - mx) / scale; xofs = xic(my); yofs = yic(width1 - ox); break; } calc_scale((double)width, (double)height); DrawWin(); XFlush(dpy); } DoZoom(mx, my) int mx, my; { Window rW, cW; int rx, ry, ox, oy, nx, ny; unsigned int mask; ox = mx; oy = my; for (;;) { if (XQueryPointer(dpy, win, &rW, &cW, &rx, &ry, &nx, &ny, &mask)) { if (! (mask & Button1Mask)) break; /* button released */ if (nx < 0) nx = 0; if (nx >= width) nx = width1; if (ny < 0) ny = 0; if (ny >= height) ny = height1; if (nx != ox || ny != oy) { XSetFunction(dpy, gc, GXinvert); Rect(mx, my, ox, oy); Rect(mx, my, nx, ny); XSetFunction(dpy, gc, GXcopy); XFlush(dpy); ox = nx; oy = ny; } } } XSetFunction(dpy, gc, GXinvert); Rect(mx, my, ox, oy); XSetFunction(dpy, gc, GXcopy); if (mx == ox || my == oy || ! Push()) { XFlush(dpy); return; } if (mx > ox) { nx = mx; mx = ox; ox = nx; } if (my > oy) { nx = my; my = oy; oy = nx; } calc_zoom(mx, my, ox, oy); } ZoomIn() { int mx, my, ox, oy; mx = width >> 2; my = height >> 2; if (! mx || ! my || ! Push()) return; ox = 3 * mx; oy = 3 * my; calc_zoom(mx, my, ox, oy); } ZoomOut() { int mx, my, ox, oy; mx = width >> 2; my = height >> 2; if (! mx || ! my || ! Push()) return; ox = 5 * mx; oy = 5 * my; calc_zoom(-mx, -my, ox, oy); } DoPan(mx, my, B_Mask) int mx, my; unsigned B_Mask; { Window rW, cW; int rx, ry, ox, oy, nx, ny; unsigned int mask; #ifdef TEST char buf[32]; sprintf(buf, "X=%.2lf Y=%.2lf", xic(mx), yic(my)); #ifdef SUN5 XSetFunction(dpy, gc, GXclear); #else XSetFunction(dpy, gc, GXcopyInverted); #endif XFillRectangle(dpy, win, gc, 0, 0, textW, 10 * textH); XSetFunction(dpy, gc, GXcopy); XDrawString(dpy, win, gc, 0, textH, buf, strlen(buf)); #endif ox = mx; oy = my; for (;;) { if (XQueryPointer(dpy, win, &rW, &cW, &rx, &ry, &nx, &ny, &mask)) { if (! (mask & B_Mask)) break; /* button released */ /* Check Window Limits here */ if (nx != ox || ny != oy) { XSetFunction(dpy, gc, GXinvert); XDrawLine(dpy, win, gc, mx, my, ox, oy); XDrawLine(dpy, win, gc, mx, my, nx, ny); XSetFunction(dpy, gc, GXcopy); XFlush(dpy); ox = nx; oy = ny; } } } if (mx == ox && my == oy) return; if (! Push()) return; /* #define yic(iy) (yofs + (double)(iy) / scale) */ switch (fsact->turn) { case 0: mx -= ox; xofs = xic(mx); my -= oy; yofs = yic(my); break; case 90: my = oy - my; xofs = xic(my); mx -= ox; yofs = yic(mx); break; case 180: mx = ox - mx; xofs = xic(mx); my = oy - my; yofs = yic(my); break; case 270: my -= oy; xofs = xic(my); mx = ox - mx; yofs = yic(mx); break; } DrawWin(); XFlush(dpy); } DoInvert() { long swap = foreground; foreground = background; background = swap; XSetForeground(dpy, gc, foreground); XSetBackground(dpy, gc, background); XSetWindowBackground(dpy, win, background); DrawWin(); XFlush(dpy); } invert_menu(fun) int fun; { int y; y = (fun - 1) * textH; XSetFunction(dpy, gc, GXinvert); XFillRectangle(dpy, win, gc, 0, y, textW, textH); XSetFunction(dpy, gc, GXcopy); XFlush(dpy); } get_menu_func(nx, ny, ofun) int nx, ny; int ofun; { int nfun; if (nx < 0 || nx > textW) { if (ofun) invert_menu(ofun); return 0; } nfun = ny / textH; if (++nfun > max_menu) nfun = 0; if (nfun != ofun) { invert_menu(ofun); invert_menu(nfun); } return nfun; } new_image() { ZoomStack *old; if (zs != NULL) { old = zs; zs = zs->next; free(old); } close_image(v); v = open_image(fsact->imgfile, "./", 1507282L, 32767, fsact->extension); if (v == NULL) exit(1); xofs = yofs = 1.0; if (fsact->turn == 0 || fsact->turn == 180) { xp = (double)v->ImageWidth; yp = (double)v->ImageLength; } else { xp = (double)v->ImageLength; yp = (double)v->ImageWidth; } calc_scale((double)width, (double)height); if (reverse == fsact->reverse) { DrawWin(); XFlush(dpy); } else { reverse = fsact->reverse; DoInvert(); } } show_nxt() { if (mp_act == -1) { fsprv = fsact; fsact = fsnxt; fsnxt = fsact->next; } new_image(); } show_prv() { if (mp_act == -1) { fsnxt = fsprv; fsprv = NULL; fsact = fsroot; while (fsact != fsnxt) { fsprv = fsact; fsact = fsact->next; } fsnxt = fsact->next; } new_image(); } void FunZoom() { pfun = 0; } void FunPan() { pfun = 1; } DoMenu() { Window rW, cW; unsigned int mask; int rx, ry, nx, ny, nfunc = 0; int i, ty = textH; #ifdef SUN5 XSetFunction(dpy, gc, GXclear); #else XSetFunction(dpy, gc, GXcopyInverted); #endif XFillRectangle(dpy, win, gc, 0, 0, textW, 11 * textH); XSetFunction(dpy, gc, GXcopy); for (i = 0; i < 8; i++) { XDrawString(dpy, win, gc, 0, ty, m_str[i], strlen(m_str[i])); ty += textH; } max_menu = 9; if (mp_act == -1) { if (fsnxt != NULL) { XDrawString(dpy, win, gc, 0, ty, m_str[8], strlen(m_str[8])); ty += textH; max_menu++; } if (fsprv != NULL) { XDrawString(dpy, win, gc, 0, ty, m_str[9], strlen(m_str[9])); ty += textH; max_menu++; } } else { if (mp_act != mp_file) { XDrawString(dpy, win, gc, 0, ty, m_str[8], strlen(m_str[8])); ty += textH; max_menu++; } if (mp_act != 0) { XDrawString(dpy, win, gc, 0, ty, m_str[9], strlen(m_str[9])); ty += textH; max_menu++; } } XDrawString(dpy, win, gc, 0, ty, m_str[10], strlen(m_str[10])); #ifdef SUN5 XSetFunction(dpy, gc, GXcopy); #endif XFlush(dpy); for (;;) { if (XQueryPointer(dpy, win, &rW, &cW, &rx, &ry, &nx, &ny, &mask)) { if (! (mask & Button3Mask)) break; /* button released */ nfunc = get_menu_func(nx, ny, nfunc); } } switch (nfunc) { case 0: DrawWin(); XFlush(dpy); break; case 1: /* Zoom */ FunZoom(); break; case 2: /* Pan */ FunPan(); break; case 3: Pop(); return; case 4: ZoomIn(); return; case 5: ZoomOut(); return; case 6: ZoomAll(); return; case 7: DoTurn(); return; case 8: DoInvert(); return; case 9: if (mp_act == -1) { if (fsnxt != NULL) { show_nxt(); return; } else if (fsprv != NULL) { show_prv(); return; } else Quit(); } else { if (mp_act != mp_file) { mp_act++; show_nxt(); return; } else if (mp_act != 0) { mp_act--; show_prv(); return; } else Quit(); } case 10: if (mp_act == -1) { if (max_menu == nfunc) Quit(); if (fsprv != NULL) { show_prv(); return; } } else { if (max_menu == nfunc) Quit(); if (mp_act != 0) { mp_act--; show_prv(); return; } } case 11: Quit(); } } void ShowPrv() { if (mp_act == -1) { if (fsprv != NULL) show_prv(); } else if (mp_act != 0) { mp_act--; show_prv(); } } void ShowNxt() { if (mp_act == -1) { if (fsnxt != NULL) show_nxt(); } else if (mp_act != mp_file) { mp_act++; show_nxt(); } } check_events() { XEvent e; static int last_etype = 0; static int new_tm, last_tm = 0; XNextEvent(dpy, &e); last_etype = e.type; /* printf("Event=%d\n", e.type); */ switch (e.type) { case ButtonPress: { XButtonEvent *be = (XButtonEvent *)&e; if (be->window != win) break; switch (e.xbutton.button) { case 1: /* Zoom */ if (pfun) DoPan(be->x, be->y, Button1Mask); else DoZoom(be->x, be->y); break; case 2: /* Pan */ DoPan(be->x, be->y, Button2Mask); break; case 3: DoMenu(); break; } } /* esac */ break; case KeyPress: { XKeyEvent *key_event = (XKeyEvent *)&e; char buf[128]; KeySym ks; XComposeStatus status; XLookupString(key_event, buf, 128, &ks, &status); switch (*buf) { case '+': ZoomIn(); break; case '-': ZoomOut(); break; case 'A': case 'a': ZoomAll(); break; case 'D': case 'd': DoTurn(); break; case 'I': case 'i': DoInvert(); break; case 'M': case 'm': DoMenu(); break; case 'N': case 'n': ShowNxt(); break; case 'P': case 'p': pfun = 1; break; case 'Q': case 'q': Quit(); break; case 'R': case 'r': ShowPrv(); break; case 'V': case 'v': Pop(); break; case 'Z': case 'z': pfun = 0; break; } } break; case Expose: { XExposeEvent *exp_event = (XExposeEvent *)&e; XWindowAttributes win_attr; if (exp_event->window == win) { XGetWindowAttributes(dpy, win, &win_attr); if (last_etype == Expose) { /* handle X11 multiple Expose */ new_tm = time(NULL); if (new_tm == last_tm && width == win_attr.width && height == win_attr.height) break; last_tm = new_tm; } else last_tm = time(NULL); width = win_attr.width; width1 = width - 1; height = win_attr.height; height1 = height - 1; calc_scale((double)width, (double)height); DrawWin(); XFlush(dpy); } } break; } /* esac */ } Quit() { close_image(v); XFreeGC(dpy, gc); XDestroyWindow(dpy, win); XCloseDisplay(dpy); exit(0); }