/* this version uses flicker */ #define V_HIST /* def for vertical histogram */ #undef DBL_LOOP /* def for for(x..., for(y... loops */ #undef FULL_SCREEN /* def to write entire screen, not just wxh */ /* * mgif - floyd-steinberg dither (mono) a gif image (.gif) * * gif decoder lifted from PBMplus package. flicker adopted from * work by Klaus Pedersen (micro@imada.dk) * * history: * * 90/12/16 1.0 rosenkra - initial release (posted to c.s.atari.st) * * 91/1/7 1.1 rosenkra - change -i to -r * - change -q to -i * - started to add -q (quantize), not complete * - fix bug with zero'ed accumulation arrays * which was being done with every call to * rasterize * - add histogram for each rgb value (eliminate * the "intensity order" histogram, too) * - make UseNTSC global * - fix scan_CM (bug in gemlib read) * - make default -s of 40 * - histogram now impacted by -N (NTSC) * - add -f option * 91/2/25 1.2 rosenkra - add -b option * - -i does not print color map. use -i -i * 91/6/3 3.0 rosenkra - major rewrite using "flicker" * - really interactive only now * - ReadGIF now single entry point * - flicker is single entry point * - does lots of image processing (menu) * including size, blur, brighten, log scale, * contrast expansion, median filter * 91/6/3 3.2 rosenkra - add convolutions * - release to usenet * 91/6/6 3.3 rosenkra - add cut, rotate, mirror * - add flicker file write (*.fl) * 91/6/9 3.4 rosenkra - fix some bugs in file write, median, log * scale, etc * - enlarge/shrink by direction * - cut can work beyond screen size * - add support for .pi1 and .pi2 files * 91/6/13 3.5 rosenkra - point coord selection by crosshairs * - add zoom (2x) * - add histogram on screen in flicker screen * - add copy orig<-->new */ static char *sccsid = "@(#) mgif.c 3.5 91/6/18 rosenkra\0\0 "; char *myname = "mgif\0\0\0\0\0\0"; char *version = "mgif 3.5 91/6/18 rosenkra\0\0\0 "; #include #include #include "mgif.h" #define SCRNSPACE 48256L /* buffer size for 3 screens (words) */ /* leave extra to word-align */ /* * globals: */ uchar_t CodedGIF[MAXRAW];/* raw LZW coded raster after unblock*/ uchar_t ColMap[MAPSIZ][3];/* color map we use (global or local)*/ screen_t ScrnInf; /* global screen descriptor */ image_t Id; /* image id struct */ uchar_t Raster[MAXIMG]; /* final raster image, ColMap indx */ uchar_t TransRast[MAXIMG];/* transformed raster image */ int Height, /* image size */ Width; int NewHeight, /* transformed image size */ NewWidth; int ShowFl = 0; int montage = 0; int Pi1 = 0; /* use this on degas files also */ int Pi2 = 0; int Batch = 0; int Noise = 0; /* percentage of random noise */ int Beta = 0; /* beta factor for Laplace filter */ int Verbose = 0; /* this is VERY verbose... */ int Inquire = 0; /* inquire or render */ int Quantize = 0; /* quantize to 16 shades */ int UseNTSC = 0; /* NTSC equation for lumin */ long Hist[HISTSIZ]; /* histogram */ int XUpperLeft = 0, /* starting pixel (default is 0,0) */ YUpperLeft = 0; int *PScreens; /* what flicker returns. ptr to 3 screens */ /* * local functions */ int usage (); int draw_image (); int cmaptoint (); int showfl (); void title (); void conv_menu (); void do_help (); /* * external functions */ extern long atol (); /* from libc */ extern int ReadGIF (); /* from readgif.c */ extern int ReadPI1 (); /* from readpi.c */ extern int ReadPI2 (); extern int *flicker (); /* from flicker.c */ extern long linea0 (); /* from linea.s */ extern int linea3 (); extern int larger (); /* from process.c */ extern int zoom (); extern int smaller (); extern int cut (); extern int rotate (); extern int mirror (); extern int convolve (); extern int blur (); extern int median (); extern int piksrt (); extern int logscale (); extern int Log2 (); extern int contrast (); extern int brighten (); extern int invert (); extern int threshold (); extern int histeq (); extern int redistribute (); extern int copyrast (); extern int do_hist (); /* from low.c */ extern int draw_hist (); extern int drhhist (); extern int drvhist (); extern int grid (); extern int do_line (); extern void xor_line (); extern void xor_dash (); extern int cursor (); extern int clr_cmd (); extern int mv_cursor (); extern int clr_screen (); extern long do_time (); extern int check_key (); extern int get_key (); extern int get_string (); extern long get_rkey (); extern int get_xypos (); extern int wait_key (); extern int wait_ms (); extern int write_fl (); /* from file.c */ extern int read_fl (); /*------------------------------*/ /* main */ /*------------------------------*/ main (argc, argv) int argc; char *argv[]; { long elapsed; /* elapsed seconds */ int gif_fd; /* file descriptor */ char *ps; char *fname; int ret; register long ii; register int *pscrn; int count; int *scrn; /* -> first screen for -fl */ /* * set defaults... */ Batch = 0; /* * parse args... */ for (argc--, argv++; (argc && **argv == '-'); argc--, argv++) { switch (*(*argv+1)) { case 'f': /* just show flicker files */ if (!strncmp (*argv, "-fl", 3)) ShowFl++; else usage (1); break; case 'm': /* with -fl, do montage */ montage++; break; case 'p': if (!strncmp (*argv, "-pi1", 4)) Pi1++; else if (!strncmp (*argv, "-pi2", 4)) Pi2++; else usage (1); break; case 'b': /* batch mode (no questions)*/ Batch = 1; /* NOT IMPLEMENTED!!! */ break; case 'N': /* NTSC lum equation */ UseNTSC = 1; break; case 'i': /* inquire only */ Inquire++; break; case 'v': /* version/verbose output */ if (!strncmp (*argv, "-vers", 5)) { printf ("%s\n", version); exit (0); } Verbose++; break; case 'h': /* help */ if (!strncmp (*argv, "-help", 5)) { usage (0); } break; default: usage (1); break; } } /* * make sure we have at least one file... */ if (argc < 1) usage (1); /* * just show flicker files and exit... */ if (ShowFl) { /* * align to page boundary. use Raster as our screen buf */ scrn = (int *) (((long) Raster + 256L) & 0xFFFFFF00L); if (montage) { /* * for either 2 320x400, 4 320x200 images or * 6 200x200 images. first read them. note * changing ptr into screen buffers... */ pscrn = scrn; count = 0; while (argc--) { /* * read a file */ printf ("Reading file: %s\n", *argv); if (!read_fl (*argv, pscrn, &Width, &Height)) { fprintf (stderr, "%s: read_fl failed for %s\n", myname, *argv); exit (1); } /* * based on screen size of this image, * change pointer to screen, get ready * to read the next... */ count++; argv++; if ((Width <= 320) && (Width > 200) && (Height <= 400) && (Height > 200)) { /* * 2 320x400 images... */ if (count == 1) pscrn = (int *) ((long) scrn + 40L); else break; } else if ((Width <= 320) && (Width > 200) && (Height <= 200)) { /* * 4 320x200 images... */ if (count == 1) pscrn = (int *) ((long) scrn + 40L); else if (count == 2) pscrn = (int *) ((long) scrn + 16000L); else if (count == 3) pscrn = (int *) ((long) scrn + 16040L); else break; } else if ((Width <= 200) && (Height <= 200)) { /* * 6 200x200 images... */ if (count == 1) pscrn = (int *) ((long) scrn + 25L); else if (count == 2) pscrn = (int *) ((long) scrn + 50L); else if (count == 3) pscrn = (int *) ((long) scrn + 16000L); else if (count == 4) pscrn = (int *) ((long) scrn + 16025L); else if (count == 5) pscrn = (int *) ((long) scrn + 16050L); else break; } else /* * just display this one */ break; } /* * show them all... */ showfl (scrn); } else { /* * loop on files */ while (argc--) { /* * read file. if ok, display... */ printf ("Reading file: %s\n", *argv); if (read_fl (*argv, scrn, &Width, &Height)) showfl (scrn); else { fprintf (stderr, "%s: read_fl failed for %s\n", myname, *argv); exit (1); } /* * clear screen buffer for next image if there * is one... */ if (argc) { pscrn = scrn; for (ii = 0L; ii < SCRNSPACE; ii++) *pscrn++ = 0; argv++; } } } exit (0); } /* * instructions (col, row)... */ do_time (0); if (!Inquire) { /* * initialize things (clear screen, turn off cursor, init * timing) */ title (Batch); } /* * loop on remaining files... */ while (argc--) { /* * fresh screen... */ if (!Inquire) clr_screen (); /* * get file to open */ fname = *argv++; /* * read image */ if (Pi1) { /* * read PI1 */ do_time (1); if (Verbose) ret = ReadPI1 (fname, Raster, ColMap, VERBOSE); else if (Inquire) ret = ReadPI1 (fname, Raster, ColMap, INQUIRE); else ret = ReadPI1 (fname, Raster, ColMap, NORMAL); elapsed = do_time (2); Width = 320; Height = 200; } else if (Pi2) { /* * read PI2. Will need to be resized after this * for correct aspect ration (either shrink horiz * or enlarge vert, but let user decide...) */ #if 0 fprintf (stderr, "%s: can't do PI2 files (yet)\n", myname); goto next; #endif printf ("\nAfter PI2 is read, you will have to shrink horiz or expand vert...\n\n"); do_time (1); if (Verbose) ret = ReadPI2 (fname, Raster, ColMap, VERBOSE); else if (Inquire) ret = ReadPI2 (fname, Raster, ColMap, INQUIRE); else ret = ReadPI2 (fname, Raster, ColMap, NORMAL); elapsed = do_time (2); Width = 640; Height = 200; } else { /* * read GIF (this assumes only 1 image per file, a * reasonable assumption)... */ do_time (1); if (Verbose) ret = ReadGIF (fname, CodedGIF, Raster, &ScrnInf, &Id, ColMap, VERBOSE); else if (Inquire) ret = ReadGIF (fname, CodedGIF, Raster, &ScrnInf, &Id, ColMap, INQUIRE); else ret = ReadGIF (fname, CodedGIF, Raster, &ScrnInf, &Id, ColMap, NORMAL); elapsed = do_time (2); Width = Id.i_dx; Height = Id.i_dy; } /* * draw if read was ok, else error and go to next file */ switch (ret) { case EGIFOK: printf ("\nElapsed time: %4ld sec\n", elapsed); if (!Inquire) draw_image (fname); break; case EGIFFILE: fprintf (stderr, "%s: could not open %s\n", myname, fname); goto next; case EGIFMAGIC: if (Pi1) fprintf (stderr, "%s: %s not a PI1 file\n", myname, fname); else fprintf (stderr, "%s: %s not a GIF87a file\n", myname, fname); goto next; case EGIFSDESC: fprintf (stderr, "%s: file %s data format error in screen descriptor\n", myname, fname); goto next; case EGIFEOF: fprintf (stderr, "%s: unexpected EOF\n", myname); goto next; case EGIFIDBAD: fprintf (stderr, "%s: bad image ID\n", myname); goto next; case EGIFBIG: fprintf (stderr, "this GIF too large for memory\n\n"); goto next; case EGIFRAST: fprintf (stderr, "%s: error reading raster image\n", myname); goto next; } next: } /* * clean up and exit */ cursor (1); exit (0); } /*------------------------------*/ /* usage */ /*------------------------------*/ usage (excode) int excode; { fprintf (stderr, "%s -fl [-m] file.fl ...\n", myname); fprintf (stderr, "-m montage of flicker files\n"); fprintf (stderr, "file.fl a .fl flicker file\n"); fprintf (stderr, "\nor:\n\n"); fprintf (stderr, "%s [-i] [-v] [-N] [-pi1] [-pi2] file ...\n", myname); fprintf (stderr, "-i inquire about image only\n"); fprintf (stderr, "-v verbose\n"); /* fprintf (stderr, "-b batch mode (no questions asked)\n");*/ fprintf (stderr, "-N use NTSC equation for luminescence\n"); fprintf (stderr, "-pi1 read Degas .pi1 file instead \n"); fprintf (stderr, "-pi2 read Degas .pi2 file instead \n"); fprintf (stderr, "file a .gif (or .pi1 or .pi2) file\n"); fprintf (stderr, "\n"); fprintf (stderr, "If more than one file, all share command switch settings.\n"); fprintf (stderr, "Note that flicker file format is still subject to change.\n"); fprintf (stderr, "All flicker files created now, however, will be ok for the future.\n"); cursor (1); exit (excode); } /*------------------------------*/ /* draw_image */ /*------------------------------*/ int draw_image (fname) char *fname; { int i; int key; int orig; int ret; char buf[256]; long ii; int lo, hi; int brite; int thresh; long cthresh; int conv; int convkern[20]; int x1, y1, x2, y2; int xstart, ystart; int angle; int opt; char *flname; long elapsed; /* elapsed seconds */ /* * convert to grayscale */ printf ("\nConvert to grayscale\n"); do_time (1); cmaptoint (Raster, Width, Height, ColMap, UseNTSC); elapsed = do_time (2); printf ("\nElapsed time: %4ld sec\n", elapsed); /* * copy image to transform array */ do_time (1); printf ("\nCopy to transform array\n"); copyrast (Raster, Width, Height, TransRast); elapsed = do_time (2); printf ("\nElapsed time: %4ld sec\n", elapsed); /* * display flicker image. flicker returns after 2 keys. flicker * returns ptr to the 3 screens, page aligned, as (int *). this * address should not change so we only need assign PScreens once. */ clr_screen (); PScreens = flicker (Raster, Width, Height, Beta, Noise, 1); /* * look for commands. redisplay image as required from TransRast. * orig set 0 so successive transforms will be on new image. 'o' * option toggles this so each transform will be done on orig image. */ orig = 0; NewWidth = Width; NewHeight = Height; while (1) { /* * get a command. they can be: * * commands * ? help * q quit (next image) * ESC exit program now * space draw image * hi histogram * o original image (otherwise transform new) * f file operations * cp copy new <-> orig * options * n noise * g Laplace filter (need beta) * frame processes * e enlarge * s shrink * cu cut * r rotate * mi mirror * point processes * he histogram equalization * i inverse (negation) * l log scaling * t threshold (black/white) * co contrast expansion (need new range) * br brighten * area processes * bl blur (3x3) * me median filter (3x3) * v convolution (3x3) */ clr_cmd (); mv_cursor (0, 24); /*printf (" Command, new(?,q,ESC,SPC,hi,o,f,cp,n,g,e,s,cu,r,mi,he,i,l,t,co,br,bl,me,v): ");*/ if (orig) printf (" Command for original image (use ? for help): "); else printf (" Command for new image (use ? for help): "); key = get_key (); if ((key > 31) && (key < 128)) printf ("%c", (char) key); switch (key) { case '?': /* help */ do_help (); break; case 0x1b: /* ESC, exit program */ clr_cmd (); mv_cursor (0, 24); printf (" Are you sure you want to exit? (y/n): "); key = get_key (); printf ("%c", (char) key); if ((key == 'y') || (key == 'Y')) { printf ("\n Program exit\n"); cursor (1); exit (0); } break; case 'Q': /* quit (next image) */ case 'q': goto endloop; break; case 'W': /* what */ case 'w': info (fname); break; case 'F': /* file operations */ case 'f': /* * write a .fl file */ clr_cmd (); mv_cursor (0, 24); printf (" Filename to write (*.FL): "); get_string (83, buf); flname = (char *) buf; clr_cmd (); mv_cursor (0, 24); printf (" Write file %s now...", flname); if (PScreens) { if (orig) { if (write_fl (flname, PScreens, Width, Height)) { mv_cursor (0, 24); printf (" Wrote .FL file %s (%dx%d). Any key...", flname, Width, Height); wait_key (); } else { mv_cursor (0, 24); printf (" Error writing .FL file %s. Any key...", flname); wait_key (); } } else { if (write_fl (flname, PScreens, NewWidth, NewHeight)) { mv_cursor (0, 24); printf (" Wrote .FL file %s (%dx%d). Any key...", flname, NewWidth, NewHeight); wait_key (); } else { mv_cursor (0, 24); printf (" Error writing .FL file %s. Any key...", flname); wait_key (); } } } else { mv_cursor (0, 24); printf (" PScreens NULL! Any key..."); wait_key (); } break; case 'H': /* histogram */ case 'h': key = get_key (); printf ("%c", (char) key); switch (key) { case 'I': /* histogram */ case 'i': clr_cmd (); mv_cursor (0, 24); printf (" Generating histogram..."); if (orig) { if (do_hist (Raster, Width, Height, Hist)) { clr_screen (); draw_hist (Hist); } else { clr_cmd (); mv_cursor (0, 24); printf (" Histogram failed. Enter any key... "); wait_key (); } } else { if (do_hist (TransRast, NewWidth, NewHeight, Hist)) { clr_screen (); draw_hist (Hist); } else { clr_cmd (); mv_cursor (0, 24); printf (" Histogram failed. Enter any key... "); wait_key (); } } break; case 'E': /* hist equal */ case 'e': clr_cmd (); mv_cursor (0, 24); printf (" Histogram equalization now..."); if (orig) { if (histeq (Raster, Width, Height, Hist, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Histogram equalization failed. Enter any key... "); wait_key (); } } else { if (histeq (TransRast, NewWidth, NewHeight, Hist, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Histogram equalization failed. Enter any key... "); wait_key (); } } break; default: clr_cmd (); mv_cursor (0, 24); printf (" Unknown command. Type ? for help. Enter any key... "); wait_key (); break; } break; case 'Z': /* zoom (2x) */ case 'z': clr_screen (); if (orig) { clr_screen (); flicker (Raster, Width, Height, Beta, Noise, 0); grid (0, 0, Width, Height, 20); } else { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 0); grid (0, 0, NewWidth, NewHeight, 20); } /* * get zoom rectangle. it is currently ALWAYS * half the width and height of the current image. * the resulting zoom will ALWAYS be the same * size as the original image (well ALMOST, since * odd dims rounded down first)... */ if (orig) { xstart = Width/4; if ((xstart % 20) == 0) xstart -= 2; ystart = Height/4; if ((ystart % 20) == 0) ystart -= 2; ret = get_xypos (VH_COORD, 1, 0, 0, Width, Height, Width/2, Height/2, xstart, ystart, &x1, &y1); if (ret == 0) { clr_cmd (); mv_cursor (0, 24); printf (" Canceled or failed. Any key... "); wait_key (); break; } } else { xstart = NewWidth/4; if ((xstart % 20) == 0) xstart -= 2; ystart = NewHeight/4; if ((ystart % 20) == 0) ystart -= 2; ret = get_xypos (VH_COORD, 1, 0, 0, NewWidth, NewHeight, NewWidth/2, NewHeight/2, xstart, ystart, &x1, &y1); if (ret == 0) { clr_cmd (); mv_cursor (0, 24); printf (" Canceled or failed. Any key... "); wait_key (); break; } } clr_cmd (); mv_cursor (0, 24); printf (" Zooming image now (%d,%d)...", x1,y1); if (orig) ret = zoom (Raster, Width, Height, x1, y1, TransRast); else ret = zoom (TransRast, NewWidth, NewHeight, x1, y1, TransRast); /* * if zoom was successful, show the new image. */ if (ret) { if (orig) { /* order of * and / IS important! */ NewWidth = 2 * (Width / 2); NewHeight = 2 * (Height / 2); } else { NewWidth = 2 * (NewWidth / 2); NewHeight = 2 * (NewHeight / 2); } clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Zoom failed. Enter any key... "); wait_key (); } break; case 'E': /* enlarge (2x) */ case 'e': e_again: clr_cmd (); mv_cursor (0, 24); printf (" Enlarge dimension (0=both,1=horizontal,2=vertical): "); get_string (32, buf); opt = atoi (buf); if ((opt < 0) || (opt > 2)) goto e_again; clr_cmd (); mv_cursor (0, 24); printf (" Enlarging image now..."); if (orig) ret = larger (Raster, Width, Height, opt, TransRast); else ret = larger (TransRast, NewWidth, NewHeight, opt, TransRast); if (ret) { if (orig) { switch (opt) { case 0: /* both */ NewWidth = 2 * Width; NewHeight = 2 * Height; break; case 1: /* horiz */ NewWidth = 2 * Width; NewHeight = Height; break; case 2: /* vert */ NewWidth = Width; NewHeight = 2 * Height; break; } } else { switch (opt) { case 0: NewWidth = 2 * NewWidth; NewHeight = 2 * NewHeight; break; case 1: NewWidth = 2 * NewWidth; NewHeight = NewHeight; break; case 2: NewWidth = NewWidth; NewHeight = 2 * NewHeight; break; } } clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Enlarged image too large. Enter any key... "); wait_key (); } break; case 'S': /* shrink (.5x) */ case 's': s_again: clr_cmd (); mv_cursor (0, 24); printf (" Shrink dimension (0=both,1=horizontal,2=vertical): "); get_string (32, buf); opt = atoi (buf); if ((opt < 0) || (opt > 2)) goto s_again; clr_cmd (); mv_cursor (0, 24); printf (" Reducing image now..."); if (orig) ret = smaller (Raster, Width, Height, opt, TransRast); else ret = smaller (TransRast, NewWidth, NewHeight, opt, TransRast); if (ret) { if (orig) { switch (opt) { case 0: /* both */ NewWidth = Width / 2; NewHeight = Height / 2; break; case 1: /* horiz */ NewWidth = Width / 2; NewHeight = Height; break; case 2: /* vert */ NewWidth = Width; NewHeight = Height / 2; break; } } else { switch (opt) { case 0: NewWidth = NewWidth / 2; NewHeight = NewHeight / 2; break; case 1: NewWidth = NewWidth / 2; NewHeight = NewHeight; break; case 2: NewWidth = NewWidth; NewHeight = NewHeight / 2; break; } } clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Reduced image too small. Enter any key... "); wait_key (); } break; case 'R': /* rotate */ case 'r': if (!orig) { clr_cmd (); mv_cursor (0, 24); printf (" Can only rotate original image Any new image will be lost. Proceed (y/n)? "); key = get_key (); printf ("%c", (char) key); if ((key != 'y') && (key != 'Y')) break; } clr_cmd (); mv_cursor (0, 24); printf (" Enter angle (90=CCW,-90=CW,180): "); get_string (32, buf); angle = atoi (buf); if ((angle != 90) && (angle != -90) && (angle != 180) && (angle != -180)) { clr_cmd (); mv_cursor (0, 24); printf (" Sorry. Bad or unsupported angle. Enter any key... "); wait_key (); break; } clr_cmd (); mv_cursor (0, 24); printf (" Forcing orig mode. After rotate, force new mode. Rotate image now..."); if (rotate (Raster, Width, Height, angle, TransRast)) { if ((angle == 90) || (angle == -90)) { NewWidth = Height; NewHeight = Width; } else if ((angle == 180) || (angle == -180)) { NewWidth = Width; NewHeight = Height; } else { clr_cmd (); mv_cursor (0, 24); printf (" Sorry. Bad or unsupported angle. Enter any key... "); wait_key (); break; } clr_cmd (); mv_cursor (0, 24); printf ("Copy to new to orig image..."); copyrast (TransRast, NewWidth, NewHeight, Raster); Width = NewWidth; Height = NewHeight; clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); orig = 0; } else { clr_cmd (); mv_cursor (0, 24); printf (" Rotation failed. Could be bad angle. Mode unchanged. Enter any key... "); wait_key (); } break; case 'T': /* threshold */ case 't': clr_cmd (); mv_cursor (0, 24); printf (" Enter threshold (0 to 255): "); get_string (32, buf); thresh = atoi (buf); clr_cmd (); mv_cursor (0, 24); printf (" Thresholding image now..."); if (orig) { if (threshold (Raster, Width, Height, thresh, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Threshold failed. Enter any key... "); wait_key (); } } else { if (threshold (TransRast, NewWidth, NewHeight, thresh, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Threshold failed. Enter any key... "); wait_key (); } } break; case 'I': /* inverse (negation) */ case 'i': clr_cmd (); mv_cursor (0, 24); printf (" Enter threshold (0 to 255): "); get_string (32, buf); thresh = atoi (buf); clr_cmd (); mv_cursor (0, 24); printf (" Invert (negate) image now..."); if (orig) { if (invert (Raster, Width, Height, thresh, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Inversion failed. Enter any key... "); wait_key (); } } else { if (invert (TransRast, NewWidth, NewHeight, thresh, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Inversion failed. Enter any key... "); wait_key (); } } break; case 'L': /* log scaling */ case 'l': clr_cmd (); mv_cursor (0, 24); printf (" Log scaling image now..."); if (orig) { if (logscale (Raster, Width, Height, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Log scaling failed. Enter any key... "); wait_key (); } } else { if (logscale (TransRast, NewWidth, NewHeight, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Log scaling failed. Enter any key... "); wait_key (); } } break; case 'C': /* cut/contrast expansion */ case 'c': key = get_key (); printf ("%c", (char) key); switch (key) { case 'P': /* copy */ case 'p': clr_cmd (); mv_cursor (0, 24); printf ("Enter copy direction (0=orig->new, 1=new->orig): "); get_string (32, buf); opt = atoi (buf); switch (opt) { case 0: /* orig->new */ clr_cmd (); mv_cursor (0, 24); printf ("Copy to orig to new image..."); copyrast (Raster, Width, Height, TransRast); NewWidth = Width; NewHeight = Height; break; case 1: /* new->orig */ clr_cmd (); mv_cursor (0, 24); printf ("Copy to new to orig image..."); copyrast (TransRast, NewWidth, NewHeight, Raster); Width = NewWidth; Height = NewHeight; break; default: clr_cmd (); mv_cursor (0, 24); printf (" Copy failed. Enter any key... "); wait_key (); break; } break; case 'U': /* cut */ case 'u': clr_screen (); if (orig) { clr_screen (); flicker (Raster, Width, Height, Beta, Noise, 0); grid (0, 0, Width, Height, 20); } else { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 0); grid (0, 0, NewWidth, NewHeight, 20); } #if 0 clr_cmd (); mv_cursor (0, 24); printf (" Enter x1 (upper left coord, 0-%d): ", (orig ? Width-1 : NewWidth-1)); get_string (32, buf); x1 = atoi (buf); clr_cmd (); mv_cursor (0, 24); printf (" Enter y1 (upper left coord, 0-%d): ", (orig ? Height-1 : NewHeight-1)); get_string (32, buf); y1 = atoi (buf); clr_cmd (); mv_cursor (0, 24); printf (" Enter x2 (lower right coord, %d-%d): ", x1+1, (orig ? Width-1 : NewWidth-1)); get_string (32, buf); x2 = atoi (buf); clr_cmd (); mv_cursor (0, 24); printf (" Enter y2 (lower right coord, %d-%d): ", y1+1, (orig ? Height-1 : NewHeight-1)); get_string (32, buf); y2 = atoi (buf); #endif if (orig) { xstart = Width/2; if ((xstart % 20) == 0) xstart -= 5; ystart = Height/2; if ((ystart % 20) == 0) ystart -= 5; ret = get_xypos (VH_COORD, 0, 0, 0, Width, Height, 0, 0, xstart, ystart, &x1, &y1); if (ret == 0) { clr_cmd (); mv_cursor (0, 24); printf (" Canceled or failed. Any key... "); wait_key (); break; } xstart = x1+1+(Width-x1-1)/2; if ((xstart % 20) == 0) xstart += 1; xstart = y1+1+(Height-y1-1)/2; if ((ystart % 20) == 0) ystart += 1; ret = get_xypos (VH_COORD, 0, x1+1, y1+1, Width-x1-1, Height-y1-1, 0, 0, xstart, ystart, &x2, &y2); if (ret == 0) { clr_cmd (); mv_cursor (0, 24); printf (" Canceled or failed. Any key... "); wait_key (); break; } } else { xstart = NewWidth/2; if ((xstart % 20) == 0) xstart -= 5; ystart = NewHeight/2; if ((ystart % 20) == 0) ystart -= 5; ret = get_xypos (VH_COORD, 0, 0, 0, NewWidth, NewHeight, 0, 0, xstart, ystart, &x1, &y1); if (ret == 0) { clr_cmd (); mv_cursor (0, 24); printf (" Canceled or failed. Any key... "); wait_key (); break; } xstart = x1+1+(NewWidth-x1-1)/2; if ((xstart % 20) == 0) xstart += 1; xstart = y1+1+(NewHeight-y1-1)/2; if ((ystart % 20) == 0) ystart += 1; ret = get_xypos (VH_COORD, 0, x1+1, y1+1, NewWidth-x1-1, NewHeight-y1-1, 0, 0, xstart, ystart, &x2, &y2); if (ret == 0) { clr_cmd (); mv_cursor (0, 24); printf (" Canceled or failed. Any key... "); wait_key (); break; } } clr_cmd (); mv_cursor (0, 24); printf (" Cutting image now ((%d,%d) to (%d,%d)...", x1,y1, x2,y2); if (orig) ret = cut (Raster, Width, Height, x1, y1, x2, y2, TransRast); else ret = cut (TransRast, NewWidth, NewHeight, x1, y1, x2, y2, TransRast); if (ret) { NewWidth = x2 - x1 + 1; NewHeight = y2 - y1 + 1; clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Cut image failed. Enter any key... "); wait_key (); } break; case 'O': /* contrast expansion */ case 'o': #if 0 clr_cmd (); mv_cursor (0, 24); printf (" Enter lo range (0-255): "); get_string (32, buf); lo = atoi (buf); clr_cmd (); mv_cursor (0, 24); printf (" lo=%d. Enter hi range (0-255, larger than lo): ", lo); get_string (32, buf); hi = atoi (buf); #endif clr_cmd (); mv_cursor (0, 24); printf (" Enter threshold (pixel count): "); get_string (32, buf); cthresh = atol (buf); clr_cmd (); mv_cursor (0, 24); printf (" Contrast expanding image now..."); if (orig) { if (contrast (Raster, Width, Height, cthresh, Hist, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Contrast expansion failed. Enter any key... "); wait_key (); } } else { if (contrast (TransRast, NewWidth, NewHeight, cthresh, Hist, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Contrast expansion failed. Enter any key... "); wait_key (); } } break; default: clr_cmd (); mv_cursor (0, 24); printf (" Unknown command. Type ? for help. Enter any key... "); wait_key (); break; } break; case 'B': /* blur or brighten */ case 'b': key = get_key (); printf ("%c", (char) key); switch (key) { case 'L': /* blur */ case 'l': clr_cmd (); mv_cursor (0, 24); printf (" Blurring image now..."); if (orig) { if (blur (Raster, Width, Height, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Blurring failed. Enter any key... "); wait_key (); } } else { if (blur (TransRast, NewWidth, NewHeight, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Blurring failed. Enter any key... "); wait_key (); } } break; case 'R': /* brighten */ case 'r': clr_cmd (); mv_cursor (0, 24); printf (" Enter brightening value (-255 to 255): "); get_string (32, buf); brite = atoi (buf); clr_cmd (); mv_cursor (0, 24); printf (" Brightening image now..."); if (orig) { if (brighten (Raster, Width, Height, brite, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Brightening failed. Enter any key... "); wait_key (); } } else { if (brighten (TransRast, NewWidth, NewHeight, brite, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Brightening failed. Enter any key... "); wait_key (); } } break; default: clr_cmd (); mv_cursor (0, 24); printf (" Unknown command. Type ? for help. Enter any key... "); wait_key (); break; } break; case 'M': /* mirror/median filter */ case 'm': key = get_key (); printf ("%c", (char) key); switch (key) { case 'I': /* mirror */ case 'i': clr_cmd (); mv_cursor (0, 24); printf (" Enter mirror direction (0=vertical, 1=horizontal): "); get_string (32, buf); opt = atoi (buf); clr_cmd (); mv_cursor (0, 24); printf (" Mirror image now..."); if (orig) { if (mirror (Raster, Width, Height, opt, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Mirror failed. Enter any key... "); wait_key (); } } else { if (mirror (TransRast, NewWidth, NewHeight, opt, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Mirror failed. Enter any key... "); wait_key (); } } break; case 'E': case 'e': /* median filter */ clr_cmd (); mv_cursor (0, 24); printf (" Median filter image now..."); if (orig) { if (median (Raster, Width, Height, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Median filter failed. Enter any key... "); wait_key (); } } else { if (median (TransRast, NewWidth, NewHeight, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Median filter failed. Enter any key... "); wait_key (); } } break; default: clr_cmd (); mv_cursor (0, 24); printf (" Unknown command. Type ? for help. Enter any key... "); wait_key (); break; } break; case 'N': /* add noise */ case 'n': clr_cmd (); mv_cursor (0, 24); printf (" Enter noise percentage (0-100): "); get_string (32, buf); Noise = atoi (buf); break; case 'G': /* Laplace filter */ case 'g': clr_cmd (); mv_cursor (0, 24); printf (" Enter beta (0,1,2,3,4,...): "); get_string (32, buf); Beta = atoi (buf); break; case 'V': /* convolutions */ case 'v': conv_menu (1); clr_cmd (); mv_cursor (0, 24); printf (" Enter your choice: "); get_string (32, buf); conv = atoi (buf); if (conv == USER_KERN) { conv_menu (2); for (i = 0; i < 9; i++) { clr_cmd (); mv_cursor (0, 24); printf (" Enter k%d (neg or pos integer): ", i); get_string (32, buf); convkern[i] = atoi (buf); } clr_cmd (); mv_cursor (0, 24); printf (" Scaling (if multiplier->1, divisor->-1, no scaling-> 0): "); get_string (32, buf); convkern[9] = atoi (buf); if (convkern[9] > 0) { clr_cmd (); mv_cursor (0, 24); printf (" Multiplier (neg or pos integer): "); get_string (32, buf); convkern[10] = atoi (buf); } else if (convkern[9] < 0) { v_again: clr_cmd (); mv_cursor (0, 24); printf (" Divisor (neg or pos integer, NOT 0!!!): "); get_string (32, buf); convkern[10] = atoi (buf); if (convkern[10] == 0) goto v_again; } else convkern[10] = 1; } clr_cmd (); mv_cursor (0, 24); printf (" Convolve image now..."); if (orig) { if (convolve (Raster, Width, Height, conv, convkern, TransRast)) { clr_screen (); flicker (TransRast, Width, Height, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Convolution failed. Enter any key... "); wait_key (); } } else { if (convolve (TransRast, NewWidth, NewHeight, conv, convkern, TransRast)) { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } else { clr_cmd (); mv_cursor (0, 24); printf (" Convolution failed. Enter any key... "); wait_key (); } } break; case 'O': /* orig/transform toggle */ case 'o': clr_cmd (); mv_cursor (0, 24); if (orig) { orig = 0; Beta = 0; Noise = 0; printf (" Transforms on new image. Beta,Noise reset. Enter any key... "); wait_key (); } else { orig = 1; Beta = 0; Noise = 0; printf (" Transforms on original image. Beta,Noise reset. Enter any key... "); wait_key (); /* printf ("Copying original to transform array...");*/ /* copyrast (Raster, Width, Height, TransRast);*/ } break; case ' ': if (orig) { clr_screen (); flicker (Raster, Width, Height, Beta, Noise, 1); } else { clr_screen (); flicker (TransRast, NewWidth, NewHeight, Beta, Noise, 1); } break; default: clr_cmd (); mv_cursor (0, 24); printf (" Unknown command. Type ? for help. Enter any key... "); wait_key (); break; } } endloop: if (check_key ()) exit (1); return (!0); } /*------------------------------*/ /* cmaptoint */ /*------------------------------*/ cmaptoint (pras, w, h, map, useNTSC) uchar_t *pras; int w; int h; uchar_t map[MAPSIZ][3]; int useNTSC; { /* * convert image (in place) from colormap index to intensity. input * contains pointer into a colormap. output will contain intensity * either simple average or using NTSC formula. values will lie * between 0 and 255, inclusive. array should be declared unsigned * char. */ register uchar_t *pr; register uchar_t *pmap; register long rpl; register long gpl; register long bpl; register uint_t c; register long val; long ii; long lim; lim = (long) w * (long) h; pr = pras; pmap = &(map[0][0]); for (ii = 0L; ii < lim; ii++) { c = (uint_t) (*pr); #if 0 rpl = (ulong_t) (map[c][0]); gpl = (ulong_t) (map[c][1]); bpl = (ulong_t) (map[c][2]); #else rpl = (ulong_t) (pmap[(3*c) ]); gpl = (ulong_t) (pmap[(3*c) + 1]); bpl = (ulong_t) (pmap[(3*c) + 2]); #endif if (useNTSC) val = ((rpl*30L) + (gpl*59L) + (bpl*11L)) / 100L; else val = (rpl + gpl + bpl) / 3L; if (val > 255) val = 255; if (val < 0) val = 0; *pr++ = (uchar_t) val; } } /*------------------------------*/ /* showfl */ /*------------------------------*/ int showfl (s0) int *s0; { /* * show a flicker image already in memory. for 640x400 ONLY!!! * returns char read to stop the display as low byte of int. */ register long ii; register char *ps1; register char *ps2; char *old1; char *old2; int *s1, *s2, *s3; long ret; /* * remember old screen */ old1 = Logbase (); old2 = Physbase (); /* * clear these (phys and logical) */ ps1 = old1; ps2 = old2; for (ii = 0L; ii < 32000L; ii++) { *ps1++ = 0; *ps2++ = 0; } /* * set phys screen to first screen */ Setscreen (old2, s0, -1); /* * set pointers */ s1 = (int *) Physbase (); s2 = (int *) ((long) s1 + 32000L); s3 = (int *) ((long) s2 + 32000L); /* * display until a key is pressed */ do { Setscreen (old2, s1, -1); Vsync (); Setscreen (old2, s2, -1); Vsync (); Setscreen (old2, s3, -1); Vsync (); } while (!Bconstat (2)); /* * get the key... */ ret = Bconin (2) & 0x000000ffL; /* * reset screen */ Setscreen (old1, old2, -1); /* * clear keypresses */ while (Bconstat (2)) Bconin (2); /* * done. */ return ((int) ret); } /*------------------------------*/ /* title */ /*------------------------------*/ void title (b) int b; { clr_screen (); cursor (0); if (!b) { mv_cursor (10, 10); printf ("%s", version); mv_cursor (10, 12); printf ("GIF file is first read then displayed. Mode initially set"); mv_cursor (10, 13); printf ("to apply successive transforms to image. Use \"o\" to apply"); mv_cursor (10, 14); printf ("transforms independently to original image. Pick options"); mv_cursor (10, 15); printf ("from menu at prompt. Use \"?\" to get help. If you plan to"); mv_cursor (10, 16); printf ("rotate an image, it is probably best to do that first."); mv_cursor (10, 18); printf ("Press any key to continue..."); wait_key (); /* wait for a keypress... */ } } /*------------------------------*/ /* conv_menu */ /*------------------------------*/ void conv_menu (opt) int opt; { if (opt == 1) { clr_screen (); mv_cursor (0, 0); printf (" Built-in Convolution Kernels:\n"); printf ("\n"); printf (" ------------ Low Pass Filter -------------- ----- High Pass Filter -----\n"); printf (" 1/9 1/9 1/9 1/10 1/10 1/10 1/16 2/16 1/16 -1 -1 -1 0 -1 0 1 -2 1\n"); printf (" 1/9 1/9 1/9 1/10 2/10 1/10 2/16 4/16 2/16 -1 9 -1 -1 5 -1 -2 5 -2\n"); printf (" 1/9 1/9 1/9 1/10 1/10 1/10 1/16 2/16 1/16 -1 -1 -1 0 -1 0 1 -2 1\n"); printf (" [1] [2] [3] [4] [5] [6]\n"); printf (" -- Shift and Difference Edge --\n"); printf (" Vertical Horizontal Hor and Ver ------------- Laplace Edge -------------\n"); printf (" 0 0 0 0 -1 0 -1 0 0 0 1 0 -1 -1 -1 -1 -1 -1 1 -2 1\n"); printf (" -1 1 0 0 1 0 0 1 0 1 -4 1 -1 8 -1 -1 9 -1 -2 4 -2\n"); printf (" 0 0 0 0 0 0 0 0 0 0 1 0 -1 -1 -1 -1 -1 -1 1 -2 1\n"); printf (" [7] [8] [9] [10] [11] [12] [13]\n"); printf (" ------------------------ Gradient Directional Edge -----------------------\n"); printf (" North Northeast East Southeast South Southwest West\n"); printf (" 1 1 1 1 1 1 -1 1 1 -1 -1 1 -1 -1 -1 1 -1 -1 1 1 -1\n"); printf (" 1 -2 1 -1 -2 1 -1 -2 1 -1 -2 1 1 -2 1 1 -2 -1 1 -2 -1\n"); printf (" -1 -1 -1 -1 -1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1\n"); printf (" [14] [15] [16] [17] [18] [19] [20]\n"); printf (" Northwest\n"); printf (" 1 1 1\n"); printf (" 1 -2 -1 Choose a filter (numbers in \"[]\" below kernels).\n"); printf (" 1 -1 -1 For user-defined, enter 0. You will be prompted for values.\n"); printf (" [21]\n"); } else if (opt == 2) { clr_screen (); mv_cursor (0, 0); printf ("\n"); printf (" The convolution kernel is a 3x3 matrix which is applied to a\n"); printf (" 3x3 neighborhood of a pixel and looks like this:\n"); printf ("\n"); printf (" __ __ \n"); printf (" | |\n"); printf (" | k0 k1 k2 |\n"); printf (" | |\n"); printf (" | k3 k4 k5 |\n"); printf (" | |\n"); printf (" | k6 k7 k8 |\n"); printf (" |__ __|\n"); printf ("\n\n"); printf (" You also need to specify if there is a resultant multiplyer or\n"); printf (" divisor. The operation on pixels (p4 is target or center) is:\n"); printf ("\n"); printf (" p4 = (p0 * k0) + ... + (p8 * k8) ( 0, no scaling)\n"); printf (" p4 = ((p0 * k0) + ... + (p8 * k8)) * mult ( 1, with multiplier)\n"); printf (" p4 = ((p0 * k0) + ... + (p8 * k8)) / div (-1, with divisor)\n"); printf ("\n"); } } /*------------------------------*/ /* info */ /*------------------------------*/ void info (fname) char *fname; { int key; long size; clr_screen (); mv_cursor (0, 1); printf (" MGIF Version: %s\n", version); printf (" \n"); printf (" File: %s\n", fname); printf (" \n"); size = (long) Width * (long) Height; printf (" Original image:\n"); printf (" Width %6d\n", Width); printf (" Height %6d\n", Height); printf (" Size %6ld pixels\n", size); printf (" \n"); size = (long) Width * (long) Height; printf (" New/transformed image:\n"); printf (" Width %6d\n", NewWidth); printf (" Height %6d\n", NewHeight); printf (" Size %6ld pixels\n", size); } /*------------------------------*/ /* do_help */ /*------------------------------*/ void do_help () { int key; clr_screen (); mv_cursor (0, 1); printf (" MGIF Version: %s\n", version); printf (" \n"); printf (" Category Key(s) Description\n"); printf (" --------------------------------------------------------------------\n"); printf (" Control: ? help\n"); printf (" w what (info about image)\n"); printf (" q quit (next image)\n"); printf (" ESC exit program now\n"); printf (" SPACE draw image\n"); printf (" hi histogram\n"); printf (" o toggle transform original/new image\n"); printf (" f file operations\n"); printf (" cp image copy (orig<-->new)\n"); printf (" \n"); printf (" Display Options: n add noise (0-100 percent, 0 turns off)\n"); printf (" g Laplace filter (beta,1,2,... 0 turns off)\n"); clr_cmd (); mv_cursor (0, 24); printf (" More? (y/n): "); key = get_key (); printf ("%c", (char) key); if ((key == 'n') || (key == 'N')) return; clr_screen (); mv_cursor (0, 1); printf (" MGIF Version: %s\n", version); printf (" \n"); printf (" Category Key(s) Description\n"); printf (" --------------------------------------------------------------------\n"); printf (" Frame Processes: e enlarge (2x)\n"); printf (" s shrink (.5x)\n"); printf (" z zoom (2x)\n"); printf (" cu cut\n"); printf (" r rotate (+/-90 or 180 deg)\n"); printf (" mi mirror (horizontal or vertical)\n"); printf (" \n"); printf (" Point Processes: he histogram equalization\n"); printf (" i inverse (negation, 0 all points else thresh)\n"); printf (" l log scaling\n"); printf (" t threshold (pseudo black/white)\n"); printf (" co contrast expansion (need new range)\n"); printf (" br brighten (darken if negative)\n"); printf (" \n"); printf (" Area Processes: bl blur (3x3)\n"); printf (" me median filter (3x3)\n"); printf (" v convolutions (3x3)\n"); return; }