2000 #include #include #include #include #include #include #include #include #include #include "imgview.h" VARS v; static void sighandler(int sig) { v.timeout++; } static void mycls(int dotitle, int doupdate) { static int first = 1; if (dotitle) settitle(WINNAME); cls(v.bgcolor); if (doupdate) { if (! first) update(0, 0, 0, 0); else first--; } } static void putimg(void) { int ulx, uly, lrx, lry; int src_x, src_y, dst_x, dst_y, w, h; static int first = 1; if (! v.curimg) goto noimg; ulx = v.img_x - v.curimg->width/2; uly = v.img_y - v.curimg->height/2; lrx = ulx + v.curimg->width - 1; lry = uly + v.curimg->height - 1; src_x = (ulx < 0 ? abs(ulx) : 0); src_y = (uly < 0 ? abs(uly) : 0); dst_x = (ulx < 0 ? 0 : ulx); dst_y = (uly < 0 ? 0 : uly); w = v.curimg->width - (ulx < 0 ? abs(ulx) : 0) - (lrx >= v.win_w ? lrx - (v.win_w - 1): 0); h = v.curimg->height - (uly < 0 ? abs(uly) : 0) - (lry >= v.win_h ? lry - (v.win_h - 1): 0); putximage(v.curimg, src_x, src_y, dst_x, dst_y, w, h); noimg: if (! first) update(0, 0, 0, 0); else first--; } static void zoomimg(void) { int w, h; void *dp1, *dp2; int x, y; int pad1 = 0, pad2 = 0; int subsmp = 0; if (! v.curimg) return; if (v.zimg) { rmximage(v.zimg); v.zimg = NULL; } 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; } v.zimg = mkximage(w, h); dp1 = v.img->data; dp2 = v.zimg->data; if (xv.depth == 16) { if ((v.img->width * 2) % 4) pad1++; if ((v.zimg->width * 2) % 4) pad2++; } if (v.zoom > 1.) { int i, j; for (y = 0; y < v.img->height; y++) { void *tp = dp1; for (i = 0; i < v.zoom; i++) { dp1 = tp; for (x = 0; x < v.img->width; x++) { if (xv.depth == 24) { for (j = 0; j < v.zoom; j++) *(((unsigned long *)dp2)++) = *((unsigned long *)dp1); ((unsigned long *)dp1)++; } else { for (j = 0; j < v.zoom; j++) *(((unsigned short *)dp2)++) = *((unsigned short *)dp1); ((unsigned short *)dp1)++; } } if (pad2) ((unsigned short *)dp2)++; } if (pad1) ((unsigned short *)dp1)++; } } else { for (y = 0; y < v.img->height; y += subsmp) { dp1 = v.img->data + y * v.img->bytes_per_line; for (x = 0; x < v.img->width; x += subsmp) { if (xv.depth == 24) *(((unsigned long *)dp2)++) = *((unsigned long *)dp1 + x); else *(((unsigned short *)dp2)++) = *((unsigned short *)dp1 + x); } if (pad2) ((unsigned short *)dp2)++; } } 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; } v.curimg = NULL; mycls(1, 1); 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); fprintf(stderr, "Unrecognized file format\n"); goto err; } } 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 = WIN_H; strcpy(v.bgcolor_s, BGCOLOR); strcpy(v.tbgcolor_s, TBGCOLOR); 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); } 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; mycls(0, 0); putimg(); } } break; case E 85f xpose: doexpose(&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); mycls(0, 0); putimg(); break; case XK_Right: v.img_x -= v.xymove * (ctrl ? 5 : 1); mycls(0, 0); putimg(); break; case XK_Up: v.img_y += v.xymove * (ctrl ? 5 : 1); mycls(0, 0); putimg(); break; case XK_Down: v.img_y -= v.xymove * (ctrl ? 5 : 1); mycls(0, 0); putimg(); break; case XK_Prior: v.zoom *= 2; mycls(0, 1); zoomimg(); break; case XK_Next: v.zoom /= 2; mycls(0, 1); 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; mycls(0, 1); zoomimg(); } else { mycls(0, 0); 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