#ifndef lint static const char RCSid[] = "$Id: vgaimage.c,v 2.11 2004/01/02 12:47:01 schorsch Exp $"; #endif /* * vgaimage.c - driver for VGA board under DOS */ #include #include "standard.h" #include #include "color.h" #include "random.h" #include "resolu.h" #include #include #define M_RDOWN 0x8 #define M_RUP 0x10 #define M_LDOWN 0x2 #define M_LUP 0x4 #define M_MOTION 0x1 int crad; int mouse_event = 0; int mouse_xpos = -1; int mouse_ypos = -1; #define hide_cursor() move_cursor(-1,-1) #define show_cursor() move_cursor(mouse_xpos,mouse_ypos) #define CTRL(c) ((c)-'@') #define MAXWIDTH 1024 #define MAXHEIGHT 768 short ourblack = 0; ourwhite = 1; double gamcor = 2.2; /* gamma correction */ int dither = 1; /* dither colors? */ int maxcolors = 0; /* maximum colors */ int minpix = 0; /* minimum pixel value */ int greyscale = 0; /* in grey */ int scale = 0; /* scalefactor; power of two */ COLR scanline[MAXWIDTH]; /* scan line buffer */ int xmax, ymax; /* picture dimensions */ FILE *fin = stdin; /* input file */ long scanpos[MAXHEIGHT]; /* scan line positions in file */ int cury = 0; /* current scan location */ double exposure = 1.0; /* exposure compensation used */ int wrongformat = 0; /* input in another format? */ struct { int xmin, ymin, xsiz, ysiz; } box = {0, 0, 0, 0}; /* current box */ int initialized = 0; int cheight, cwidth; #define postext(x,y) _settextposition(1+(y)/cheight,1+(x)/cwidth) char *progname; char errmsg[128]; extern BYTE clrtab[256][3]; /* global color map */ static gethfunc headline; main(argc, argv) int argc; char *argv[]; { extern char *getenv(), *fixargv0(); char *gv; int i; progname = argv[0] = fixargv0(argv[0]); if ((gv = getenv("DISPLAY_GAMMA")) != NULL) gamcor = atof(gv); for (i = 1; i < argc; i++) if (argv[i][0] == '-') switch (argv[i][1]) { case 'c': maxcolors = atoi(argv[++i]); break; case 'b': greyscale = !greyscale; break; case 'm': maxcolors = 2; break; case 'd': dither = !dither; break; case 'e': if (argv[i+1][0] != '+' && argv[i+1][0] != '-') goto userr; scale = atoi(argv[++i]); break; case 'g': gamcor = atof(argv[++i]); break; default: goto userr; } else break; if (i == argc-1) { /* open picture */ fin = fopen(argv[i], "r"); if (fin == NULL) { sprintf(errmsg, "cannot open file \"%s\"", argv[i]); quiterr(errmsg); } } else if (i != argc) goto userr; setmode(fileno(fin), O_BINARY); /* get header */ getheader(fin, headline, NULL); /* get picture dimensions */ if (wrongformat || fgetresolu(&xmax, &ymax, fin) < 0) quiterr("bad picture format"); if (xmax > MAXWIDTH | ymax > MAXHEIGHT) quiterr("input picture too large for VGA"); init(); /* initialize and display */ while (docommand()) /* loop on command */ ; quiterr(NULL); userr: fprintf(stderr, "Usage: %s [-b][-m][-d][-c ncolors][-e +/-stops] file\n", progname); exit(1); } static int headline( /* get relevant info from header */ char *s, void *p ) { char fmt[32]; if (isexpos(s)) exposure *= exposval(s); else if (isformat(s)) { formatval(fmt, s); wrongformat = strcmp(fmt, COLRFMT); } return(0); } init() /* initialize and load display */ { static struct { short mode; short xsiz, ysiz; } video[] = { {_MRES256COLOR, 320, 200}, {_VRES256COLOR, 640, 480}, {_SVRES256COLOR, 800, 600}, {_XRES256COLOR, 1024, 768}, {-1, 0, 0} }; struct videoconfig config; register int i; /* pick a card... */ for (i = 0; video[i].mode != -1; i++) if (video[i].xsiz >= xmax && video[i].ysiz >= ymax) break; if (video[i].mode == -1) quiterr("input picture too large"); if (_setvideomode(video[i].mode) == 0) quiterr("inadequate display card for picture"); ms_init(); initialized = 1; _getvideoconfig(&config); if (maxcolors == 0 | maxcolors > config.numcolors) maxcolors = config.numcolors-2; if (maxcolors <= config.numcolors-2) minpix = 2; else ourwhite = maxcolors-1; _settextcolor(ourwhite); cheight = config.numypixels/config.numtextrows; cwidth = config.numxpixels/config.numtextcols; /* clear scan position array */ for (i = 0; i < ymax; i++) scanpos[i] = -1; /* display image */ if (greyscale) greyimage(); else mappedimage(); } quiterr(err) /* print message and exit */ char *err; { if (initialized) { ms_done(); _setvideomode(_DEFAULTMODE); } if (err != NULL) { fprintf(stderr, "%s: %s\n", progname, err); exit(1); } exit(0); } int docommand() /* execute command */ { char buf[64]; COLOR cval; int com; double comp; while (!kbhit()) watch_mouse(); com = getch(); switch (com) { /* interpret command */ case 'q': case CTRL('Z'): /* quit */ return(0); case '\n': case '\r': case 'l': case 'c': /* value */ if (avgbox(cval) == -1) return(-1); switch (com) { case '\n': case '\r': /* radiance */ sprintf(buf, "%.3f", intens(cval)/exposure); break; case 'l': /* luminance */ sprintf(buf, "%.0fL", luminance(cval)/exposure); break; case 'c': /* color */ comp = pow(2.0, (double)scale); sprintf(buf, "(%.2f,%.2f,%.2f)", colval(cval,RED)*comp, colval(cval,GRN)*comp, colval(cval,BLU)*comp); break; } postext(box.xmin+box.xsiz/2, box.ymin+box.ysiz/2); hide_cursor(); _outtext(buf); show_cursor(); return(1); default: return(-1); } } watch_mouse() /* look after mousie */ { int a_x, a_y, l_x, l_y; if (mouse_event & M_MOTION) move_cursor(mouse_xpos, mouse_ypos); if (!(mouse_event & M_LDOWN)) return; l_x = a_x = mouse_xpos; l_y = a_y = mouse_ypos; hide_cursor(); revbox(a_x, a_y, l_x, l_y); /* show box */ do { mouse_event = 0; while (!mouse_event) ; if (mouse_event & M_MOTION) { revbox(a_x, a_y, l_x, l_y); revbox(a_x, a_y, l_x=mouse_xpos, l_y=mouse_ypos); } } while (!(mouse_event & M_LUP)); revbox(a_x, a_y, l_x, l_y); /* hide box */ show_cursor(); box.xmin = mouse_xpos; box.ymin = mouse_ypos; if (box.xmin > a_x) { box.xsiz = box.xmin - a_x + 1; box.xmin = a_x; } else { box.xsiz = a_x - box.xmin + 1; } if (box.ymin > a_y) { box.ysiz = box.ymin - a_y + 1; box.ymin = a_y; } else { box.ysiz = a_y - box.ymin + 1; } mouse_event = 0; } revbox(x0, y0, x1, y1) /* draw box with reversed lines */ int x0, y0, x1, y1; { _setplotaction(_GXOR); _setcolor(255); _moveto(x0, y0); _lineto(x1, y0); _lineto(x1, y1); _lineto(x0, y1); _lineto(x0, y0); } int avgbox(clr) /* average color over current box */ COLOR clr; { static COLOR lc; static int ll, lr, lt, lb; int left, right, top, bottom; int y; double d; COLOR ctmp; register int x; setcolor(clr, 0.0, 0.0, 0.0); left = box.xmin; right = left + box.xsiz; if (left < 0) left = 0; if (right > xmax) right = xmax; if (left >= right) return(-1); top = box.ymin; bottom = top + box.ysiz; if (top < 0) top = 0; if (bottom > ymax) bottom = ymax; if (top >= bottom) return(-1); if (left == ll && right == lr && top == lt && bottom == lb) { copycolor(clr, lc); return(0); } for (y = top; y < bottom; y++) { if (getscan(y) == -1) return(-1); for (x = left; x < right; x++) { colr_color(ctmp, scanline[x]); addcolor(clr, ctmp); } } d = 1.0/((right-left)*(bottom-top)); scalecolor(clr, d); ll = left; lr = right; lt = top; lb = bottom; copycolor(lc, clr); return(0); } setpalette() /* set our palette using clrtab */ { long cvals[256]; register int i; cvals[ourblack] = _BLACK; cvals[ourwhite] = _BRIGHTWHITE; for (i = 0; i < maxcolors; i++) cvals[i+minpix] = (long)clrtab[i][BLU]<<14 & 0x3f0000L | clrtab[i][GRN]<<6 & 0x3f00 | clrtab[i][RED]>>2; _remapallpalette(cvals); } greyimage() /* display greyscale image */ { short thiscolor, lastcolor = -1; int y; register int x; /* set gamma correction */ setcolrgam(gamcor); /* set up color map */ for (x = 0; x < maxcolors; x++) clrtab[x][RED] = clrtab[x][GRN] = clrtab[x][BLU] = ((long)x*256 + 128)/maxcolors; setpalette(); _setplotaction(_GPSET); /* read and display file */ for (y = 0; y < ymax; y++) { getscan(y); if (scale) shiftcolrs(scanline, xmax, scale); for (x = 0; x < xmax; x++) scanline[x][GRN] = normbright(scanline[x]); colrs_gambs(scanline, xmax); if (maxcolors < 256) for (x = 0; x < xmax; x++) { thiscolor = ((long)scanline[x][GRN] * maxcolors + maxcolors/2) / 256; if (thiscolor != lastcolor) _setcolor((lastcolor=thiscolor)+minpix); _setpixel(x, y); } else for (x = 0; x < xmax; x++) { thiscolor = scanline[x][GRN]; if (thiscolor != lastcolor) _setcolor((lastcolor=thiscolor)+minpix); _setpixel(x, y); } } } mappedimage() /* display color-mapped image */ { BYTE bscan[MAXWIDTH]; int y; register int x; /* set gamma correction */ setcolrgam(gamcor); /* make histogram */ _outtext("Quantizing image -- Please wait..."); new_histo(); for (y = 0; y < ymax; y++) { if (getscan(y) < 0) quiterr("seek error in getmapped"); if (scale) shiftcolrs(scanline, xmax, scale); colrs_gambs(scanline, xmax); cnt_colrs(scanline, xmax); } /* map pixels */ if (!new_clrtab(maxcolors)) quiterr("cannot create color map"); setpalette(); _setplotaction(_GPSET); /* display image */ for (y = 0; y < ymax; y++) { if (getscan(y) < 0) quiterr("seek error in getmapped"); if (scale) shiftcolrs(scanline, xmax, scale); colrs_gambs(scanline, xmax); if (dither) dith_colrs(bscan, scanline, xmax); else map_colrs(bscan, scanline, xmax); for (x = 0; x < xmax; x++) { if (x==0 || bscan[x] != bscan[x-1]) _setcolor(bscan[x]+minpix); _setpixel(x, y); } } } getscan(y) int y; { if (y != cury) { if (scanpos[y] == -1) return(-1); if (fseek(fin, scanpos[y], 0) == -1) quiterr("fseek error"); cury = y; } else if (fin != stdin && scanpos[y] == -1) scanpos[y] = ftell(fin); if (freadcolrs(scanline, xmax, fin) < 0) quiterr("picture read error"); cury++; return(0); } /* * Microsoft Mouse handling routines */ #pragma off (check_stack) void _loadds far mouse_handler (int max, int mcx, int mdx) { #pragma aux mouse_handler parm [EAX] [ECX] [EDX] mouse_event = max; mouse_xpos = mcx; mouse_ypos = mdx; } #pragma on (check_stack) void move_cursor(newx, newy) /* move cursor to new position */ int newx, newy; { static char *imp = NULL; static int curx = -1, cury = -1; #define xcmin (curx-crad<0 ? 0 : curx-crad) #define ycmin (cury-crad<0 ? 0 : cury-crad) #define xcmax (curx+crad>=xmax ? xmax-1 : curx+crad) #define ycmax (cury+crad>=ymax ? ymax-1 : cury+crad) if (newx == curx & newy == cury) return; if (imp == NULL && (imp = bmalloc(_imagesize(0,0,2*crad+1,2*crad+1))) == NULL) { quiterr("out of memory in move_cursor"); } if (curx >= 0 & cury >= 0) /* clear old cursor */ _putimage(xcmin, ycmin, imp, _GPSET); /* record new position */ curx = newx; cury = newy; if (curx < 0 | cury < 0) return; /* no cursor */ /* save under new cursor */ _getimage(xcmin, ycmin, xcmax, ycmax, imp); /* draw new cursor */ _setplotaction(_GPSET); _setcolor(ourwhite); _rectangle(_GFILLINTERIOR, xcmin, cury-1, xcmax, cury+1); _rectangle(_GFILLINTERIOR, curx-1, ycmin, curx+1, ycmax); _setcolor(ourblack); _moveto(xcmin+1, cury); _lineto(xcmax-1, cury); _moveto(curx, ycmin+1); _lineto(curx, ycmax-1); #undef xcmin #undef ycmin #undef xcmax #undef ycmax } int ms_init() { struct SREGS sregs; union REGS inregs, outregs; int far *ptr; int (far *function_ptr)(); segread(&sregs); /* check for mouse driver */ inregs.w.ax = 0; int386 (0x33, &inregs, &outregs); if( outregs.w.ax != -1 ) { return(0); } crad = ymax/40; /* set screen limits */ inregs.w.ax = 0x7; /* horizontal resolution */ inregs.w.cx = 0; inregs.w.dx = xmax-1; int386x( 0x33, &inregs, &outregs, &sregs ); inregs.w.ax = 0x8; /* vertical resolution */ inregs.w.cx = 0; inregs.w.dx = ymax-1; int386x( 0x33, &inregs, &outregs, &sregs ); /* install watcher */ inregs.w.ax = 0xC; inregs.w.cx = M_LDOWN | M_LUP | M_MOTION; function_ptr = mouse_handler; inregs.x.edx = FP_OFF( function_ptr ); sregs.es = FP_SEG( function_ptr ); int386x( 0x33, &inregs, &outregs, &sregs ); return(1); } ms_done() { union REGS inregs, outregs; /* uninstall watcher */ inregs.w.ax = 0; int386 (0x33, &inregs, &outregs); }