This is getx10.c in view mode; [Download] [Up]
/*
* This software is copyrighted as noted below. It may be freely copied,
* modified, and redistributed, provided that the copyright notice is
* preserved on all copies.
*
* There is no warranty or other guarantee of fitness for this software,
* it is provided solely "as is". Bug reports or fixes may be sent
* to the author, who may or may not act on them as he desires.
*
* You may not include this software in a program or other software product
* without supplying the source, or without informing the end-user that the
* source is available for no extra charge.
*
* If you modify this software, you should include a notice giving the
* name of the person performing the modification, the date of modification,
* and the reason for such modification.
*/
/*
* getx10.c - Put RLE images on X display.
*
* Author: Spencer W. Thomas
* Computer Science Dept.
* University of Utah
* Date: Thu Feb 20 1986
* Copyright (c) 1986, University of Utah
*
*/
#ifndef lint
static char rcs_ident[] = "$Id: getx10.c,v 3.0 90/08/03 15:19:23 spencer Exp $";
#endif
#include <stdio.h>
#include <math.h>
#include <X/Xlib.h>
#include "rle.h"
#ifdef USE_STDLIB_H
#include <stdlib.h>
#else
#ifdef VOID_STAR
extern void *malloc();
#else
extern char *malloc();
#endif
extern void free();
#endif
/* Most that can be sent to X in one chunk */
#define MAXSEND 65535 /* 64K */
/*
* Basic magic square for dithering
*/
int magic[4][4] = {
0, 14, 3, 13,
11, 5, 8, 6,
12, 2, 15, 1,
7, 9, 4, 10
};
int dm4[4][4] = {
0, 43, 9, 40,
34, 15, 25, 18,
37, 6, 46, 3,
21, 28, 12, 31 };
int dm16[16][16];
/* define arrow cursor for zoom mode */
#define arrow_width 16
#define arrow_height 16
#define arrow_x_hot 4
#define arrow_y_hot 1
static short arrow_bits[] = {
0x0000, 0x0010, 0x0030, 0x0070,
0x00f0, 0x01f0, 0x03f0, 0x07f0,
0x0ff0, 0x01f0, 0x03b0, 0x0310,
0x0700, 0x0600, 0x0600, 0x0000};
#define arrow_mask_width 16
#define arrow_mask_height 16
static short arrow_mask_bits[] = {
0x0018, 0x0038, 0x0078, 0x00f8,
0x01f8, 0x03f8, 0x07f8, 0x0ff8,
0x1ff8, 0x1ff8, 0x07f8, 0x07b8,
0x0f98, 0x0f00, 0x0f00, 0x0f00};
Cursor arrow_curs;
/*
* Color map, gamma correction map, and lookup tables
*/
Color colmap[256];
int gammamap[256];
rle_pixel ** in_cmap;
int modN[256], divN[256];
int bwflag = 0; /* if non zero, dither in B&W
* Value of 2 means 1-bit system
*/
/*
* Number of color map levels, (square and cube), and number of gradations
* per level.
*/
int levels = 0, levelsq, levelsc;
/*
* Global variables
*/
double disp_gam = 2.5; /* default gammas for display and image */
double img_gam = 1.0;
int iflag = 0; /* flag to tell if gamma was on command line */
int setbg = 0; /* set root background to image? */
int mapflg = 0; /* flag to just load color map */
int usemap = 0; /* Use given color map, don't dither */
int forkflg = 0; /* No fork allows zoom info (middle button) */
int zoomflg = 0; /* build zoom window */
Display * dpy;
Window fbwin, iconwin, zoomwin;
int iconfact, iconrow, iconscan, iconbyte;
int zoomfact = 8;
int zoom_x_dim = 15;
int zoom_y_dim = 15;
int zoom_x_center, zoom_y_center;
int nscan, nrow; /* size of window */
int nbyte; /* size of bitrow for 1-bit displays */
int dbg = 0; /* set if debug mode */
unsigned char *buffer, *iconbuf; /* data storage pointers */
/*****************************************************************
* TAG( main )
*
* Usage:
* getx10 [-{bB}] [-z] [-m] [-f] [-p] [-D] [-d display]
* [-= window-geometry] [-{iI} gamma] [-g gamma] [file]
* Inputs:
* -b: Set the root window background to the resultant image.
* -B: Set the root background, but don't display the image
* in a separate window.
* -z: Create Zoom window also. Any button in image recenters
* zoom. Drag in image resizes zoom window to enclose
* region. Left in zoom window decreases zoom factor.
* Right increases zoom factor. Middle prints position
* info to the terminal, but only if -f is on.
* -m: Just load color map and exit.
* -f: Don't fork after putting image on screen.
* -p: Don't use off-screen memory to speed up redraw.
* -D: Debug mode: print input file as read.
* -w: Black & white: reduce color images to B&W before
* display. Advantage is that smoother shading can
* be achieved.
* -c: Use colors specified in color map. Will try to load
* entire color map. No dithering will be done
* when this option is specified. Actual number
* of entries in color map may be given as a
* picture comment:
* color_map_length=<number of entries in color map>.
* -d display: Specify display name.
* -= window_geometry:
* Specify window geometry (but min size set by file).
* -i gamma: Specify gamma of image. (default 1.0)
* -I gamma: Specify gamma of display image was computed for.
* getx10 will also read picture comments from the input file to determine
* the image gamma. These are
* image_gamma= gamma of image (equivalent to -i)
* display_gamma= gamma of display image was computed for.
* Command line arguments override values in the file.
*
* -g gamma: Specify gamma of display. (default 2.5)
* file: Input Run Length Encoded file. Uses stdin if not
* specified.
* Outputs:
* Puts image on screen.
* Assumptions:
* Input file is in RLE format.
* Algorithm:
* [None]
*/
main(argc, argv)
char **argv;
{
char ** infnames = NULL, *infname = NULL, *display_name = NULL,
* window_geometry = NULL;
FILE * infile = stdin;
int nfile = 0, use_pix = 0,
dflag = 0, gflag = 0, wflag = 0;
if ( scanargs( argc, argv,
"% Bb%- m%- f%- p%- cWw%- D%- n%-levels!d d%-display!s \n\
\t=%-window-geometry!s Ii%-gamma!F g%-gamma!F z%- file%s",
&setbg, &mapflg, &forkflg, &use_pix, &bwflag, &dbg,
&levels, &levels,
&dflag, &display_name,
&wflag, &window_geometry,
&iflag, &img_gam,
&gflag, &disp_gam,
&zoomflg,
&infname ) == 0 )
exit( 1 );
use_pix = ! use_pix;
if ( setbg & !use_pix )
{
fprintf( stderr, "Can't specify -p with -b, -p ignored\n" );
use_pix = 1;
}
if ( setbg == 2 )
forkflg = 1;
if ( iflag == 1 ) /* -i */
img_gam = 1.0 / img_gam;
if ( bwflag == 4 ) /* -c */
{
bwflag = 0;
usemap = 1;
}
/* Would like to be able to use multiple files, but haven't
* figured how to get X to let us. So, use this kludge for now.
*/
if ( infname != NULL )
{
infnames = &infname;
nfile = 1;
}
/*
* For each file, display it.
*/
do {
if ( nfile > 0 )
{
infile = rle_open_f("getx10", *infnames, "r");
get_pic( infile, *infnames, display_name,
window_geometry );
fclose( infile );
infnames++;
nfile--;
}
else
get_pic( stdin, NULL, display_name,
window_geometry );
if ( ! forkflg )
{
if ( fork() == 0 )
{
/*
* Get rid of std fds so rshd will go
* away.
*/
close( 0 );
close( 1 );
close( 2 );
update_pic( use_pix );
break;
}
}
else
{
update_pic( use_pix );
}
} while ( nfile > 0 );
exit( 0 );
/* XCloseDisplay( dpy );*/
}
/*
* Read an image from the input file and display it.
*/
get_pic( infile, infname, display_name, window_geometry )
FILE * infile;
char * infname;
char * display_name;
char * window_geometry;
{
register int i,
y;
int ncolors,
xmin_original;
unsigned char *scan[3];
/*
* Read setup info from file.
*/
rle_dflt_hdr.rle_file = infile;
if ( !mapflg || usemap )
if (rle_get_setup(&rle_dflt_hdr) < 0)
{
fprintf(stderr, "getx10: Error reading setup information from %s\n",
infname ? infname : "stdin");
exit(1);
}
if ( dbg )
rle_debug( 1 );
/* We're only interested in R, G, & B */
RLE_CLR_BIT(rle_dflt_hdr, RLE_ALPHA);
for (i = 3; i < rle_dflt_hdr.ncolors; i++)
RLE_CLR_BIT(rle_dflt_hdr, i);
ncolors = rle_dflt_hdr.ncolors > 3 ? 3 : rle_dflt_hdr.ncolors;
/*
* Open display first time through.
*/
if (dpy == NULL)
{
dpy = XOpenDisplay(display_name);
if (dpy == NULL)
{
fprintf(stderr, "getx10: Can't open display %s\n",
display_name ? "" : display_name);
exit(1);
}
if ( DisplayPlanes() == 1 ) /* b&w display */
bwflag = 2;
}
/* If no image gamma on command line, check comments in file */
if ( ! iflag )
{
char * v;
if ( (v = rle_getcom( "image_gamma", &rle_dflt_hdr )) != NULL )
{
img_gam = atof( v );
/* Protect against bogus information */
if ( img_gam == 0.0 )
img_gam = 1.0;
else
img_gam = 1.0 / img_gam;
}
else if ( (v = rle_getcom( "display_gamma", &rle_dflt_hdr )) != NULL )
{
img_gam = atof( v );
/* Protect */
if ( img_gam == 0.0 )
img_gam = 1.0;
}
}
/*
* Set up the color map.
*/
/* Input map, at least 3 channels */
in_cmap = buildmap( &rle_dflt_hdr, 3, img_gam, 1.0 );
/* Get X color map */
if ( usemap )
load_x_map();
else
init_color();
if ( mapflg )
exit( 0 );
/*
* Compute image size and allocate storage.
*/
nrow = (rle_dflt_hdr.xmax - rle_dflt_hdr.xmin + 1);
if ( bwflag == 2 )
nbyte = ((nrow + 15) / 16) * 2; /* 1 bit display */
else
nbyte = nrow;
nscan = (rle_dflt_hdr.ymax - rle_dflt_hdr.ymin + 1);
buffer = (unsigned char *) malloc(nbyte * nscan);
/*
* Icon wants to be about 50 x 50. Figure out how much smaller than the
* image this is.
*/
iconfact = nrow / 50;
if (iconfact < nscan / 50)
iconfact = nscan / 50;
if ( iconfact == 0 )
iconfact = 1;
iconrow = (1 + nrow / iconfact);
iconscan = (1 + nscan / iconfact);
if ( bwflag == 2 )
{
iconbuf = (unsigned char *)
malloc(BitmapSize( (1 + nrow / iconfact),
(1 + nscan / iconfact) ));
iconbyte = 2 * ((iconrow + 15) / 16);
}
else
{
iconbuf = (unsigned char *) malloc((1 + nrow / iconfact) *
(1 + nscan / iconfact));
iconbyte = iconrow;
}
/*
* Set up for rle_getrow. Pretend image x origin is 0.
*/
for (i = 0; i < 3; i++)
scan[i] = (unsigned char *) malloc(nrow);
rle_dflt_hdr.xmax -= rle_dflt_hdr.xmin;
xmin_original = rle_dflt_hdr.xmin;
rle_dflt_hdr.xmin = 0;
/*
* Get a window of the right size (user positions it with the mouse).
*/
if ( setbg < 2 )
create_window(nrow, nscan, window_geometry);
/*
* For each scan line, dither it and display.
*/
while ((y = rle_getrow(&rle_dflt_hdr, scan)) <= rle_dflt_hdr.ymax)
{
if ( bwflag && ncolors > 1 )
{
map_rgb_to_bw( scan[0], scan[1], scan[ncolors - 1], scan[0],
in_cmap, nrow );
/* Note: map_scanline only uses channel 0 for B&W */
}
else if ( bwflag )
for ( i = 0; i < nrow; i++ )
scan[0][i] = in_cmap[0][scan[0][i]];
else
for (i = 2; i >= ncolors; i--)
bcopy(scan[0], scan[i], nrow);
map_scanline(scan, nrow, 1, y,
&buffer[(rle_dflt_hdr.ymax - y) * nbyte]);
/* Subsample image to create icon */
if ( (rle_dflt_hdr.ymax - y) % iconfact == 0 )
map_scanline( scan, iconrow, iconfact,
(rle_dflt_hdr.ymax - y) / iconfact,
&iconbuf[((rle_dflt_hdr.ymax - y) / iconfact) *
iconbyte] );
if ( setbg < 2 )
put_scanline(&buffer[(rle_dflt_hdr.ymax - y) * nbyte], nrow, 0,
rle_dflt_hdr.ymax - y );
}
/*
* Free temp storage
*/
for (i = 0; i < 3; i++)
free(scan[i]);
rle_dflt_hdr.xmin = xmin_original;
rle_dflt_hdr.xmax += xmin_original;
}
/*
* Track events & redraw image when necessary.
*/
update_pic( use_pix )
{
int i,
npix,
pixscan,
lastscan,
gotpix;
long bufsize,
pixsize;
XEvent rep;
XButtonEvent xkey;
XExposeEvent xex;
int zoom_x_press, zoom_y_press;
Pixmap(*pix)[] = 0;
Bitmap bm;
if (zoomflg)
{
zoom_x_center = nrow / 2;
zoom_y_center = nscan / 2;
update_zoom();
}
/*
* If requested, use off screen pixmap to speed image redisplay. Need to
* allocate it in slices, since can't write whole image to X at once.
*/
if (use_pix)
{
npix = 1 + (nscan * nbyte) / MAXSEND;
pixscan = MAXSEND / nbyte;
pixsize = pixscan * nbyte;
lastscan = nscan % pixscan;
pix = (Pixmap(*)[]) malloc(npix * sizeof(Pixmap));
for (i = 0; i < npix; i++)
if ( bwflag != 2 )
(*pix)[i] = XStorePixmapZ(nrow,
(i == npix - 1) ? lastscan : pixscan,
&buffer[i * nrow * pixscan]);
else
{
bm = XStoreBitmap(nrow,
(i == npix - 1) ? lastscan : pixscan,
&buffer[i * nbyte * pixscan]);
(*pix)[i] = XMakePixmap( bm, 1, 0 );
XFreeBitmap( bm );
}
}
if ( setbg )
{
XChangeBackground( RootWindow, (*pix)[0] );
XClear( RootWindow );
XFlush();
if ( setbg == 2 )
exit( 0 );
}
/*
* Basic event loop: handle expose events on window & icon, and exit on
* (shifted) mouse button event.
*/
for (;;)
{
XNextEvent(&rep);
if (rep.type == ButtonPressed)
{
xkey = *(XButtonEvent *) &rep;
if (zoomflg && (xkey.window == fbwin))
{
zoom_x_press = xkey.x;
zoom_y_press = xkey.y;
}
}
else if (rep.type == ButtonReleased)
{
xkey = *(XButtonEvent *) &rep;
if ( xkey.detail & ShiftMask )
{
if (zoomflg && (xkey.window == zoomwin))
{
/* get rid of just zoom window if shiftclicked */
XDestroyWindow(zoomwin);
zoomflg = 0;
}
else
{
/* Shiftclick in fbwin means exit. */
break;
}
}
if (zoomflg && (xkey.window == fbwin))
{
zoom_x_center = xkey.x;
zoom_y_center = xkey.y;
if ((zoom_x_center != zoom_x_press) &&
(zoom_y_center != zoom_y_press))
{
/* drag to define zoom region */
if (zoom_x_press < zoom_x_center)
{
zoom_x_dim = (zoom_x_center - zoom_x_press);
zoom_x_center = zoom_x_press + (zoom_x_dim / 2);
}
else
{
zoom_x_dim = (zoom_x_press - zoom_x_center);
zoom_x_center = zoom_x_center + (zoom_x_dim / 2);
}
if (zoom_y_press < zoom_y_center)
{
zoom_y_dim = (zoom_y_center - zoom_y_press);
zoom_y_center = zoom_y_press + (zoom_y_dim / 2);
}
else
{
zoom_y_dim = (zoom_y_press - zoom_y_center);
zoom_y_center = zoom_y_center + (zoom_y_dim / 2);
}
XChangeWindow(zoomwin, zoomfact * zoom_x_dim,
zoomfact * zoom_y_dim);
XSetResizeHint( zoomwin, 0, 0, zoomfact, zoomfact );
}
update_zoom();
}
else if (zoomflg && (xkey.window == zoomwin))
{
if (xkey.detail & RightMask)
{
/* increase zoom factor */
zoomfact += 1;
XChangeWindow(zoomwin, zoomfact * zoom_x_dim,
zoomfact * zoom_y_dim);
XSetResizeHint( zoomwin, 0, 0, zoomfact, zoomfact );
}
else if (xkey.detail & LeftMask)
{
/* decrease zoom factor */
if (zoomfact > 1)
{
zoomfact -= 1;
XChangeWindow(zoomwin, zoomfact * zoom_x_dim,
zoomfact * zoom_y_dim);
XSetResizeHint( zoomwin, 0, 0, zoomfact, zoomfact );
}
}
else if (xkey.detail & MiddleMask)
{
if (forkflg)
{
/* can only report pixel status when not forking */
fprintf(stderr, "Position: (%d, %d)\n",
rle_dflt_hdr.xmin +
xkey.x / zoomfact + (zoom_x_center
- (zoom_x_dim / 2)),
(rle_dflt_hdr.ymax
- xkey.y / zoomfact
- (zoom_y_center - (zoom_y_dim / 2))));
fprintf(stderr, "Image crop: (%d, %d) to (%d, %d)\n",
rle_dflt_hdr.xmin, rle_dflt_hdr.ymin,
rle_dflt_hdr.xmax, rle_dflt_hdr.ymax);
fprintf(stderr, "Zoom crop: (%d, %d) to (%d, %d)\n",
rle_dflt_hdr.xmin +
(zoom_x_center - (zoom_x_dim / 2)),
(rle_dflt_hdr.ymax - (zoom_y_dim - 1)
- (zoom_y_center - (zoom_y_dim / 2))),
rle_dflt_hdr.xmin + (zoom_x_dim - 1)
+ (zoom_x_center - (zoom_x_dim / 2)),
(rle_dflt_hdr.ymax
- (zoom_y_center - (zoom_y_dim / 2))));
}
}
}
}
else if (rep.type == ExposeWindow || rep.type == ExposeRegion)
{
xex = *((XExposeEvent *) & rep);
/*
* For icon exposure, just redraw whole thing - it's quick and
* much easier.
*/
if (xex.window == iconwin)
if ( bwflag != 2 )
XPixmapBitsPutZ(iconwin, 0, 0, iconrow, iconscan,
iconbuf, 0, GXcopy, AllPlanes);
else
XBitmapBitsPut(iconwin, 0, 0, iconrow, iconscan,
iconbuf, 1, 0, 0, GXcopy, AllPlanes);
else if (zoomflg && (xex.window == zoomwin))
{
resize_zoom_window();
update_zoom();
}
else
{
/*
* If window has been resized (bigger), don't bother redrawing
* the area outside the image.
*/
if (xex.y + xex.height >= nscan)
xex.height = nscan - xex.y;
/*
* If bitmap, round beginning pixel to beginning of word
*/
if ( bwflag == 2 )
{
xex.width += xex.x; /* remember ending pixel */
xex.x = (xex.x / 16) * 16; /* round down */
xex.width -= xex.x; /* new width */
}
if (xex.x + xex.width >= nrow)
xex.width = nrow - xex.x;
/*
* If no pixmap, do it the slow way.
*/
if (pix == 0)
if ( bwflag == 2 )
for (i = xex.y; i < xex.y + xex.height; i++)
put_scanline( &buffer[i * nbyte + xex.x / 8],
xex.width, xex.x, i );
else
for (i = xex.y; i < xex.y + xex.height; i++)
put_scanline( &buffer[i * nbyte + xex.x],
xex.width, xex.x, i );
else
{
/*
* Pixmaps exist, figure out how many slices are affected
* and which portion of each.
*/
int start = xex.y / pixscan,
end = (xex.y + xex.height) / pixscan,
y = xex.y,
ytop;
register int j;
for (i = start; i <= end; i++)
{
ytop = (i == end) ? xex.y + xex.height
: (i + 1) * pixscan;
/*
* if this slice has a pixmap, blit it. If not, do it
* slow from the buffer.
*/
if ((*pix)[i] != 0)
XPixmapPut(fbwin, xex.x, y - i * pixscan,
xex.x, y,
xex.width, ytop - y, (*pix)[i],
GXcopy, AllPlanes);
else
if ( bwflag == 2 )
for (j = y; j < ytop; j++)
put_scanline( &buffer[j * nbyte +
xex.x / 8],
xex.width, xex.x, j );
else
for (j = y; j < ytop; j++)
put_scanline( &buffer[j * nbyte + xex.x],
xex.width, xex.x, j );
y = ytop;
}
}
}
}
else if ( rep.type != ButtonPressed )
fprintf(stderr, "getx10: Event type %x?\n", rep.type);
}
/*
* Window goes away when we do.
*/
XDestroyWindow(fbwin);
if (zoomflg) XDestroyWindow(zoomwin);
}
update_zoom()
{
unsigned char the_pix;
int i,j;
int zoomx, zoomy;
int x_bottom, x_top;
int y_bottom, y_top;
int zoom_x_corner, zoom_y_corner;
x_bottom = zoom_x_center - (zoom_x_dim / 2);
x_top = x_bottom + zoom_x_dim - 1;
y_bottom = zoom_y_center - (zoom_y_dim / 2);
y_top = y_bottom + zoom_y_dim - 1;
for (j=y_bottom; j<=y_top; j++)
{
zoom_y_corner = (j - y_bottom) * zoomfact;
if ((j < 0) || (j >= nscan))
{
/* dump a blank line */
XPixSet( zoomwin, 0, zoom_y_corner, zoomfact * zoom_x_dim,
zoomfact, colmap[0].pixel );
}
else
{
for ( i= x_bottom; i<=x_top; i++)
{
zoom_x_corner = (i - x_bottom) * zoomfact;
if ((i < 0) || (i >= nrow))
{
/* dump a black pixel */
XPixSet( zoomwin, zoom_x_corner, zoom_y_corner,
zoomfact, zoomfact, colmap[0].pixel );
}
else
{
if ( bwflag != 2 )
the_pix = buffer[j * nbyte + i];
else
the_pix = buffer[j * nbyte + i/8] & (1 << (i % 8)) ?
1 : 0;
XPixSet( zoomwin, zoom_x_corner, zoom_y_corner,
zoomfact, zoomfact, the_pix );
}
}
}
}
}
/*
* Create a window with help from user.
*/
create_window( width, height, window_geometry )
{
OpaqueFrame frame;
char geometry[30];
int zoomwidth, zoomheight;
/*
* Now, make the window.
*/
sprintf( geometry, "=%dx%d+0+0", nrow, nscan );
frame.bdrwidth = 3;
frame.border = WhitePixmap;
frame.background = BlackPixmap;
if ( (fbwin = XCreate( "getx10", "getx10", window_geometry, geometry,
&frame, nrow, nscan )) == NULL )
{
fprintf( stderr, "getx10: Window Create failed\n" );
exit( 1 );
}
XMapWindow( fbwin );
XGetHardwareColor( &colmap[0] ); /* Assume black! */
XPixSet( fbwin, 0, 0, width, height, colmap[0].pixel );
XSetResizeHint( fbwin, width, height, 1, 1 );
XSelectInput( fbwin, ButtonPressed|ButtonReleased|ExposeRegion );
if (zoomflg)
{
arrow_curs = XCreateCursor(arrow_width,arrow_height,arrow_bits,
arrow_mask_bits, arrow_x_hot, arrow_y_hot,
BlackPixel, WhitePixel, GXcopy);
XDefineCursor(fbwin,arrow_curs);
}
iconwin = XCreateWindow( RootWindow, 1, 1,
width / iconfact, height / iconfact, 0, 0, 0 );
XTileRelative( iconwin );
XSetIconWindow( fbwin, iconwin );
XSelectInput( iconwin, ButtonPressed|ButtonReleased|ExposeWindow );
if (zoomflg)
{
zoomwidth = zoomfact * zoom_x_dim;
zoomheight = zoomfact * zoom_y_dim;
sprintf( geometry, "=%dx%d+0+0", zoomwidth, zoomheight );
frame.bdrwidth = 3;
frame.border = WhitePixmap;
frame.background = BlackPixmap;
if ( (zoomwin = XCreate( "getx10 zoom", "getx10", window_geometry,
geometry,
&frame, zoomwidth, zoomheight )) == NULL )
{
fprintf( stderr, "getx10: Zoom window Create failed\n" );
exit( 1 );
}
resize_zoom_window();
XMapWindow( zoomwin );
XPixSet( zoomwin, 0, 0, zoomfact * zoom_x_dim, zoomfact * zoom_y_dim,
colmap[0].pixel );
XSetResizeHint( zoomwin, 0, 0, zoomfact, zoomfact );
XSelectInput( zoomwin, ButtonPressed|ButtonReleased|ExposeRegion );
XDefineCursor(zoomwin,arrow_curs);
}
}
/*
* Map a scanline to 8 bits through the dither matrix.
*
* Inputs:
* rgb: Pointers to buffers containing the red, green,
* and blue color rows.
* n: Length of row.
* s: Skip between pixels in original image.
* y: Y position of row (necessary for dither)
* line: Pointer to output buffer for dithered color data.
*/
#define DMAP(v,x,y) (modN[v]>dm16[x][y] ? divN[v] + 1 : divN[v])
map_scanline( rgb, n, s, y, line )
unsigned char *rgb[3], *line;
{
register int i, col, row;
if ( usemap )
{
register unsigned char *r;
for ( r = rgb[0], i = 0; i < n; i++, r += s )
line[i] = colmap[*r].pixel;
}
else if ( !bwflag )
{
register unsigned char *r, *g, *b;
for ( row = y % 16, col = 0, i = 0, r = rgb[0], g = rgb[1], b = rgb[2];
i < n; i++, r+=s, g+=s, b+=s, col = ((col + 1) & 15) )
line[i] = colmap[DMAP(in_cmap[0][*r], col, row) +
DMAP(in_cmap[1][*g], col, row) * levels +
DMAP(in_cmap[2][*b], col, row) * levelsq].pixel;
}
else if ( bwflag == 1 ) /* gray scale display */
{
register unsigned char *r;
for ( row = y % 16, col = 0, i = 0, r = rgb[0];
i < n; i++, r+=s, col = ((col + 1) & 15) )
line[i] = colmap[DMAP(*r, col, row)].pixel;
}
else /* bitmap display */
{
register unsigned short *l = (unsigned short *)line;
register unsigned char * r;
for ( row = y % 16, col = 0, i = 0, r = rgb[0], *l = 0;
i < n; r+=s, col = ((col + 1) & 15) )
{
*l |= (*r > dm16[col][row] ? 1 : 0) << (i % 16);
if ( (++i % 16) == 0 && i < n )
*++l = 0;
}
}
}
put_scanline( scan, width, x, y )
unsigned char *scan;
{
if ( bwflag != 2 )
XPixmapBitsPutZ( fbwin, x, y, width, 1, scan, 0, GXcopy, AllPlanes );
else
XBitmapBitsPut( fbwin, x, y, width, 1, scan, 1, 0, 0, GXcopy,
AllPlanes );
}
/*****************************************************************
* TAG( map_rgb_to_bw )
*
* Convert RGB to black and white through NTSC transform, but map
* RGB through a color map first.
* Inputs:
* red_row, green_row, blue_row: Given RGB pixel data.
* map: Array[3] of pointers to pixel arrays,
* representing color map.
* rowlen: Number of pixels in the rows.
* Outputs:
* bw_row: Output B&W data. May coincide with one of the
* inputs.
* Algorithm:
* BW = .35*map[0][R] + .55*map[1][G] + .10*map[2][B]
*/
map_rgb_to_bw( red_row, green_row, blue_row, bw_row, map, rowlen )
rle_pixel *red_row;
rle_pixel *green_row;
rle_pixel *blue_row;
rle_pixel *bw_row;
rle_pixel **map;
{
register int x, bw;
for (x=0; x<rowlen; x++)
{
/* 68000 won't store float > 127 into byte? */
/* HP compiler blows it */
bw = .35*map[0][red_row[x]] + .55*map[1][green_row[x]] +
.10*map[2][blue_row[x]];
bw_row[x] = bw;
}
}
/*
* This routine builds the color map (for X window system, details may
* differ in your system. Note particularly the two level color
* mapping: X will give back 216 color map entries, but there is no
* guarantee they are sequential. The dithering code above wants to
* compute a number in 0 - 215, so we must map from this to the X color
* map entry id.
*/
/*
* Initialize the 8 bit color map. Use gamma corrected map.
*/
init_color()
{
int i, rgbmap[256][3], bwmap[256];
#ifdef DEBUG
int j;
#endif
if ( !bwflag )
{
/*
* Figure out how many color map entries we can get
*/
if ( levels == 0 )
levels = 6; /* default starting point */
for ( ; levels >= 2; levels-- )
if ( levels*levels*levels < DisplayCells() )
break;
if ( levels < 2 )
{
fprintf(stderr,
"getx10: This display doesn't have enough color resolution.\
\nWill produce black and white image instead.\n" );
bwflag = 1;
levels = 0;
}
/*
* levels is the maximum number we can get. Now we have to try to
* actually acquire the color map entries.
*/
while ( levels >= 2 )
{
levelsq = levels * levels;
levelsc = levelsq * levels;
dithermap( levels, disp_gam, rgbmap, divN, modN, dm16 );
/*
* Set up the color map entries. We don't yet know the location
* in the map at which each will reside, so init it to 0.
*/
for(i = 0; i < levelsc; i++) {
colmap[i].pixel = 0;
colmap[i].red = rgbmap[i][0] << 8;
colmap[i].green = rgbmap[i][1] << 8;
colmap[i].blue = rgbmap[i][2] << 8;
}
/* Get a color map entry for each color. Assume enough exist! */
for ( i = 0; i < levelsc; i++ )
{
if ( XGetHardwareColor( &colmap[i] ) == 0 )
break;
}
/* Check if the colors are available */
if ( i < levelsc )
{
levels--;
/* Free the colors already obtained */
for ( i--; i >= 0; i-- )
XFreeColors( &colmap[i].pixel, 1, 0 );
continue;
}
break; /* succeeded */
}
if ( levels < 2 && bwflag == 0 )
{
fprintf( stderr,
"getx10: Sorry, not enough color map entries are available.\
\nWill make black & white image instead.\n" );
bwflag = 1;
levels = 0;
}
}
/* Get a B&W color map */
if ( bwflag == 1 )
{
/* Try for lots of levels, give up by factors of 2 until success */
if ( levels == 0 )
if ( DisplayCells() > 16 )
levels = DisplayCells() / 2;
else
levels = DisplayCells() - 4; /* assume this many taken */
for ( ; levels > 1; (levels > 16) ? (levels /= 2) : (levels -= 1) )
{
bwdithermap( levels, disp_gam, bwmap, divN, modN, dm16 );
/*
* Set up the color map entries. We don't yet know the location
* in the map at which each will reside, so init it to 0.
*/
for ( i = 0; i < levels; i++ )
{
colmap[i].pixel = 0;
colmap[i].red = bwmap[i] << 8;
colmap[i].green = colmap[i].red;
colmap[i].blue = colmap[i].red;
}
/* Get a color map entry for each color. Assume enough exist! */
for ( i = 0; i < levels; i++ )
{
if ( XGetHardwareColor( &colmap[i] ) == 0 )
break;
}
/* Check if the colors are available */
if ( i < levels )
{
/* Free the colors already obtained */
for ( i--; i >= 0; i-- )
XFreeColors( &colmap[i].pixel, 1, 0 );
continue;
}
break; /* succeeded */
}
if ( levels < 2 )
bwflag = 2; /* use 1 bit dithering */
else
levelsc = levels; /* remember full range */
}
/* If b&w 1-bit display, just use two colors */
if ( bwflag == 2 )
{
/* All we care about, really, is the magic square */
make_square( 255.0, divN, modN, dm16 );
levels = levelsc = 2;
}
#ifdef DEBUG
printf( "Magic square for %d levels:\n", levels );
for ( i = 0; i < 16; i++ )
{
for ( j = 0; j < 16; j++ )
printf( "%4d", dm16[i][j] );
printf( "\n" );
}
printf( "divN array:\n" );
for ( i = 0; i < 256; i++ )
printf( "%4d%s", divN[i], i % 16 == 15 ? "\n" : "" );
printf( "modN array:\n" );
for ( i = 0; i < 256; i++ )
printf( "%4d%s", modN[i], i % 16 == 15 ? "\n" : "" );
#endif
}
/*****************************************************************
* TAG( load_x_map )
*
* Loads the color map from the input RLE file directly into X window
* system.
* Inputs:
* in_cmap: Global variable containing gamma corrected color
* map from input file.
* Outputs:
* Loads color map (further gamma corrected for display) into
* display. If not enough display map entries are available,
* prints a message and exits the program.
* Assumptions:
* [None]
* Algorithm:
* [None]
*/
load_x_map()
{
int nmap = 0, i, j;
char * mapcom;
int gammamap[256];
if ( (mapcom = rle_getcom( "color_map_length", &rle_dflt_hdr )) )
nmap = atoi( mapcom );
if ( nmap == 0 )
nmap = 1 << rle_dflt_hdr.cmaplen;
/* We won't be using in_cmap, so gamma correct it in place */
for ( i = 0; i < 256; i++ )
gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/disp_gam ));
for ( i = 0; i < nmap; i++ )
for ( j = 0; j < 3; j++ )
in_cmap[j][i] = gammamap[in_cmap[j][i]];
/*
* Set up the color map entries. We don't yet know the location
* in the map at which each will reside, so init it to 0.
*/
for(i = 0; i < nmap; i++) {
colmap[i].pixel = 0;
colmap[i].red = in_cmap[0][i] << 8;
colmap[i].green = in_cmap[1][i] << 8;
colmap[i].blue = in_cmap[2][i] << 8;
if ( XGetHardwareColor( &colmap[i] ) == 0 )
{
fprintf( stderr,
"getx10: Sorry, need at least %d color map entries, only got %d.\n\
Will display image anyway.\n",
nmap, i );
break;
}
}
for ( ; i < 256; i++ )
colmap[i].pixel = 0; /* for "undefined" colors */
}
resize_zoom_window()
{
WindowInfo info;
int xs, ys;
XQueryWindow( zoomwin, &info );
/* truncate to multiple of zoomfact */
xs = zoomfact * ( info.width / zoomfact );
ys = zoomfact * ( info.height / zoomfact );
if ( xs != info.width || ys != info.height )
XChangeWindow( zoomwin, xs, ys );
zoom_x_dim = xs / zoomfact;
zoom_y_dim = ys / zoomfact;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.