📄 viewfax.c
字号:
/* Program to view fax files on an X-window screen Copyright (C) 1990, 1995 Frank D. Cringle.This file is part of viewfax - g3/g4 fax processing software. viewfax is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 2 of the License, or (at youroption) any later version. This program is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details. You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <sys/time.h>/* NewImage() needs to fiddle with the Display structure */#define XLIB_ILLEGAL_ACCESS#include <X11/Xlib.h>#include <X11/Xutil.h>#include <X11/Xatom.h>#include <X11/keysym.h>#include <X11/keysymdef.h>#include <X11/cursorfont.h>#include "faxexpand.h"#define VERSION "2.4"/* If moving the image around with the middle mouse button is jerky or slow, try defining USE_MOTIONHINT. It may help (it may also make things worse - it depends on the server implementation) */#undef USE_MOTIONHINTstruct pagenode *firstpage, *lastpage, *thispage, *helppage;struct pagenode defaultpage;/* access the 'extra' field in a pagenode */#define Pimage(p) ((XImage *)(p)->extra)/* getopt declarations */extern int getopt();extern char *optarg;extern int optind, opterr, optopt;/* forward declarations */static XImage *FlipImage(XImage *xi);static XImage *MirrorImage(XImage *xi);static XImage *NewImage(int w, int h, char *data, int bit_order);static XImage *RotImage(XImage *Image);static XImage *ZoomImage(XImage *Big);static void FreeImage(XImage *Image);static int GetImage(struct pagenode *pn);static void SetupDisplay(int argc, char **argv);static void ShowLoop(void);static int release(int quit);static char *suffix(char *opt, const char *str);/* X variables */static char *DispName = NULL;static char *Geometry = NULL;static Display *Disp;static Window Root;static Window Win;static int Default_Screen;static GC PaintGC;static Cursor WorkCursor;static Cursor ReadyCursor;static Cursor MoveCursor;static Cursor LRCursor;static Cursor UDCursor;char *ProgName;int verbose = 0;static int abell = 0; /* audio bell */static int vbell = 1; /* visual bell */static int zfactor = 0; /* zoom factor */static size_t Memused = 0; /* image memory usage */static size_t Memlimit = 4*1024*1024; /* try not to exceed */#undef min#undef max#define min(a,b) ((a)<(b)?(a):(b))#define max(a,b) ((a)>(b)?(a):(b))#ifndef EXIT_FAILURE#define EXIT_FAILURE 1#endif/* OK, OK - this is a dreadful hack. But it adequately distinguishes modern big- and little- endian hosts. We only need this to set the byte order in XImage structures */static union { t32bits i; unsigned char b[4]; } bo;#define ByteOrder bo.b[3]static char Banner[] ="\nviewfax version " VERSION ", Copyright (C) 1990, 1995 Frank D. Cringle.\n""viewfax comes with ABSOLUTELY NO WARRANTY; for details see the\n""file \"COPYING\" in the distribution directory.\n\n";static char Usage[] ="usage: %s <flags> file ...\n""\t-f\tfine resolution (default unless filename begins with 'fn')\n""\t-n\tnormal resolution\n""\t-h\theight (number of fax lines)\n""\t-w\twidth (dots per fax line)\n""\t-l\tturn image 90 degrees (landscape mode)\n""\t-u\tturn image upside down\n""\t-i\tinvert (black/white)\n""\t-d\t(or -display) use an alternate X display\n""\t-g\t(or -geometry) size and position of window\n""\t-b\tuse audio (-ba) or visual (-bv) warning bell\n""\t-m\tmemory usage limit\n""\t-r\tfax data is packed ls-bit first in input bytes\n""\t-v\tverbose messages\n""\t-z\tinitial zoom factor\n""\t-2\traw files are g3-2d\n""\t-4\traw files are g4\n";intmain(int argc, char **argv){ int c; int err = 0; bo.i = 1; defaultpage.vres = -1; defaultpage.expander = g31expand; opterr = 0; /* suppress getopt error message */ if ((ProgName = strrchr(argv[0], '/')) == NULL) ProgName = argv[0]; else ProgName++; while ((c = getopt(argc, argv, "b:d:fg:h:ilm:nruvw:z:24")) != -1) switch(c) { case 'b': abell = vbell = 0; while (*optarg) { abell |= (*optarg == 'a'); vbell |= (*optarg == 'v'); optarg++; } break; case 'd': /* display name */ if (*(DispName = suffix(optarg, "isplay")) == 0) DispName = argv[optind++]; break; case 'f': /* fine resolution */ defaultpage.vres = 1; break; case 'g': /* geometry */ if (*(Geometry = suffix(optarg, "eometry")) == 0) Geometry = argv[optind++]; break; case 'h': /* user thinks this is the height */ defaultpage.height = atoi(optarg); break; case 'i': /* invert black/white */ defaultpage.inverse = 1; break; case 'l': /* landscape */ defaultpage.orient |= TURN_L; break; case 'm': /* memory usage limit */ Memlimit = atoi(optarg); switch(optarg[strlen(optarg)-1]) { case 'M': case 'm': Memlimit *= 1024; case 'K': case 'k': Memlimit *= 1024; } break; case 'n': /* normal resolution */ defaultpage.vres = 0; break; case 'r': /* reverse input bits */ defaultpage.lsbfirst = 1; break; case 'u': /* upside down */ defaultpage.orient |= TURN_U; break; case 'v': /* verbose messages */ verbose = 1; break; case 'w': /* user thinks this is the width */ defaultpage.width = atoi(optarg); break; case 'z': /* zoom factor */ c = atoi(optarg); if (c <= 0) c = 1; for (zfactor = 1; c > 1; c >>= 1) zfactor <<= 1; /* constrain to a power of 2 */ break; case '2': defaultpage.expander = g32expand; break; case '4': defaultpage.expander = g4expand; break; default: err++; break; } if (defaultpage.expander == g4expand && defaultpage.height == 0) { fputs("-h value is required to interpret raw g4 faxes\n", stderr); err++; } if (verbose) fputs(Banner, stdout); firstpage = lastpage = thispage = helppage = NULL; for (; optind < argc; optind++) (void) notetiff(argv[optind]); if (err || firstpage == NULL) { if (!verbose) fprintf(stderr, Banner); fprintf(stderr, Usage, ProgName); exit(EXIT_FAILURE); } if ((Disp = XOpenDisplay(DispName)) == NULL) { fprintf(stderr, "%s: can't open display %s\n", ProgName, DispName ? DispName : XDisplayName((char *) NULL)); exit(EXIT_FAILURE); } Default_Screen = XDefaultScreen(Disp); faxinit(); thispage = firstpage; while (!GetImage(firstpage)) /* try again */; SetupDisplay(argc, argv); ShowLoop(); return 0;}/* return mismatching suffix of option name */static char *suffix(char *opt, const char *prefix){ while (*opt && *opt == *prefix) { opt++; prefix++; } return opt;}/* Change orientation of all following pages */static voidTurnFollowing(int How, struct pagenode *pn){ while (pn) { if (Pimage(pn)) { FreeImage(Pimage(pn)); pn->extra = NULL; } pn->orient ^= How; pn = pn->next; }}static voiddrawline(pixnum *run, int LineNum, struct pagenode *pn){ t32bits *p, *p1; /* p - current line, p1 - low-res duplicate */ pixnum *r; /* pointer to run-lengths */ t32bits pix; /* current pixel value */ t32bits acc; /* pixel accumulator */ int nacc; /* number of valid bits in acc */ int tot; /* total pixels in line */ int n; LineNum += pn->stripnum * pn->rowsperstrip; p = (t32bits *) (Pimage(pn)->data + LineNum*(2-pn->vres)*Pimage(pn)->bytes_per_line); p1 = pn->vres ? NULL : p + Pimage(pn)->bytes_per_line/sizeof(*p); r = run; acc = 0; nacc = 0; pix = pn->inverse ? ~0 : 0; tot = 0; while (tot < pn->width) { n = *r++; tot += n; if (pix) acc |= (~(t32bits)0 >> nacc); else if (nacc) acc &= (~(t32bits)0 << (32 - nacc)); else acc = 0; if (nacc + n < 32) { nacc += n; pix = ~pix; continue; } *p++ = acc; if (p1) *p1++ = acc; n -= 32 - nacc; while (n >= 32) { n -= 32; *p++ = pix; if (p1) *p1++ = pix; } acc = pix; nacc = n; pix = ~pix; } if (nacc) { *p++ = acc; if (p1) *p1++ = acc; }}static intGetPartImage(struct pagenode *pn, int n){ unsigned char *Data = getstrip(pn, n); if (Data == NULL) return 0; pn->stripnum = n; (*pn->expander)(pn, drawline); free(Data); return 1;}static intGetImage(struct pagenode *pn){ int i; if (pn->strips == NULL) { /* raw file; maybe we don't have the height yet */ unsigned char *Data = getstrip(pn, 0); if (Data == NULL) return 0; pn->extra = NewImage(pn->width, pn->vres ? pn->height : 2*pn->height, NULL, 1); (*pn->expander)(pn, drawline); } else { /* multi-strip tiff */ pn->extra = NewImage(pn->width, pn->vres ? pn->height : 2*pn->height, NULL, 1); pn->stripnum = 0; for (i = 0; i < pn->nstrips; i++) { if (verbose) printf("\texpanding strip #%d\n", i); if (GetPartImage(pn, i) == 0) { FreeImage(Pimage(pn)); return 0; } } } if (pn->orient & TURN_U) pn->extra = FlipImage(Pimage(pn)); if (pn->orient & TURN_M) pn->extra = MirrorImage(Pimage(pn)); if (pn->orient & TURN_L) pn->extra = RotImage(Pimage(pn)); if (verbose) printf("\tmemused = %d\n", Memused); return 1;}#ifndef _HAVE_USLEEPstatic intusleep(unsigned usecs){ struct timeval t; t.tv_sec = usecs/10000000; t.tv_usec = usecs%1000000; (void) select(1, NULL, NULL, NULL, &t); return 0;}#endif#ifndef REAL_ROOT/* Function Name: GetVRoot * Description: Gets the root window, even if it's a virtual root * Arguments: the display and the screen * Returns: the root window for the client * * by David Elliott, taken from the x-faq */static WindowGetVRoot(Display *dpy, int scr){ Window rootReturn, parentReturn, *children; unsigned int numChildren; Window root = RootWindow(dpy, scr); Atom __SWM_VROOT = None; int i; __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False); XQueryTree(dpy, root, &rootReturn, &parentReturn, &children, &numChildren); for (i = 0; i < numChildren; i++) { Atom actual_type; int actual_format; unsigned long nitems, bytesafter; Window *newRoot = NULL; if (XGetWindowProperty(dpy, children[i], __SWM_VROOT, 0, 1, False, XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter, (unsigned char **) &newRoot) == Success && newRoot) { if (children) XFree(children); return *newRoot; } } return root;}#endifstatic Atom wm_delete_window;/* Area the user would like us to use, derived from -geometry */static struct { int v, x, y; unsigned int w, h;} Area = {0, 0, 0};/* nominal border width */#define BW 4/* Figure out the zoom factor needed to fit the fax on the available display */static voidSetupDisplay(int argc, char **argv){ int Width, Height, i; XSetWindowAttributes Attr; XSizeHints size_hints; Atom wm_protocols; int faxh = Pimage(thispage)->height; int faxw = Pimage(thispage)->width;#ifdef REAL_ROOT Root = RootWindow(Disp, Default_Screen); Width = Area.w = DisplayWidth(Disp, Default_Screen); Height = Area.h = DisplayHeight(Disp, Default_Screen);#elif TVTWM_BIGWINDOW XWindowAttributes RootWA; Root = GetVRoot(Disp, Default_Screen); XGetWindowAttributes(Disp, Root, &RootWA); Width = Area.w = RootWA.width; Height = Area.h = RootWA.height;#else Root = GetVRoot(Disp, Default_Screen); Width = Area.w = DisplayWidth(Disp, Default_Screen);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -