2000 #include #include #include #include #include #include #include #include #include #include #include "imgview.h" #include "reader/common.h" VARS v; static void sighandler(int sig) { v.timeout++; } static void mycls(void) { if (! v.curimg) { settitle(WINNAME); XFillRectangle(xv.d, xv.w, xv.gc, 0, 0, v.win_w, v.win_h); XSync(xv.d, False); return; } if (v.ulx > 0 && v.ulx > v.oulx) XFillRectangle(xv.d, xv.w, xv.gc, v.oulx, 0, v.ulx - v.oulx, v.win_h); if (v.uly > 0 && v.uly > v.ouly) XFillRectangle(xv.d, xv.w, xv.gc, 0, v.ouly, v.win_w, v.uly - v.ouly); if (v.lrx < (v.win_w - 1) && v.lrx < v.olrx) XFillRectangle(xv.d, xv.w, xv.gc, v.lrx + 1, 0, v.olrx - v.lrx, v.win_h); if (v.lry < (v.win_h - 1) && v.lry < v.olry) XFillRectangle(xv.d, xv.w, xv.gc, 0, v.lry + 1, v.win_w, v.olry - v.lry); } static void putimg(void) { static int first = 1; if (! v.curimg) { if (first) first--; return; } v.ulx = v.img_x - v.curimg->width/2; v.uly = v.img_y - v.curimg->height/2; v.lrx = v.ulx + v.curimg->width - 1; v.lry = v.uly + v.curimg->height - 1; if (! xv.pmap) { GC putgc; xv.pmap = mkpixmap(v.curimg->width, v.curimg->height, v.curimg->depth); if (v.curimg->depth == 1) { static GC mgc = NULL; if (! mgc) mgc = XCreateGC(xv.d, xv.pmap, 0, NULL); if (v.black == 1) { XSetBackground(xv.d, mgc, 0); XSetForeground(xv.d, mgc, 1); } else { XSetBackground(xv.d, mgc, 1); XSetForeground(xv.d, mgc, 0); } putgc = mgc; } else putgc = xv.gc; XPutImage(xv.d, xv.pmap, putgc, v.curimg, 0, 0, 0, 0, v.curimg->width, v.curimg->height); } if (! first) { mycls(); if (v.curimg->depth == 1) XCopyPlane(xv.d, xv.pmap, xv.w, v.monogc, 0, 0, v.curimg->width, v.curimg->height, v.ulx, v.uly, 1); else XCopyArea(xv.d, xv.pmap, xv.w, xv.gc, 0, 0, v.curimg->width, v.curimg->height, v.ulx, v.uly); } else first--; v.oulx = v.ulx; v.ouly = v.uly; v.olrx = v.lrx; v.olry = v.lry; } static void zoomimg(void) { int w, h; unsigned char *dp1, *dp2; unsigned short **sdpp1 = (unsigned short **)&dp1, **sdpp2 = (unsigned short **)&dp2; unsigned long **ldpp1 = (unsigned long **)&dp1, **ldpp2 = (unsigned long **)&dp2; int x, y, y2, sbit, sbit2, dbit; int pad; int subsmp = 0; if (v.zimg) { rmximage(v.zimg); v.zimg = NULL; } if (xv.pmap) { rmpixmap(xv.pmap); xv.pmap = 0; } if (v.zoom == 1.) { v.curimg = v.img; putimg(); return; } if (v.zoom > 1.) { w = v.img->width * v.zoom; h = v.img->height * v.zoom; } else { subsmp = 1 / v.zoom; w = (v.img->width + subsmp - 1) / subsmp; h = (v.img->height + subsmp - 1) / subsmp; } pad = 0; v.zimg = mkximage(w, h, v.img->depth, &pad); if (v.img->depth == 1) memset(v.zimg->data, 0, v.zimg->bytes_per_line * h); dp1 = v.img->data; dp2 = v.zimg->data; if (v.zoom > 1.) { int i, j; for (y = 0; y < v.img->height; y++) { unsigned char *tp = dp1; for (i = 0; i < v.zoom; i++) { dp1 = tp; if (v.img->depth == 24) { for (x = 0; x < v.img->width; x++) { for (j = 0; j < v.zoom; j++) *(*ldpp2)++ = *(*ldpp1); (*ldpp1)++; } } else if (v.img->depth == 16) { for (x = 0; x < v.img->width; x++) { for (j = 0; j < v.zoom; j++) *(*sdpp2)++ = *(*sdpp1); (*sdpp1)++; } } else { for (x = 0, sbit = dbit = 7; x < v.img->width; x++, sbit--) { if (sbit < 0) { dp1++; sbit = 7; } sbit2 = (*dp1 >> sbit) & 1; for (j = 0; j < v.zoom; j++, dbit--) { if (dbit < 0) { dp2++; dbit = 7; } *dp2 |= sbit2 << dbit; } } dp1++; dp2++; } if (pad) dp2 += pad; } if (v.pad) dp1 += v.pad; } } else { for (y = 0, y2 = 0; y < v.img->height; y += subsmp, y2++) { dp1 = v.img->data + y * v.img->bytes_per_line; if (v.img->depth == 24) { for (x = 0; x < v.img->width; x += subsmp) *(*ldpp2)++ = *(*ldpp1 + x); } else if (v.img->depth == 16) { for (x = 0; x < v.img->width; x += subsmp) *(*sdpp2)++ = *(*sdpp1 + x); } else { for (x = 0, sbit = dbit = 7; x < v.img->width; x += subsmp, sbit -= subsmp, dbit--) { if (sbit < 0) { dp1 += (abs(sbit) + 7) / 8; sbit = 7; } if (dbit < 0) { dp2++; dbit = 7; } *dp2 |= ((*dp1 >> sbit) & 1) << dbit; } dp2++; } if (pad) dp2 += pad; } } v.curimg = v.zimg; putimg(); } static int getfmt(int fd) { unsigned char magic[4]; if (read(fd, magic, 4) < 4) return -1; lseek(fd, 0, SEEK_SET); if (magic[0] == 'P' && (magic[1] >= '1' && magic[1] <= '6')) return FMT_PPM; else if (*(unsigned int *)magic == 0x38464947) return FMT_GIF; else if (*(unsigned short *)magic == 0xd8ff) return FMT_JPEG; else if (*(unsigned int *)magic == 0x2a004d4d || *(unsigned int *)magic == 0x002a4949) return FMT_TIFF; else if (*(unsigned int *)magic == 0x474e5089) return FMT_PNG; else if (magic[0] == 0x0a) return FMT_PCX; else if (magic[2] >= 1 && magic[2] <= 8) return FMT_JBIG; else return -1; } static void readfile(char *fname) { char *tail = NULL, tmp[512]; char *tmpname = NULL; if (v.img) { rmximage(v.img); v.img = NULL; } if (v.zimg) { rmximage(v.zimg); v.zimg = NULL; } if (xv.pmap) { rmpixmap(xv.pmap); xv.pmap = 0; } v.curimg = NULL; v.black = 1; v.white = 0; mycls(); if (fname) { int fd; if ((tail = strrchr(fname, '/'))) tail++; else tail = fname; if (! strncmp(fname, "http://", 7)) { int r; tmpname = (char *)malloc(128); sprintf(tmpname, "%s/.imgview.XXXXXX", getenv("HOME")); if ((fd = mkstemp(tmpname)) < 0) { perror("mkstemp"); goto err; } else close(fd); sprintf(tmp, "wget -q -O %s %s", tmpname, fname); if ((r = system(tmp))) { if (r < 0) perror("system"); else fprintf(stderr, "wget failed with exit status %d\n", WEXITSTATUS(r)); goto err; } if ((fd = open(tmpname, O_RDONLY)) < 0) { perror("open"); goto err; } } else { if ((fd = open(fname, O_RDONLY)) < 0) { perror("open"); goto err; } } switch (getfmt(fd)) { case FMT_PPM: v.img = readppm(fd); break; case FMT_GIF: v.img = readgif(fd); break; case FMT_JPEG: v.img = readjpeg(fd); break; case FMT_TIFF: v.img = readtiff(fd, fname); break; case FMT_PNG: v.img = readpng(fd); break; case FMT_PCX: v.img = readpcx(fd); break; case FMT_JBIG: v.img = readjbig(fd); break; default: close(fd); v.img = readxbm(fname); break; } } else v.img = readppm(0); if (! v.img) goto err; if (fname) { sprintf(tmp, "%s - %s [%dx%d]", WINNAME, tail, v.img->width, v.img->height); } else { sprintf(tmp, "%s - stdin [%dx%d]", WINNAME, v.img->width, v.img->height); } settitle(tmp); v.curimg = v.img; v.img_x = v.win_w/2; v.img_y = v.win_h/2; if (v.keepzoom) zoomimg(); else { v.zoom = 1.0; putimg(); } if (tmpname) { unlink(tmpname); free(tmpname); } return; err: if (fname) sprintf(tmp, "%s - %s [ERROR]", WINNAME, tail); else sprintf(tmp, "%s - stdin [ERROR]", WINNAME); settitle(tmp); putimg(); if (fname) fprintf(stderr, "%s: Error while reading `%s'\n", APPNAME, tail); else fprintf(stderr, "%s: Error while reading stdin\n", APPNAME); if (tmpname) { unlink(tmpname); free(tmpname); } } static void usage(void) { fprintf(stderr, "usage: iv [-s] [-v] [file ...]\n"); exit(1); } static void init(int argc, char **argv) { int c, s_flag = 0; char rcname[512]; FILE *f; v.win_x = WIN_X; v.win_y = WIN_Y; v.win_w = WIN_W; v.win_h 1203 = WIN_H; strcpy(v.bgcolor_s, BGCOLOR); strcpy(v.tbgcolor_s, TBGCOLOR); strcpy(v.bwbgcolor_s, BWBGCOLOR); strcpy(v.bwfgcolor_s, BWFGCOLOR); v.xymove = XYMOVE; v.delay = DELAY; v.jbigw = JBIGW; v.jbigh = JBIGH; v.zoom = 1.0; v.keepzoom = v.slide = v.timeout = 0; v.verbose = 0; while ((c = getopt(argc, argv, ":sv")) != -1) { switch (c) { case 's': s_flag++; break; case 'v': v.verbose++; break; case '?': case ':': default: usage(); } } if ((argc - optind) && s_flag) { signal(SIGALRM, sighandler); v.slide++; } atexit(writeconfig); sprintf(rcname, "%s/.imgviewrc", getenv("HOME")); if ((f = fopen(rcname, "r"))) readconfig(f); xinit(APPNAME, CLASSNAME, WINNAME, v.win_x, v.win_y, v.win_w, v.win_h, 1, v.bgcolor_s, v.bgcolor_s, 0); v.win_w = xv.width; v.win_h = xv.height; v.bgcolor = getnamedcolor(v.bgcolor_s, &v.bgcolor_rgb); v.tbgcolor = getnamedcolor(v.tbgcolor_s, &v.tbgcolor_rgb); v.bwbgcolor = getnamedcolor(v.bwbgcolor_s, NULL); v.bwfgcolor = getnamedcolor(v.bwfgcolor_s, NULL); XSetForeground(xv.d, xv.gc, v.bgcolor); v.monogc = XCreateGC(xv.d, xv.w, 0, NULL); XSetBackground(xv.d, v.monogc, v.bwbgcolor); XSetForeground(xv.d, v.monogc, v.bwfgcolor); } int main(int argc, char **argv) { struct timeval t; int fnum; init(argc, argv); fnum = optind; readfile(argc - fnum ? argv[fnum] : NULL); if (v.slide) alarm(v.delay); for (;;) { XEvent e; if (v.slide && v.timeout) { if (++fnum == argc) exit(0); readfile(argv[fnum]); v.timeout = 0; alarm(v.delay); } while (getevent(&e)) { static int shift = 0, ctrl = 0; int k; switch (e.type) { case ConfigureNotify: { v.win_x = xv.x; v.win_y = xv.y; if (xv.width != v.win_w || xv.height != v.win_h) { v.win_w = xv.width; v.win_h = xv.height; v.img_x = v.win_w/2; v.img_y = v.win_h/2; putimg(); } } break; case Expose: if (v.curimg) { for (;;) { XExposeEvent *ee = (XExposeEvent *)&e; if (v.curimg->depth == 1) XCopyPlane(xv.d, xv.pmap, xv.w, v.monogc, ee->x - v.ulx, ee->y - v.uly, ee->width, ee->height, ee->x, ee->y, 1); else XCopyArea(xv.d, xv.pmap, xv.w, xv.gc, ee->x - v.ulx, ee->y - v.uly, ee->width, ee->height, ee->x, ee->y); if (! ee->count) break; XNextEvent(xv.d, &e); } } break; case KeyPress: k = XLookupKeysym((XKeyEvent *)&e, 0); switch (k) { case XK_Shift_L: case XK_Shift_R: shift++; break; case XK_Control_L: case XK_Control_R: ctrl++; break; case XK_Left: v.img_x += v.xymove * (ctrl ? 5 : 1); putimg(); break; case XK_Right: v.img_x -= v.xymove * (ctrl ? 5 : 1); putimg(); break; case XK_Up: v.img_y += v.xymove * (ctrl ? 5 : 1); putimg(); break; case XK_Down: v.img_y -= v.xymove * (ctrl ? 5 : 1); putimg(); break; case XK_Prior: v.zoom *= 2; zoomimg(); break; case XK_Next: v.zoom /= 2; zoomimg(); break; case XK_Home: v.img_x = v.win_w/2; v.img_y = v.win_h/2; if (ctrl) { v.zoom = 1.0; zoomimg(); } else { putimg(); } break; case XK_p: if (argc > 1) { int ofnum = fnum; fnum = (shift ? 1 : (fnum > 1 ? fnum - 1 : fnum)); if (fnum != ofnum) { readfile(argv[fnum]); if (v.slide) gettimeofday(&t, NULL); } } break; case XK_n: if (argc > 1) { int ofnum = fnum; fnum = (shift ? argc - 1 : (fnum < argc - 1 ? fnum + 1 : fnum)); if (fnum != ofnum) { readfile(argv[fnum]); if (v.slide) gettimeofday(&t, NULL); } } break; case XK_z: v.keepzoom ^= 1; break; case XK_q: exit(0); } if (v.slide && k != XK_Shift_L && k != XK_Shift_R && k != XK_Control_L && k != XK_Control_R) { v.timeout = 0; alarm(v.delay); } break; case KeyRelease: switch (XLookupKeysym((XKeyEvent *)&e, 0)) { case XK_Shift_L: case XK_Shift_R: shift--; break; case XK_Control_L: case XK_Control_R: ctrl--; break; } break; } } usleep(1000); } } . 0