[alt.sources] Vue v1.2, A Sunview rasterfile display utility

matthew@sunpix.East.Sun.COM (Matthew Stier - Sun Visualization Products) (03/09/91)

After receiving a few bug notices, I have fixed 'vue', and am reposting
it in its entirety.

Note: For those looking for a Sunview 'GIF' display program, this is what
you are looking for.  Matter of fact, 'vue' will display any file format
that there is a whatever_to_ras filter for.


---- Cut Here and unpack ----
#!/bin/sh
# shar:	Shell Archiver  (v1.25)
#	Packed Fri Mar  8 16:18:24 EST 1991 by gumbo!matthew
#	from directory /home/matthew/.bin/src/Sunview/Vue
#
#	Run the following text with /bin/sh to create:
#	  Makefile
#	  hglass.cursor
#	  vue.c
#	  vue.h
#	  vue.icon
#	  vue.man
#	  gif2ras.c
#	  gif2ras.man
#
if test -f Makefile; then echo "File Makefile exists"; else
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#
X# Makefile for 'vue'
X#
X# Note: Pre-SunOS 4.x.x machines do not support Frame props.
X#       To compile on Pre-SunOS 4.x.x machines, delete '-DFRAME_PROPS'
X#       from the 'CFLAGS' definition line, or override the 'CFLAGS' 
X#       definition line with a command-line definition.
X#
X
XCFLAGS	= -O -DFRAME_PROPS
XLDFLAGS	= -s
XLDLIBS	= -lsuntool -lsunwindow -lpixrect
X
Xvue:
X
Xgif2ras:
X
Xlint:
X	$(LINT) vue.c $(LDLIBS) 
X
Xclean:
X	$(RM) a.out core *.o
X
Xrealclean: clean
X	$(RM) vue
X
SHAR_EOF
chmod 0777 Makefile || echo "restore of Makefile fails"
fi
if test -f hglass.cursor; then echo "File hglass.cursor exists"; else
echo "x - extracting hglass.cursor (Text)"
sed 's/^X//' << 'SHAR_EOF' > hglass.cursor &&
X/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16
X */
X	0x7FFE,0x4002,0x200C,0x1A38,0x0FF0,0x07E0,0x03C0,0x0180,
X	0x0180,0x0240,0x0520,0x0810,0x1108,0x23C4,0x47E2,0x7FFE
SHAR_EOF
chmod 0644 hglass.cursor || echo "restore of hglass.cursor fails"
fi
if test -f vue.c; then echo "File vue.c exists"; else
echo "x - extracting vue.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > vue.c &&
X#ifndef lint
Xstatic char author[] = "matthew.stier@east.sun.com";
Xstatic char patchlevel[] = "Vue: Release 1, Patchlevel 2";
X/* 
X** Release 1.2: Fix Patch 1, and enable Sunview command line arguments
X**   Problem(s) noted by jwm@sun4.jhuapl.edu:
X**     Vue does not recognize standard tool arguments
X**   Problem(s) noted by lwv27@CAS.Bitnet
X**     Patch 1 syntax problem
X** Release 1.1: Make 'vue' SunOS 3.5 compatible 
X**   Problem(s) noted by jwm@sun4.jhuapl.edu:
X**     SunOS 3.5 does not support the 'props' option in frame menu.
X**     SunOS 3.5 does not support 'event_action()' macro.
X** Release 1.0: Initial release
X*/
X#endif /* lint */
X
X/* Define general items */
X#define PROGRAMNAME     "vue"
X#define ICON            "vue.icon"
X#define CURSOR          "hglass.cursor"
X#define DEFAULT_LABEL   "(hit right mouse button for menu)"
X
X/* Get #include */
X#include <stdio.h>
X#include <malloc.h>
X#include <strings.h>
X#include <sys/param.h>
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X#include <suntool/panel.h>
X#include <suntool/scrollbar.h>
X#include <suntool/expand_name.h>
X#include <sunwindow/cms_mono.h>
X#include "vue.h"
X
X/* Load the icon */
Xstatic short icon_image[] = {
X#include ICON
X};
Xmpr_static(icon_pixrect, 64, 64, 1, icon_image);
X
X/* Load the hour_glass cursor */
Xstatic short cursor_image[] = {
X#include CURSOR
X};
Xmpr_static(cursor_pixrect, 16, 16, 1, cursor_image);
X
X/* Define functions */
Xint main();
Xvoid frame_event();
Xint show();
Xvoid canvas_repaint(); 
Xvoid update_canvas_menu();
Xvoid set_frame_label();
Xchar *basename();
Xvoid create_control_panel();
Xvoid control_panel_proc();
Xvoid control_panel_done();
Xvoid selection_update();
Xvoid filter_update();
XPixrect *load_pixrect();
XPixrect *convert8to1();
XPixrect *convert32to1();
XPixrect *convert32to8();
XPixrect *convert8to32();
Xvoid init_colormap32();
X
X/* Define variables */
Xstatic Icon icon;
Xstatic Cursor hglass_cursor;
Xstatic Frame frame;
Xstatic Frame control_frame;
Xstatic Canvas canvas;
Xstatic Pixwin *pw;
Xstatic Pixrect *pr  = 0;
Xstatic Menu canvas_menu = 0;
Xstatic Panel control_panel;
Xstatic Panel_item fname_item;
Xstatic Panel_item filter_item;
Xstatic Panel_item order_item;
Xstatic int where = 0;
Xstatic int skip  = 0;
Xstatic int nitems;
Xstatic int max_depth;
Xstatic char directory[MAXPATHLEN];
Xstatic char *programname = PROGRAMNAME;
Xstatic char *filter = "";
Xstatic char current_image[MAXPATHLEN + 256];
Xstatic char **filename = 0;
Xstruct namelist *name_list;
X
X/* Define constants */
X#define ERROR_PAUSE  2
X#define ESCAPE_KEY   '\033'
X
Xint
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    int getpid();
X    char *getwd();
X    char *sprintf();
X
X    /* Set 'programname' */
X    if ( argc && *basename(argv[0]) != '\0')
X        programname = basename(argv[0]);
X
X    icon = icon_create(ICON_IMAGE, &icon_pixrect,
X        ICON_LABEL,  0,
X        ICON_WIDTH,  icon_pixrect.pr_size.x,
X        ICON_HEIGHT, icon_pixrect.pr_size.y,
X        0);
X
X    /* Create the hourglass cursor */
X    hglass_cursor = cursor_create(CURSOR_IMAGE, &cursor_pixrect, 0);
X
X    /* Create the frame */
X    frame = window_create((Window) 0, FRAME,
X        FRAME_ARGC_PTR_ARGV,     &argc, argv,
X        FRAME_ICON,              icon,
X#ifdef FRAME_PROPS
X        FRAME_PROPS_ACTIVE,      TRUE,
X        FRAME_PROPS_ACTION_PROC, control_panel_proc,
X#endif /* FRAME_PROPS */
X        WIN_ERROR_MSG,            "Couldn't create frame",
X        0);
X
X    /* Exit program if unable to create frame */
X    if (frame == 0) 
X        return(1);
X
X    /* Set frame label to default label */
X    (void) strcpy(current_image, DEFAULT_LABEL);
X    set_frame_label("%s: %s", current_image);
X
X    /* Create the canvas */
X    canvas = window_create(frame, CANVAS,
X        CANVAS_AUTO_EXPAND,       FALSE,
X        CANVAS_AUTO_SHRINK,       FALSE,
X        CANVAS_AUTO_CLEAR,        FALSE,
X        CANVAS_RETAINED,          FALSE,
X        CANVAS_REPAINT_PROC,      canvas_repaint,
X        WIN_EVENT_PROC,           frame_event,
X        WIN_CONSUME_KBD_EVENT,    WIN_ASCII_EVENTS,
X        WIN_ERROR_MSG,            "Couldn't create canvas",
X        WIN_HORIZONTAL_SCROLLBAR, scrollbar_create(SCROLL_LINE_HEIGHT, 1, 0),
X        WIN_VERTICAL_SCROLLBAR,   scrollbar_create(SCROLL_LINE_HEIGHT, 1, 0),
X        0);
X
X    /* Exit program if unable to create canvas */
X    if (canvas == 0)
X        return(1);
X
X    /* Get the pixwin for the canvas */
X    pw = canvas_pixwin(canvas);
X
X    /* determine max depth of the pixwin */
X    max_depth = pw->pw_pixrect->pr_depth;
X
X#ifdef CANVAS_COLOR24 /* If CANVAS_COLOR24 not declared, its not supported */
X    /* Set 24-bit color mode if the frame buffer is deep enough */
X    if (max_depth == 24 || max_depth == 32)
X        window_set(canvas, CANVAS_COLOR24, TRUE, 0);
X#endif /* CANVAS_COLOR24 */
X
X    /* Create a control panel */
X    create_control_panel();
X
X    /* Search command line for options */
X    while (argc > 1 && argv[1][0] == '-') {    
X        switch (argv[1][1]) {
X            case 'f': /* If filter specified, get filter name */
X                if ( argv[1][2] )  {
X                    filter = &argv[1][2];
X                } else {
X                    if ( argc > 2 ) {
X                        filter = argv[2];
X                        argc--;
X                        argv++;
X                    }
X                }
X                    break;
X            default: /* invalid option, complain */
X                (void) fprintf(stderr, 
X                    "Usage: %s [-f filter] [file]....\n", 
X                    programname);
X                return(1);
X        }
X        argc--;
X        argv++;
X    }
X
X    /* Set default fname_item for control panel */
X    if (argc > 1 && basename(argv[1]) != argv[1]) {
X        (void) strcpy(directory, argv[1]);
X        (void) strcpy(basename(directory), "*");
X    } else {
X        (void) getwd(directory);
X        (void) strcat(directory, "/*");
X    }
X        
X    /* Create the icon  */
X    /* Create a selection menu from the remaining items */
X    update_canvas_menu(--argc, ++argv);
X
X    /* Start main program loop */
X    (void) window_main_loop(frame);
X
X    /* Exit program successfully */
X    return(0);
X}
X
Xvoid
Xframe_event(window, event, arg)
X    Window window;
X    Event *event;
X    caddr_t arg;
X{
X
X    int item;
X
X    /* If a mouse button is pressed inside the canvas, do its action */
X    if (event_is_button(event) && event_is_down(event)) {
X        switch(event_id(event)) {
X            case MS_LEFT:   /* Goto previous image */
X                skip  = (skip > 0 ? -1 : skip - 1);
X                item  = (where ? where + skip : 1 + skip);
X                item += (item <      1 ? nitems : 0);
X                break;
X            case MS_MIDDLE: /* Goto next image */
X                skip  = (skip < 0 ?  1 : skip + 1);
X                item  = where + skip;
X                item -= (item > nitems ? nitems : 0);
X                break;
X            case MS_RIGHT:  /* Got to selected image */
X                item = (int) menu_show(canvas_menu, canvas,
X                    canvas_window_event(canvas, event), 0);
X                skip = 0;
X                break;
X            default:
X                break;
X        }
X
X        /* If it is a valid 'item', load the file */
X        if (item > 0 && item <= nitems && item != where ) {
X            /* Announce you are loading a new image */
X            set_frame_label("%s: %s (Loading)", filename[item - 1]);
X            /* Show new file */
X            if (show(filename[item - 1])) {
X                /* Set "where" pointer to image being shown */
X                where = item;
X                /* Zero out the skip_image counter */
X                skip = 0;
X                /* Syncronize MS_RIGHT menu to image being shown */
X                (void) menu_set(canvas_menu, MENU_SELECTED, item, 0);
X                /* Create new title bar */
X                (void) sprintf(current_image, "%s (%d x %d x %d)", 
X                    filename[item - 1],
X                    pr->pr_size.x, pr->pr_size.y, pr->pr_depth);
X            } else {
X                /* Report problem loading image */
X                set_frame_label("%s: Error loading '%s'", filename[item - 1]);
X                /* Pause so people can read it */
X                sleep(ERROR_PAUSE);
X            }
X            /* Update the frame label */
X            set_frame_label("%s: %s", current_image);
X        }
X    } else {
X        /* if the escape key is pressed, open the control panel */
X        if (event_id(event) == ESCAPE_KEY)
X            control_panel_proc();
X        /* handle all other canvas events */
X        (void) window_default_event_proc(window, event, arg); 
X    }
X}
X
Xint
Xshow(name)
X    char *name;
X{
X    /* Define functions */
X    char *sprintf();
X
X    /* Define local variables */
X    Cursor current_cursor;
X    char cmsname[CMS_NAMESIZE];
X    colormap_t cm;
X    Pixrect *new_pr = 0;
X
X    /* Get the current cursor */
X    current_cursor = (Cursor) window_get(canvas,WIN_CURSOR);
X
X    /* Change cursor to hour glass */
X    (void) window_set(canvas,WIN_CURSOR,hglass_cursor,0);
X
X    /* Load image into pixrect */
X    new_pr = load_pixrect(name, &cm);
X
X    /* If an error in reading the file, return cursor to normal and return */
X    if (!new_pr) {
X        (void) window_set(canvas, WIN_CURSOR, current_cursor, 0);
X        return (0);
X    }
X
X    /* Check pixrect depth against canvas depth, process where necessary */
X    switch (max_depth) {
X        case  1:
X            switch (new_pr->pr_depth) {
X                case  1:
X                    break;
X                case  8:
X                    new_pr = convert8to1(new_pr, &cm);
X                    break;
X                case 32:
X                    new_pr = convert32to1(new_pr, &cm);
X                    break;
X                default:
X                    pr_destroy(new_pr);
X                    new_pr = (Pixrect *) 0;
X                    break;
X            }
X            break;
X        case  8:
X            switch (new_pr->pr_depth) {
X                case  1:
X                    break;
X                case  8:
X                    break;
X                case 32:
X                    new_pr = convert32to8(new_pr, &cm);
X                    break;
X                default:
X                    pr_destroy(new_pr);
X                    new_pr = (Pixrect *) 0;
X                    break;
X            }
X            break;
X        case 24:
X            switch (new_pr->pr_depth) {
X                case  1:
X                    pr_destroy(new_pr);
X                    new_pr = (Pixrect *) 0;
X                    break;
X                case  8:
X                    pr_destroy(new_pr);
X                    new_pr = (Pixrect *) 0;
X                    break;
X                case 32:
X                    pr_destroy(new_pr);
X                    new_pr = (Pixrect *) 0;
X                    break;
X                default:
X                    pr_destroy(new_pr);
X                    new_pr = (Pixrect *) 0;
X                    break;
X            }
X            break;
X        case 32:
X            switch (new_pr->pr_depth) {
X                case  1:
X                    break;
X                case  8:
X                    new_pr = convert8to32(new_pr, &cm);
X                    break;
X                case 32:
X                    break;
X                default:
X                    pr_destroy(new_pr);
X                    new_pr = (Pixrect *) 0;
X                    break;
X            }
X            break;
X        default:
X            pr_destroy(new_pr);
X            new_pr = (Pixrect *) 0;
X            break;
X    }
X
X    /* If an error in converting the file, return cursor to normal and return */
X    if (!new_pr) {
X        (void) window_set(canvas, WIN_CURSOR, current_cursor, 0);
X        return (0);
X    }
X
X    /* Set colormaps */
X    switch (new_pr->pr_depth) {
X        case 1:
X            (void) pw_setcmsname(pw, CMS_MONOCHROME); 
X            break;
X        case 8:
X            switch (cm.type) {
X                case RMT_EQUAL_RGB:
X                    (void) sprintf(cmsname, "rs-%05d-%03d", 
X                        getpid(), cm.length);
X                    (void) pw_setcmsname(pw, cmsname); 
X                    (void) pw_putcolormap(pw, 0, cm.length,
X                        cm.map[0], cm.map[1], cm.map[2]);
X                    break;
X                default:
X                    break;
X            }
X        case 32:
X            break;
X        default:
X            break;
X    }
X
X    /* Blank the canvas */
X    (void) pw_writebackground(pw, 0, 0, 
X        pw->pw_pixrect->pr_size.x, pw->pw_pixrect->pr_size.y, PIX_SRC);
X
X    /* Resize the new canvas */
X    (void) window_set(canvas, 
X        CANVAS_WIDTH,  new_pr->pr_size.x, 
X        CANVAS_HEIGHT, new_pr->pr_size.y, 
X        0);
X    
X    /* Write the image to the canvas */
X    (void) pw_write(pw, 0, 0, 
X        new_pr->pr_size.x, new_pr->pr_size.y, PIX_SRC, new_pr, 0, 0);
X
X    /* All finished. Clean up and return success */
X    if (pr)
X        pr_destroy(pr);
X    pr = new_pr;
X    (void) window_set(canvas, WIN_CURSOR, current_cursor, 0);
X    return(1);
X}
X
X/*ARGSUSED*/
Xvoid
Xcanvas_repaint(canvas, pw, area)
XCanvas canvas;
XPixwin *pw;
XRectlist *area;
X{
X    if (pr) {
X        /* Repaint the image */
X        (void) pw_write(pw, 0, 0, 
X            pr->pr_size.x, pr->pr_size.y, PIX_SRC, pr, 0, 0);
X    } else {
X        /* Blank the canvas */
X        (void) pw_writebackground(pw, 0, 0, 
X            pw->pw_pixrect->pr_size.x, pw->pw_pixrect->pr_size.y, PIX_SRC);
X    }
X}
X
Xvoid
Xupdate_canvas_menu(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int index;
X
X    /* Destroy the old menu */    
X    if (canvas_menu != 0)
X        menu_destroy(canvas_menu);
X    
X    /* Create a new one     */
X    canvas_menu = menu_create(0);
X
X    /* and fill it in       */
X    for (index = 0; index < argc; index++)
X        (void) menu_set(canvas_menu, MENU_STRING_ITEM, 
X            argv[index], index + 1, 0);
X
X    /* and set some variables for frame_event() */
X    skip =0;
X    where = 0;
X    nitems = argc;
X    filename = argv;
X}
X
Xvoid
Xset_frame_label(format, filename)
Xchar *format;
Xchar *filename;
X{
X    char *sprintf();
X    char *title[MAXPATHLEN];
X
X    /* create the label */
X    (void) sprintf(title, format, programname, filename);
X    /* send it to the frame */
X    (void) window_set(frame, FRAME_LABEL, title, 0);
X}
X
Xchar *
Xbasename(pn)
Xchar *pn;      /* pointer to pathname */
X{
X    char *sp;  /* search pointer */
X    
X    /* set search pointer to the start of pathname */
X    sp = pn;
X
X    /* search pathname for last delimeter */
X    while ( *sp != '\0' ) {
X        if ( *sp++ == '/' )
X            pn = sp; 
X    }
X
X    /* return the basename */
X    return(pn);
X}
X
Xvoid
Xcreate_control_panel()
X{
X
X    control_frame = window_create(frame, FRAME, 
X        FRAME_LABEL,      programname,
X        FRAME_SHOW_LABEL, TRUE,
X        WIN_SHOW,         FALSE, 
X        0);
X
X    control_panel = window_create(control_frame, PANEL, 0); 
X
X    fname_item = panel_create_item(control_panel, PANEL_TEXT,
X        PANEL_LABEL_Y,              ATTR_ROW(0),
X        PANEL_LABEL_X,              ATTR_COL(0),
X        PANEL_VALUE_DISPLAY_LENGTH, 32,
X        PANEL_LABEL_STRING,         "File:  ",
X        PANEL_VALUE,                directory,
X        0);
X
X    (void) panel_create_item(control_panel, PANEL_BUTTON,
X        PANEL_LABEL_X,              ATTR_COL(42),
X        PANEL_LABEL_IMAGE, panel_button_image(control_panel, 
X            "Update Menu", 15, (Pixfont *) 0),
X        PANEL_NOTIFY_PROC, selection_update,
X        0);
X
X    filter_item = panel_create_item(control_panel, PANEL_TEXT,
X        PANEL_LABEL_Y,              ATTR_ROW(1),
X        PANEL_LABEL_X,              ATTR_COL(0),
X        PANEL_VALUE_DISPLAY_LENGTH, 32,
X        PANEL_LABEL_STRING,         "Filter:",
X        PANEL_VALUE,                filter,
X        0);
X
X    (void) panel_create_item(control_panel, PANEL_BUTTON,
X        PANEL_LABEL_X,              ATTR_COL(42),
X        PANEL_LABEL_IMAGE,          panel_button_image(control_panel, 
X                                        "Update filter", 15, (Pixfont *) 0),
X        PANEL_NOTIFY_PROC,          filter_update,
X        0);
X
X    order_item = panel_create_item(control_panel, PANEL_CYCLE,
X        PANEL_LABEL_Y,              ATTR_ROW(2),
X        PANEL_LABEL_X,              ATTR_COL(0),
X        PANEL_LABEL_STRING,         "Color ordering:",
X        PANEL_CHOICE_STRINGS,       "rgb", "bgr", 0,
X        0);
X
X    (void) panel_create_item(control_panel, PANEL_BUTTON,
X        PANEL_LABEL_X,              ATTR_COL(42),
X        PANEL_LABEL_IMAGE,          panel_button_image(control_panel, 
X                                       "Done", 15, (Pixfont *) 0),
X        PANEL_NOTIFY_PROC,          control_panel_done,
X        0);
X
X    (void) window_set(control_panel, PANEL_CARET_ITEM, fname_item, 0);
X
X    (void) window_fit(control_panel);
X    (void) window_fit(control_frame);
X
X}
X
Xvoid
Xcontrol_panel_proc()
X{
X    window_set(control_frame, 
X        WIN_X,    50, 
X        WIN_Y,    50, 
X        WIN_SHOW, TRUE,
X        0);
X}
X
Xvoid
Xcontrol_panel_done()
X{
X    window_set(control_frame, WIN_SHOW, FALSE, 0);
X}
X
Xvoid
Xselection_update()
X{
X    static char previous_dir[MAXPATHLEN];
X    char current_dir[MAXPATHLEN];
X    char fname[MAXPATHLEN];
X
X    /* Get a copy of fname_item */
X    (void) strcpy(current_dir, panel_get_value(fname_item));
X    (void) strcpy(fname, current_dir);
X
X    /* Truncate current_dir to the directory component */
X    (void) strcpy(basename(current_dir), "");
X
X    /* Truncate fname to filename only */
X    /* If no filename specified, assume wildcard of '*' */
X    if (!strlen(basename(fname))) {
X        (void) strcat(fname, "*");
X        (void) panel_set_value(fname_item, (caddr_t) fname); 
X    }
X
X    /* Change directories to match fname_item */
X    if (strcmp(previous_dir, current_dir)) {
X        (void) chdir(current_dir);
X        (void) strcpy(previous_dir, current_dir);
X    }
X
X    /* Convert filename to list of files */
X    name_list = expand_name(basename(fname));
X
X    /* Convert the expanded filename to a canvas menu */
X    update_canvas_menu((int) name_list->count, name_list->names);
X}
X
Xvoid
Xfilter_update()
X{
X    /* Get the filter_item value from the control panel */
X    filter = (char *) panel_get_value(filter_item);
X
X    /* Skip leading whitespace */
X    while ( *filter == ' ' || *filter == '\t' ) 
X        filter++; 
X}
X
XPixrect *
Xload_pixrect(name, cm)
Xchar *name;
Xcolormap_t *cm;
X{
X    FILE *inf;
X    Pixrect *tpr;
X    char *cmd;
X    char *cmdfmt = "(%s) < %s";
X
X    /* Load image into pixrect */
X    if (*filter) {
X        /* Allocate enough space to create commandline */
X        cmd = (char *) malloc((unsigned) 
X            (strlen(cmdfmt) + strlen(filter) + strlen(name)));
X        /* Verify allocation of commandline space */
X        if (cmd) {
X            /* Load image by piping the file thru a filter */
X            (void) sprintf(cmd, cmdfmt, filter, name);
X            if (!(inf = popen(cmd, "r")))
X                return((Pixrect *) 0);
X            tpr = pr_load(inf, cm);
X            if (pclose(inf))
X                tpr = (Pixrect *) 0;
X            (void) free(cmd);
X        } else {
X            (void) fprintf(stderr, 
X                "Error allocating space for filter commandline");
X        }
X    } else {
X        if (!(inf = fopen(name, "r")))
X            return((Pixrect *) 0);
X        tpr = pr_load(inf, cm);
X        if (fclose(inf))
X            tpr = (Pixrect *) 0;
X    }
X
X    /* And return */
X    return(tpr);
X}
X
XPixrect *
Xconvert8to1(pr8, cm)
XPixrect *pr8;
Xcolormap_t *cm;
X{
X    /* Define function variables */
X    Pixrect *pr1;
X    unsigned char *cm1 = 0;
X    int x, y, pixel8, pixel1;
X    unsigned long avg = 0;
X
X    /* Create an 1-bit pixrect */
X    pr1 = mem_create(pr8->pr_size.x, pr8->pr_size.y, 1);
X
X    /* Verify creation of mem_rect */
X    if (!pr1) {
X        pr_destroy(pr8);
X        return((Pixrect *) 0);
X    }
X
X    /* Convert the 8-bit pixrect to an 1-bit pixrect */
X    for (y = 0; y < pr8->pr_size.y; y++) {
X        for (x = 0; x < pr8->pr_size.x; x++) {
X            pixel8 = pr_get(pr8, x, y);
X            pixel1 = (ntscr[cm->map[0][pixel8]] + 
X                      ntscg[cm->map[1][pixel8]] + 
X                      ntscb[cm->map[2][pixel8]])/256;
X            pixel1 = pixel1 <= dither_table[y%16][x%16];
X            pr_put(pr1, x, y, pixel1);
X        }
X    }
X
X    /* Destroy the old pixrect, and return the new */
X    pr_destroy(pr8);
X    return(pr1);
X}
X
XPixrect *
Xconvert32to1(pr32, cm)
XPixrect *pr32;
Xcolormap_t *cm;
X{
X    /* Define function variables */
X    Pixrect *pr1;
X    unsigned char *cm1 = 0;
X    int x, y, blu_shift, grn_shift, red_shift, pixel32, pixel1;
X
X    /* Create an 1-bit pixrect */
X    pr1 = mem_create(pr32->pr_size.x, pr32->pr_size.y, 1);
X
X    /* Verify creation of mem_rect */
X    if (!pr1) {
X        pr_destroy(pr32);
X        return((Pixrect *) 0);
X    }
X
X    /* Set pixel shift value in accordance with the panel selection */
X    switch ((int) panel_get_value(order_item)) {
X        case 0: /* rgb */
X            blu_shift =  0;
X            grn_shift =  8;
X            red_shift = 16;
X            break;
X        case 1: /* bgr */
X            blu_shift = 16;
X            grn_shift =  8;
X            red_shift =  0;
X            break;
X        default: /* rgb */
X            blu_shift =  0;
X            grn_shift =  8;
X            red_shift = 16;
X            break;
X    }
X
X    /* Convert the 32-bit pixrect to an 1-bit pixrect */
X    for (y = 0; y < pr32->pr_size.y; y++) {
X        for (x = 0; x < pr32->pr_size.x; x++) {
X            pixel32 = pr_get(pr32, x, y);
X            pixel1 = (ntscb[((pixel32 >> blu_shift) & 0xff)] + 
X                      ntscg[((pixel32 >> grn_shift) & 0xff)] + 
X                      ntscr[((pixel32 >> red_shift) & 0xff)])/256;
X            pixel1 = pixel1 <= dither_table[y%16][x%16];
X            pr_put(pr1, x, y, pixel1);
X        }
X    }
X
X    /* Destroy the old pixrect, and return the new */
X    pr_destroy(pr32);
X    return(pr1);
X}
X
XPixrect *
Xconvert32to8(pr32, cm)
XPixrect *pr32;
Xcolormap_t *cm;
X{
X
X#undef  CM_SIZE
X#define CM_SIZE 256
X#define MAX_BLU   4
X#define BLU_STEP 85    
X#define MAX_GRN   8
X#define GRN_STEP 36    
X#define MAX_RED   8
X#define RED_STEP 36    
X
X    /* Define function variables */
X    int blu_index, grn_index, red_index, cm_index = 0;
X    Pixrect *pr8 = 0;
X    unsigned char *cm8 = 0;
X    int x, y, pixel32, pixel8;
X    int order, blu_shift, grn_shift, red_shift;
X
X    /* Get the space for a colormap */
X    cm8 = (unsigned char *) malloc(CM_SIZE * 3);
X
X    /* Verify allocation of colormap space */
X    if (!cm) {
X        pr_destroy(pr32);
X        return((Pixrect *) 0);
X    }
X
X    /* Create a colormap table */
X    cm->type = RMT_EQUAL_RGB;
X    cm->length = CM_SIZE;
X    cm->map[0] = cm8;
X    cm->map[1] = cm->map[0] + CM_SIZE;
X    cm->map[2] = cm->map[1] + CM_SIZE;
X
X    /* Fill-in the colormap */
X    for (blu_index = 0; blu_index < MAX_BLU; blu_index++) {
X        for (grn_index = 0; grn_index < MAX_GRN; grn_index++) {
X            for (red_index = 0; red_index < MAX_RED; red_index++) {
X                cm->map[0][cm_index] = red_index * RED_STEP;
X                cm->map[1][cm_index] = grn_index * GRN_STEP;
X                cm->map[2][cm_index] = blu_index * BLU_STEP;
X                cm_index++;
X            }
X        }
X    }
X
X    /* Create an 8-bit pixrect */
X    pr8 = mem_create(pr32->pr_size.x, pr32->pr_size.y, 8);
X
X    /* Verify creation of mem_rect */
X    if (!pr8) {
X        pr_destroy(pr32);
X        return((Pixrect *) 0);
X    }
X
X    /* Set pixel shift value in accordance with the panel selection */
X    switch ((int) panel_get_value(order_item)) {
X        case 0: /* rgb */
X            blu_shift =  0;
X            grn_shift = 10;
X            red_shift = 21;
X            break;
X        case 1: /* bgr */
X            blu_shift = 16;
X            grn_shift = 10;
X            red_shift =  5;
X            break;
X        default: /* rgb */
X            blu_shift =  0;
X            grn_shift = 10;
X            red_shift = 21;
X            break;
X    }
X
X    /* Convert the 32-bit pixrect to an 8-bit pixrect */
X    for (y = 0; y < pr32->pr_size.y; y++) {
X        for (x = 0; x < pr32->pr_size.x; x++) {
X            pixel32 = pr_get(pr32, x, y);
X            pixel8 = ((pixel32 >> blu_shift) & 0xc0) | 
X                     ((pixel32 >> grn_shift) & 0x38) |
X                     ((pixel32 >> red_shift) & 0x07);
X            pr_put(pr8, x, y, pixel8);
X        }
X    }
X    /* Destroy the old pixrect, and return the new */
X    pr_destroy(pr32);
X    return(pr8);
X}
X
XPixrect *
Xconvert8to32(pr8, cm)
XPixrect *pr8;
Xcolormap_t *cm;
X{
X    /* Define function variables */
X    Pixrect *pr32 = 0;
X    int x, y, pixel32, pixel8;
X    int order, blu_shift, grn_shift, red_shift;
X
X    /* Create an 32-bit pixrect */
X    pr32 = mem_create(pr8->pr_size.x, pr8->pr_size.y, 32);
X
X    /* Verify creation of mem_rect */
X    if (!pr32) {
X        pr_destroy(pr8);
X        return((Pixrect *) 0);
X    }
X
X    /* Set pixel shift value in accordance with the panel selection */
X    switch ((int) panel_get_value(order_item)) {
X        case 0: /* rgb */
X            blu_shift =  0;
X            grn_shift =  8;
X            red_shift = 16;
X            break;
X        case 1: /* bgr */
X            blu_shift = 16;
X            grn_shift =  8;
X            red_shift =  0;
X            break;
X        default: /* rgb */
X            blu_shift =  0;
X            grn_shift =  8;
X            red_shift = 16;
X            break;
X    }
X
X    /* Convert the 8-bit pixrect to an 32-bit pixrect */
X    for (y = 0; y < pr8->pr_size.y; y++) {
X        for (x = 0; x < pr8->pr_size.x; x++) {
X            pixel8  = pr_get(pr8, x, y);
X            pixel32 = cm->map[2][pixel8] << blu_shift |
X                      cm->map[1][pixel8] << grn_shift |
X                      cm->map[0][pixel8] << red_shift;
X            pr_put(pr32, x, y, pixel32);
X        }
X    }
X    /* Destroy the old pixrect, and return the new */
X    pr_destroy(pr8);
X    return(pr32);
X}
X
SHAR_EOF
chmod 0777 vue.c || echo "restore of vue.c fails"
fi
if test -f vue.h; then echo "File vue.h exists"; else
echo "x - extracting vue.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > vue.h &&
Xstatic unsigned int ntscr[] = {
X        0,   77,  153,  230,  306,  383,  459,  536,
X      612,  689,  765,  842,  919,  995, 1072, 1148,
X     1225, 1301, 1378, 1454, 1531, 1607, 1684, 1761,
X     1837, 1914, 1990, 2067, 2143, 2220, 2296, 2373,
X     2449, 2526, 2602, 2679, 2756, 2832, 2909, 2985,
X     3062, 3138, 3215, 3291, 3368, 3444, 3521, 3598,
X     3674, 3751, 3827, 3904, 3980, 4057, 4133, 4210,
X     4286, 4363, 4440, 4516, 4593, 4669, 4746, 4822,
X     4899, 4975, 5052, 5128, 5205, 5282, 5358, 5435,
X     5511, 5588, 5664, 5741, 5817, 5894, 5970, 6047,
X     6124, 6200, 6277, 6353, 6430, 6506, 6583, 6659,
X     6736, 6812, 6889, 6966, 7042, 7119, 7195, 7272,
X     7348, 7425, 7501, 7578, 7654, 7731, 7807, 7884,
X     7961, 8037, 8114, 8190, 8267, 8343, 8420, 8496,
X     8573, 8649, 8726, 8803, 8879, 8956, 9032, 9109,
X     9185, 9262, 9338, 9415, 9491, 9568, 9645, 9721,
X     9798, 9874, 9951,10027,10104,10180,10257,10333,
X    10410,10487,10563,10640,10716,10793,10869,10946,
X    11022,11099,11175,11252,11329,11405,11482,11558,
X    11635,11711,11788,11864,11941,12017,12094,12170,
X    12247,12324,12400,12477,12553,12630,12706,12783,
X    12859,12936,13012,13089,13166,13242,13319,13395,
X    13472,13548,13625,13701,13778,13854,13931,14008,
X    14084,14161,14237,14314,14390,14467,14543,14620,
X    14696,14773,14850,14926,15003,15079,15156,15232,
X    15309,15385,15462,15538,15615,15692,15768,15845,
X    15921,15998,16074,16151,16227,16304,16380,16457,
X    16534,16610,16687,16763,16840,16916,16993,17069,
X    17146,17222,17299,17375,17452,17529,17605,17682,
X    17758,17835,17911,17988,18064,18141,18217,18294,
X    18371,18447,18524,18600,18677,18753,18830,18906,
X    18983,19059,19136,19213,19289,19366,19442,19519};
X
Xstatic unsigned int ntscg[] = {
X        0,  150,  301,  451,  601,  751,  902, 1052,
X     1202, 1352, 1503, 1653, 1803, 1954, 2104, 2254,
X     2404, 2555, 2705, 2855, 3005, 3156, 3306, 3456,
X     3607, 3757, 3907, 4057, 4208, 4358, 4508, 4658,
X     4809, 4959, 5109, 5260, 5410, 5560, 5710, 5861,
X     6011, 6161, 6311, 6462, 6612, 6762, 6913, 7063,
X     7213, 7363, 7514, 7664, 7814, 7964, 8115, 8265,
X     8415, 8566, 8716, 8866, 9016, 9167, 9317, 9467,
X     9617, 9768, 9918,10068,10218,10369,10519,10669,
X    10820,10970,11120,11270,11421,11571,11721,11871,
X    12022,12172,12322,12473,12623,12773,12923,13074,
X    13224,13374,13524,13675,13825,13975,14126,14276,
X    14426,14576,14727,14877,15027,15177,15328,15478,
X    15628,15779,15929,16079,16229,16380,16530,16680,
X    16830,16981,17131,17281,17432,17582,17732,17882,
X    18033,18183,18333,18483,18634,18784,18934,19085,
X    19235,19385,19535,19686,19836,19986,20136,20287,
X    20437,20587,20738,20888,21038,21188,21339,21489,
X    21639,21789,21940,22090,22240,22391,22541,22691,
X    22841,22992,23142,23292,23442,23593,23743,23893,
X    24044,24194,24344,24494,24645,24795,24945,25095,
X    25246,25396,25546,25697,25847,25997,26147,26298,
X    26448,26598,26748,26899,27049,27199,27350,27500,
X    27650,27800,27951,28101,28251,28401,28552,28702,
X    28852,29002,29153,29303,29453,29604,29754,29904,
X    30054,30205,30355,30505,30655,30806,30956,31106,
X    31257,31407,31557,31707,31858,32008,32158,32308,
X    32459,32609,32759,32910,33060,33210,33360,33511,
X    33661,33811,33961,34112,34262,34412,34563,34713,
X    34863,35013,35164,35314,35464,35614,35765,35915,
X    36065,36216,36366,36516,36666,36817,36967,37117,
X    37267,37418,37568,37718,37869,38019,38169,38319};
X
Xstatic unsigned int ntscb[] = {
X        0,   29,   58,   88,  117,  146,  175,  204,
X      233,  263,  292,  321,  350,  379,  409,  438,
X      467,  496,  525,  554,  584,  613,  642,  671,
X      700,  730,  759,  788,  817,  846,  876,  905,
X      934,  963,  992, 1021, 1051, 1080, 1109, 1138,
X     1167, 1197, 1226, 1255, 1284, 1313, 1342, 1372,
X     1401, 1430, 1459, 1488, 1518, 1547, 1576, 1605,
X     1634, 1663, 1693, 1722, 1751, 1780, 1809, 1839,
X     1868, 1897, 1926, 1955, 1985, 2014, 2043, 2072,
X     2101, 2130, 2160, 2189, 2218, 2247, 2276, 2306,
X     2335, 2364, 2393, 2422, 2451, 2481, 2510, 2539,
X     2568, 2597, 2627, 2656, 2685, 2714, 2743, 2772,
X     2802, 2831, 2860, 2889, 2918, 2948, 2977, 3006,
X     3035, 3064, 3094, 3123, 3152, 3181, 3210, 3239,
X     3269, 3298, 3327, 3356, 3385, 3415, 3444, 3473,
X     3502, 3531, 3560, 3590, 3619, 3648, 3677, 3706,
X     3736, 3765, 3794, 3823, 3852, 3881, 3911, 3940,
X     3969, 3998, 4027, 4057, 4086, 4115, 4144, 4173,
X     4202, 4232, 4261, 4290, 4319, 4348, 4378, 4407,
X     4436, 4465, 4494, 4524, 4553, 4582, 4611, 4640,
X     4669, 4699, 4728, 4757, 4786, 4815, 4845, 4874,
X     4903, 4932, 4961, 4990, 5020, 5049, 5078, 5107,
X     5136, 5166, 5195, 5224, 5253, 5282, 5311, 5341,
X     5370, 5399, 5428, 5457, 5487, 5516, 5545, 5574,
X     5603, 5633, 5662, 5691, 5720, 5749, 5778, 5808,
X     5837, 5866, 5895, 5924, 5954, 5983, 6012, 6041,
X     6070, 6099, 6129, 6158, 6187, 6216, 6245, 6275,
X     6304, 6333, 6362, 6391, 6420, 6450, 6479, 6508,
X     6537, 6566, 6596, 6625, 6654, 6683, 6712, 6742,
X     6771, 6800, 6829, 6858, 6887, 6917, 6946, 6975,
X     7004, 7033, 7063, 7092, 7121, 7150, 7179, 7208,
X     7238, 7267, 7296, 7325, 7354, 7384, 7413, 7442};
X
Xstatic int dither_table[16][16] = {
X    {  0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,254},
X    {128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127},
X    { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223},
X    {160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95},
X    {  8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247},
X    {136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119},
X    { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215},
X    {168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87},
X    {  2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253},
X    {130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125},
X    { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221},
X    {162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93},
X    { 10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245},
X    {138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117},
X    { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213},
X    {170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85}};
X
SHAR_EOF
chmod 0644 vue.h || echo "restore of vue.h fails"
fi
if test -f vue.icon; then echo "File vue.icon exists"; else
echo "x - extracting vue.icon (Text)"
sed 's/^X//' << 'SHAR_EOF' > vue.icon &&
X/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
X */
X	0x3FFF,0xFFFF,0xFFFF,0xFFFC,0x7FFF,0xFFFF,0xFFFF,0xFFFE,
X	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE083,0x5555,0x5591,0x1107,
X	0xE092,0xAAAA,0xAA88,0x8927,0xE0BB,0x5555,0x55A2,0x2377,
X	0xE092,0xAAAA,0xAAC4,0x4527,0xE083,0x5555,0x5591,0x1107,
X	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE080,0x0000,0x0000,0x0007,
X	0xE480,0x0000,0x0000,0x0007,0xEE80,0x0000,0x0000,0x0007,
X	0xE480,0x0000,0x0000,0x0007,0xE080,0x0000,0x0000,0x0007,
X	0xFF80,0x0000,0x0000,0x0007,0xF580,0x0000,0x0000,0x0007,
X	0xEA80,0x0000,0x0000,0x0007,0xF59C,0x1C00,0x0000,0x0007,
X	0xEA8C,0x0800,0x0000,0x0007,0xF586,0x1000,0x0000,0x0007,
X	0xEA86,0x1000,0x0000,0x0007,0xF586,0x10F3,0xC1E0,0x0007,
X	0xEA83,0x2061,0x8618,0x0007,0xF583,0x2061,0x8C0C,0x0007,
X	0xEA83,0x2061,0x8C0C,0x0007,0xF581,0x8061,0x8FFC,0x0007,
X	0xEA81,0xC061,0x8C00,0x0007,0xF581,0xC061,0x8C00,0x0007,
X	0xEA80,0x8061,0x8600,0x0007,0xF580,0x8073,0x830C,0x0007,
X	0xEA80,0x803C,0xC1F0,0x0007,0xFF80,0x0000,0x0000,0x0007,
X	0xE880,0x0000,0x0000,0x0007,0xE280,0x0000,0x0000,0x0007,
X	0xE480,0x0000,0x0000,0x0007,0xF180,0x0000,0x0000,0x0007,
X	0xE880,0x0000,0x0000,0x0007,0xE280,0x0000,0x0000,0x0007,
X	0xE480,0x0000,0x0000,0x0007,0xF180,0x0000,0x0000,0x0007,
X	0xE880,0x0000,0x0000,0x0007,0xE280,0x0000,0x0000,0x0007,
X	0xE480,0x0000,0x0000,0x0007,0xF180,0x0000,0x0000,0x0007,
X	0xE880,0x0000,0x0000,0x0007,0xE280,0x0000,0x0000,0x0007,
X	0xE480,0x0000,0x0000,0x0007,0xF180,0x0000,0x0000,0x0007,
X	0xE880,0x0000,0x0000,0x0007,0xE280,0x0000,0x0000,0x0007,
X	0xE480,0x0000,0x0000,0x0007,0xF180,0x0000,0x0000,0x0007,
X	0xE880,0x0000,0x0000,0x0007,0xE280,0x0000,0x0000,0x0007,
X	0xE480,0x0000,0x0000,0x0007,0xFF80,0x0000,0x0000,0x0007,
X	0xE080,0x0000,0x0000,0x0007,0xE480,0x0000,0x0000,0x0007,
X	0xEE80,0x0000,0x0000,0x0007,0xE480,0x0000,0x0000,0x0007,
X	0xE080,0x0000,0x0000,0x0007,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
X	0x7FFF,0xFFFF,0xFFFF,0xFFFE,0x3FFF,0xFFFF,0xFFFF,0xFFFC
SHAR_EOF
chmod 0777 vue.icon || echo "restore of vue.icon fails"
fi
if test -f vue.man; then echo "File vue.man exists"; else
echo "x - extracting vue.man (Text)"
sed 's/^X//' << 'SHAR_EOF' > vue.man &&
X.TH VUE L
X.SH NAME
Xvue \- a Sunview rasterfile display program
X.SH SYNOPSIS
X\fBvue\fP [ \fB-f filter\fP ] [ \fBfilename... \fP]
X.SH DESCRIPTION
XVue is a Sunview tool to display images in a scrollable Sunview 
Xwindow. Vue can be used with or without a filter. Without a filter
Xvue can be used to display ordinary rasterfiles. With a user 
Xsupplied filter, vue can display whatever filetype the supplied 
Xfilter works with.
X
XFile selection within vue is very easy. 
XWhile the mouse cursor is inside the display area, 
Xa new file may selected using any of the three mouse buttons. 
XPressing the right mouse button will display a menu of available files.
XTo select a new file, simply high-lighting the desired file, 
Xand release the button.
XSingle stepping thru the file menu is accomplished by clicking 
Xthe left and middle mouse buttons. 
XClicking the left mouse button to go up the list. 
XClicking the middle mouse button to go down the list. 
XVue will "roll-over" upon reaching either end of the list. 
XVue will also "step over" files it cannot load 
X(simply press the same mouse button again).
X
XVue uses the frame's label bar to display program status messages,
Xand the name of the file being displayed.
X
XAccess to vue's control panel can be obtain by selecting [props] from
Xvue's frame menu, or by pressing the [esc] key while the mouse cursor 
Xis inside the display area. The selection menu can be updated by 
Xentering a new filename on the 'File:' line and pressing the [Update_Menu] 
Xbutton. Changing the filter or updating the filter options used can be 
Xdone by editing the 'Filter:' line and pressing the [Update_filter] button.
X(These lines many contain shell wildcard characters.)  
X.SH OPTIONS
X.TP
X\fB-f\fP \fIfilter\fP
XSpecify a filter vue is to pipe the selected file thru before
Xdisplaying it. Using 'zcat' as a filter, vue can display the contents 
Xof compressed rasterfiles. Using Patrick J. Naughton's gif2ras program, 
Xvue can be used to display GIF files.
X.SH AUTHOR
X.nf
XMatthew Lee Stier
XSun Microsystems
X2000 Aerial Center, Suite 110
XMorrisville, NC 27560
X(919) 469-8300
X.fi
X.SH CREDITS
XVue was developed from a program publically called rastershow.
XRastershow's author is: David DiGiacomo, also an employee of Sun Microsystems
X.SH NOTES
XVue expects filters to accept input via stdin, and output the rasterfile 
Xvia stdout. If the filter you intend to use requires command-line option, 
Xthese need to included with the filter argument by enclosing it in single quotes. 
X
X	vue -f 'filter -options' filename filename....
X
XAny filter you specify must be reachable using your $PATH enviromental variable, 
Xor you must specify the the filters full path/filename.
X
XVue does do rudimentary dithering. This is to permit the viewing of color images
Xon monochrome workstations, and 24-bit images on 8-bit color displays.
SHAR_EOF
chmod 0777 vue.man || echo "restore of vue.man fails"
fi
if test -f gif2ras.c; then echo "File gif2ras.c exists"; else
echo "x - extracting gif2ras.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > gif2ras.c &&
X#ifndef lint
Xstatic char sccsid[] = "@(#)gif2ras.c 1.1 89/01/17";
X#endif
X/*-
X * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
X *
X * Copyright (c) 1988, 1989 by Patrick J. Naughton
X *
X * Author: Patrick J. Naughton
X * naughton@wind.sun.com
X *
X * Permission to use, copy, modify, and distribute this software and its
X * documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appear in all copies and that
X * both that copyright notice and this permission notice appear in
X * supporting documentation.
X *
X * This file is provided AS IS with no warranties of any kind.  The author
X * shall have no liability with respect to the infringement of copyrights,
X * trade secrets or any patents by this file or any part thereof.  In no
X * event will the author be liable for any lost revenue or profits or
X * other special, indirect and consequential damages.
X *
X * Comments and additions should be sent to the author:
X *
X *                     Patrick J. Naughton
X *                     Sun Microsystems
X *                     2550 Garcia Ave, MS 14-40
X *                     Mountain View, CA 94043
X *                     (415) 336-1080
X *
X * Revision History:
X * 01-Jan-89: Added error checking and removed NEXTSHORT.
X * 07-Sep-88: Added BytesPerScanline fix.
X * 30-Aug-88: Allow stdin/stdout. Restructured argument parser.
X * 27-Jul-88: Updated to use libpixrect to fix 386i byteswapping problems.
X * 11-Apr-88: Converted to C and changed to write Sun rasterfiles.
X * 19-Jan-88: GIFSLOW.PAS posted to comp.graphics by Jim Briebel,
X *            a Turbo Pascal 4.0 program to painfully slowly display
X *            GIF images on an EGA equipped IBM-PC.
X *
X * Description:
X *   This program takes a Compuserve "Graphics Interchange Format" or "GIF"
X * file as input and writes a file known as a Sun rasterfile.  This datafile
X * can be loaded by the NeWS "readcanvas" operator and is of the same format
X * as the files in /usr/NeWS/smi/*.  Under X11R2 there is a program called
X * xraster to display these files.
X *
X * Portability:
X *   To make this program convert to some image format other than Sun's
X * Rasterfile format simply seach for the tag "SS:" in the source and
X * replace these simple mechanisms with the appropriate ones for the
X * other output format.  I have marked all (six) Sun Specific pieces
X * of code with this comment.
X *
X * SS: compile with "cc -o gif2ras -O gif2ras.c -lpixrect"
X */
X
X#include <stdio.h>
X#include <pixrect/pixrect_hs.h> /* SS: main Pixrect header file */
X
Xtypedef int boolean;
X#define True (1)
X#define False (0)
X
X#define NEXTBYTE (*ptr++)
X#define IMAGESEP 0x2c
X#define INTERLACEMASK 0x40
X#define COLORMAPMASK 0x80
X
XFILE *fp;
X
Xint BitOffset = 0,		/* Bit Offset of next code */
X    XC = 0, YC = 0,		/* Output X and Y coords of current pixel */
X    Pass = 0,			/* Used by output routine if interlaced pic */
X    OutCount = 0,		/* Decompressor output 'stack count' */
X    RWidth, RHeight,		/* screen dimensions */
X    Width, Height,		/* image dimensions */
X    LeftOfs, TopOfs,		/* image offset */
X    BitsPerPixel,		/* Bits per pixel, read from GIF header */
X    BytesPerScanline,		/* bytes per scanline in output raster */
X    ColorMapSize,		/* number of colors */
X    CodeSize,			/* Code size, read from GIF header */
X    InitCodeSize,		/* Starting code size, used during Clear */
X    Code,			/* Value returned by ReadCode */
X    MaxCode,			/* limiting value for current code size */
X    ClearCode,			/* GIF clear code */
X    EOFCode,			/* GIF end-of-information code */
X    CurCode, OldCode, InCode,	/* Decompressor variables */
X    FirstFree,			/* First free code, generated per GIF spec */
X    FreeCode,			/* Decompressor, next free slot in hash table */
X    FinChar,			/* Decompressor variable */
X    BitMask,			/* AND mask for data size */
X    ReadMask;			/* Code AND mask for current code size */
X
Xboolean Interlace, HasColormap;
Xboolean Verbose = False;
X
X/* SS: defined in pixrect/pixrect_hs.h */
XPixrect *Output;		/* The Sun Pixrect */
Xcolormap_t Colormap;		/* The Pixrect Colormap */
X
Xu_char *Image;			/* The result array */
Xu_char *RawGIF;			/* The heap array to hold it, raw */
Xu_char *Raster;			/* The raster data stream, unblocked */
X
X    /* The hash table used by the decompressor */
Xint Prefix[4096];
Xint Suffix[4096];
X
X    /* An output array used by the decompressor */
Xint OutCode[1025];
X
X    /* The color map, read from the GIF header */
Xu_char Red[256], Green[256], Blue[256];
X
Xchar *id = "GIF87a";
X
Xchar *pname;			/* program name (used for error messages) */
X 
Xvoid
Xerror(s1, s2)
Xchar *s1, *s2;
X{
X    fprintf(stderr, s1, pname, s2);
X    exit(1);
X}
X
Xvoid
Xusage()
X{
X    error("usage: %s -[vq] [-|GIFfile] [rasterfile]\n", NULL);
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
Xchar *inf = NULL;
Xchar *outf = NULL;
Xint filesize;
Xregister u_char ch, ch1;
Xregister u_char *ptr, *ptr1;
Xregister int i;
X
X    setbuf(stderr, NULL);
X    pname = argv[0];
X
X    while (--argc)
X	if ((++argv)[0][0] == '-')
X	    switch (argv[0][1]) {
X	    case 'v':
X		Verbose = True;
X		break;
X	    case 'q':
X		usage();
X	    case '\0':
X		if (inf == NULL)
X		    inf = "Standard Input";
X		else if (outf == NULL)
X		    outf = "Standard Output";
X		else
X		    usage();
X		break;
X	    default:
X		fprintf(stderr, "%s: illegal option -%c.\n", pname,
X			argv[0][1]);
X		exit(1);
X	    }
X	else if (inf == NULL)
X	    inf = argv[0];
X	else if (outf == NULL)
X	    outf = argv[0];
X	else
X	    usage();
X
X    if (inf == NULL || strcmp(inf, "Standard Input") == 0) {
X	inf = "Standard Input";
X	fp = stdin;
X    } else if (!(fp = fopen(inf, "r")))
X	error("%s: %s not found.\n", inf);
X
X    /* find the size of the file */
X    fseek(fp, 0L, 2);
X    filesize = ftell(fp);
X    fseek(fp, 0L, 0);
X
X    if (!(ptr = RawGIF = (u_char *) malloc(filesize)))
X	error("%s: not enough memory to read gif file.\n", NULL);
X
X    if (!(Raster = (u_char *) malloc(filesize)))
X	error("%s: not enough memory to read gif file.\n", NULL);
X
X    if (fread(ptr, filesize, 1, fp) != 1)
X	error("%s: GIF data read failed\n", NULL);
X
X    if (strncmp(ptr, id, 6))
X	error("%s: %s is not a GIF file.\n", inf);
X    ptr += 6;
X
X/* Get variables from the GIF screen descriptor */
X
X    ch = NEXTBYTE;
X    RWidth = ch + 0x100 * NEXTBYTE;	/* screen dimensions... not used. */
X    ch = NEXTBYTE;
X    RHeight = ch + 0x100 * NEXTBYTE;
X
X    if (Verbose)
X	fprintf(stderr, "screen dims: %dx%d.\n", RWidth, RHeight);
X
X    ch = NEXTBYTE;
X    HasColormap = ((ch & COLORMAPMASK) ? True : False);
X
X    BitsPerPixel = (ch & 7) + 1;
X    ColorMapSize = 1 << BitsPerPixel;
X    BitMask = ColorMapSize - 1;
X
X    ch = NEXTBYTE;		/* background color... not used. */
X
X    if (NEXTBYTE)		/* supposed to be NULL */
X	error("%s: %s is a corrupt GIF file (nonull).\n", inf);
X
X/* Read in global colormap. */
X
X    if (HasColormap) {
X	if (Verbose)
X	    fprintf(stderr, "%s is %d bits per pixel, (%d colors).\n",
X		inf, BitsPerPixel, ColorMapSize);
X	for (i = 0; i < ColorMapSize; i++) {
X	    Red[i] = NEXTBYTE;
X	    Green[i] = NEXTBYTE;
X	    Blue[i] = NEXTBYTE;
X	}
X
X/* SS: Fill in the Pixrect colormap struct */
X	Colormap.type = RMT_EQUAL_RGB;
X	Colormap.length = ColorMapSize;
X	Colormap.map[0] = Red;
X	Colormap.map[1] = Green;
X	Colormap.map[2] = Blue;
X    }
X    else error("%s: %s does not have a colormap.\n", inf);
X
X
X/* Check for image seperator */
X
X    if (NEXTBYTE != IMAGESEP)
X	error("%s: %s is a corrupt GIF file (nosep).\n", inf);
X
X/* Now read in values from the image descriptor */
X
X    ch = NEXTBYTE;
X    LeftOfs = ch + 0x100 * NEXTBYTE;
X    ch = NEXTBYTE;
X    TopOfs = ch + 0x100 * NEXTBYTE;
X    ch = NEXTBYTE;
X    Width = ch + 0x100 * NEXTBYTE;
X    ch = NEXTBYTE;
X    Height = ch + 0x100 * NEXTBYTE;
X    Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
X
X    if (Verbose)
X	fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
X		Width, Height, (Interlace) ? "" : "non-");
X    
X
X/* Note that I ignore the possible existence of a local color map.
X * I'm told there aren't many files around that use them, and the spec
X * says it's defined for future use.  This could lead to an error
X * reading some files. 
X */
X
X/* Start reading the raster data. First we get the intial code size
X * and compute decompressor constant values, based on this code size.
X */
X
X    CodeSize = NEXTBYTE;
X    ClearCode = (1 << CodeSize);
X    EOFCode = ClearCode + 1;
X    FreeCode = FirstFree = ClearCode + 2;
X
X/* The GIF spec has it that the code size is the code size used to
X * compute the above values is the code size given in the file, but the
X * code size used in compression/decompression is the code size given in
X * the file plus one. (thus the ++).
X */
X
X    CodeSize++;
X    InitCodeSize = CodeSize;
X    MaxCode = (1 << CodeSize);
X    ReadMask = MaxCode - 1;
X
X/* Read the raster data.  Here we just transpose it from the GIF array
X * to the Raster array, turning it from a series of blocks into one long
X * data stream, which makes life much easier for ReadCode().
X */
X
X    ptr1 = Raster;
X    do {
X	ch = ch1 = NEXTBYTE;
X	while (ch--) *ptr1++ = NEXTBYTE;
X	if ((ptr1 - Raster ) > filesize)
X	    error("%s: %s is a corrupt GIF file (unblock).\n", inf);
X    } while(ch1);
X
X    free(RawGIF);		/* We're done with the raw data now... */
X
X    if (Verbose) {
X	fprintf(stderr, "done.\n");
X	fprintf(stderr, "Decompressing...");
X    }
X
X
X/* SS: Allocate the Sun Pixrect and make "Image" point to the image data. */
X    Output = mem_create(Width, Height, 8);
X    if (Output == (Pixrect *) NULL)
X	error("%s: not enough memory for output data.\n", NULL);
X    Image = (u_char *) mpr_d(Output)->md_image;
X    BytesPerScanline = mpr_d(Output)->md_linebytes;
X
X
X/* Decompress the file, continuing until you see the GIF EOF code.
X * One obvious enhancement is to add checking for corrupt files here.
X */
X
X    Code = ReadCode();
X    while (Code != EOFCode) {
X
X/* Clear code sets everything back to its initial value, then reads the
X * immediately subsequent code as uncompressed data.
X */
X
X	if (Code == ClearCode) {
X	    CodeSize = InitCodeSize;
X	    MaxCode = (1 << CodeSize);
X	    ReadMask = MaxCode - 1;
X	    FreeCode = FirstFree;
X	    CurCode = OldCode = Code = ReadCode();
X	    FinChar = CurCode & BitMask;
X	    AddToPixel(FinChar);
X	}
X	else {
X
X/* If not a clear code, then must be data: save same as CurCode and InCode */
X
X	    CurCode = InCode = Code;
X
X/* If greater or equal to FreeCode, not in the hash table yet;
X * repeat the last character decoded
X */
X
X	    if (CurCode >= FreeCode) {
X		CurCode = OldCode;
X		OutCode[OutCount++] = FinChar;
X	    }
X
X/* Unless this code is raw data, pursue the chain pointed to by CurCode
X * through the hash table to its end; each code in the chain puts its
X * associated output code on the output queue.
X */
X
X	    while (CurCode > BitMask) {
X		if (OutCount > 1024)
X		    error("%s: %s is a corrupt GIF file (OutCount).\n", inf);
X		OutCode[OutCount++] = Suffix[CurCode];
X		CurCode = Prefix[CurCode];
X	    }
X
X/* The last code in the chain is treated as raw data. */
X
X	    FinChar = CurCode & BitMask;
X	    OutCode[OutCount++] = FinChar;
X
X/* Now we put the data out to the Output routine.
X * It's been stacked LIFO, so deal with it that way...
X */
X
X	    for (i = OutCount - 1; i >= 0; i--)
X		AddToPixel(OutCode[i]);
X	    OutCount = 0;
X
X/* Build the hash table on-the-fly. No table is stored in the file. */
X
X	    Prefix[FreeCode] = OldCode;
X	    Suffix[FreeCode] = FinChar;
X	    OldCode = InCode;
X
X/* Point to the next slot in the table.  If we exceed the current
X * MaxCode value, increment the code size unless it's already 12.  If it
X * is, do nothing: the next code decompressed better be CLEAR
X */
X
X	    FreeCode++;
X	    if (FreeCode >= MaxCode) {
X		if (CodeSize < 12) {
X		    CodeSize++;
X		    MaxCode *= 2;
X		    ReadMask = (1 << CodeSize) - 1;
X		}
X	    }
X	}
X	Code = ReadCode();
X    }
X
X    free(Raster);
X
X    if (Verbose)
X	fprintf(stderr, "done.\n");
X
X    if (fp != stdin)
X	fclose(fp);
X
X    if (outf == NULL || strcmp(outf, "Standard Output") == 0) {
X	outf = "Standard Output";
X	fp = stdout;
X    }
X    else {
X	if (!(fp = fopen(outf, "w")))
X	    error("%s: %s couldn't be opened for writing.\n", outf);
X    }
X
X    if (Verbose)
X	fprintf(stderr, "Writing rasterfile in %s...", outf);
X
X/* SS: Pixrect Rasterfile output code. */
X    if (pr_dump(Output, fp, &Colormap, RT_STANDARD, 0) == PIX_ERR)
X	error("%s: error writing Sun Rasterfile: %s\n", outf);
X
X    if (Verbose)
X	fprintf(stderr, "done.\n");
X
X    pr_destroy(Output);
X
X    if (fp != stdout)
X	fclose(fp);
X
X    exit(0);
X}
X
X
X/* Fetch the next code from the raster data stream.  The codes can be
X * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
X * maintain our location in the Raster array as a BIT Offset.  We compute
X * the byte Offset into the raster array by dividing this by 8, pick up
X * three bytes, compute the bit Offset into our 24-bit chunk, shift to
X * bring the desired code to the bottom, then mask it off and return it. 
X */
XReadCode()
X{
Xint RawCode, ByteOffset;
X
X    ByteOffset = BitOffset / 8;
X    RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
X    if (CodeSize >= 8)
X	RawCode += (0x10000 * Raster[ByteOffset + 2]);
X    RawCode >>= (BitOffset % 8);
X    BitOffset += CodeSize;
X    return(RawCode & ReadMask);
X}
X
X
XAddToPixel(Index)
Xu_char Index;
X{
X    *(Image + YC * BytesPerScanline + XC) = Index;
X
X/* Update the X-coordinate, and if it overflows, update the Y-coordinate */
X
X    if (++XC == Width) {
X
X/* If a non-interlaced picture, just increment YC to the next scan line. 
X * If it's interlaced, deal with the interlace as described in the GIF
X * spec.  Put the decoded scan line out to the screen if we haven't gone
X * past the bottom of it
X */
X
X	XC = 0;
X	if (!Interlace) YC++;
X	else {
X	    switch (Pass) {
X		case 0:
X		    YC += 8;
X		    if (YC >= Height) {
X			Pass++;
X			YC = 4;
X		    }
X		break;
X		case 1:
X		    YC += 8;
X		    if (YC >= Height) {
X			Pass++;
X			YC = 2;
X		    }
X		break;
X		case 2:
X		    YC += 4;
X		    if (YC >= Height) {
X			Pass++;
X			YC = 1;
X		    }
X		break;
X		case 3:
X		    YC += 2;
X		break;
X		default:
X		break;
X	    }
X	}
X    }
X}
SHAR_EOF
chmod 0644 gif2ras.c || echo "restore of gif2ras.c fails"
fi
if test -f gif2ras.man; then echo "File gif2ras.man exists"; else
echo "x - extracting gif2ras.man (Text)"
sed 's/^X//' << 'SHAR_EOF' > gif2ras.man &&
X.TH GIF2SUN L
X.SH NAME
Xgif2sun \- GIF to Sun rasterfile filter
X.SH SYNOPSIS
X\fBgif2sun\fP [\fB-v\fP] [\fB-q\fP] [\fB-\fP|\fBGIFfile\fP] [\fBrasterfile\fP]
X.SH DESCRIPTION
XGenerate the rasterfile equivalent of a GIF image.
X.SH OPTIONS
X.TP
X.nf
X\fB-v\fP
XSet verbose mode. 
X(Reports status of program via stderr.)
X.fi
X.TP
X.nf
X\fB-q\fP
XDisplay help message. 
X(Usage prompt.)
X.fi
X.TP
X.nf
X\fB-\fP
XForce sourcing of GIF file from stdin. 
X(Only needed when sourcing the GIF file from \fBstdin\fP and 
Xspecifying the output rasterfile on the command line.)
X.fi
X.SH DIAGNOSTICS
XSee verbose mode above.
X.SH AUTHOR
X.nf
XPatrick J. Naughton
XSun Microsystems
X2550 Garcia Ave, MS 14-40
XMountain View, CA 94043
X(415) 336-1080
X.fi
SHAR_EOF
chmod 0644 gif2ras.man || echo "restore of gif2ras.man fails"
fi
exit 0

-- 
Matthew Lee Stier    (mstier@east.Sun.COM)   |
Sun Microsystems ---  RTP, NC  27709-3447    |     "Wisconsin   Escapee"
uucp:  sun!mstier or mcnc!rti!sunpix!matthew |
phone: (919) 469-8300 fax: (919) 460-8355    |