Graphics (bit map) on a 3b1 -- how?
egray at fthood.UUCP
egray at fthood.UUCP
Fri Jan 6 23:36:00 AEST 1989
How about a "readmac" clone? It has some good simple examples of how the
bit mapped stuff works.
Emmet P. Gray US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV
Directorate of Engineering & Housing
Environmental Management Office
Fort Hood, TX 76544-5057
-------------------------------------------------------------------------------
/*
* Program to display and print Macintosh MacPaint images
*
* Emmet P. Gray US Army, HQ III Corps & Fort Hood
* ...!ethos!gizzmo!fthood!egray Attn: AFZF-DE-ENV
* ...!ihnp4!uiucuxc!fthood!egray Directorate of Engineering & Housing
* Environmental Management Office
* Fort Hood, TX 76544-5057
*/
#include <stdio.h>
#include <tam.h>
#define INVERSE
unsigned short pic[720][36];
int row, col, next_row, hi_byte = 1;
/* table for transposing bits */
unsigned char xp_table[256] = {0, 128, 64, 192, 32, 160, 96, 224, 16, 144,
80, 208, 48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104, 232, 24,
152, 88, 216, 56, 184, 120, 248, 4, 132, 68, 196, 36, 164, 100, 228,
20, 148, 84, 212, 52, 180, 116, 244, 12, 140, 76, 204, 44, 172, 108,
236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130, 66, 194, 34, 162,
98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 10, 138, 74, 202, 42,
170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134, 70, 198,
38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 14, 142, 78,
206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 1, 129,
65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 9,
137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117,
245, 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189,
125, 253, 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51,
179, 115, 243, 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219,
59, 187, 123, 251, 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87,
215, 55, 183, 119, 247, 15, 143, 79, 207, 47, 175, 111, 239, 31, 159,
95, 223, 63, 191, 127, 255};
main(argc, argv)
int argc;
char *argv[];
{
FILE *fp;
int choice, next;
short win;
char name[80];
winit();
if (!iswind()) {
fprintf(stderr, "Sorry, readmac requires a bit-mapped screen\n");
wexit(1);
}
/* create the window */
win = wcreate(1, 0, 24, 80, BORDVSCROLL);
clear();
wgoto(win, 0, 0);
if (argc != 2) {
wprintf(win, "Readmac - program to display and print Macintosh MacPaint images\n\n");
wprintf(win, "up move the image up 20 pixel rows\n");
wprintf(win, "down move the image down 20 pixel rows\n");
wprintf(win, "P Print the image\n");
wprintf(win, "L Load another image\n");
wprintf(win, "Q Quit\n\n");
wprintf(win, "Enter the file name : ");
wgets(win, name);
}
else
strcpy(name, argv[1]);
start:
row = 0;
col = 0;
next_row = 0;
if (!(fp = fopen(name, "r"))) {
wprintf(win, "Can't open '%s' for read\n", name);
wprintf(win, "Enter the file name [or control-c to quit] : ");
wgets(win, name);
goto start;
}
wprintf(win, "Reading the data file...\n");
if (read_data(fp)) {
wprintf(win, "Bad file or not in MacPaint format\n", name);
sleep(3);
clean_up(win);
wexit(1);
}
fclose(fp);
clear();
/* show first 240 rows */
wrastop(win, pic, 72, 0, 0, 0, 0, 0, 0, 576, 240, SRCSRC, DSTSRC, 0);
wprintf(win, "\033[=1C"); /* turn cursor off */
while (1) {
choice = wgetc(win);
switch (choice) {
case 033: /* escape character '^[' */
next = wgetc(win);
if (next != '[') {
wputc(win, 07);
break;
}
next = wgetc(win);
switch (next) {
case 'B': /* roll down key */
case 'S': /* arrow on border */
roll(1, win);
break;
case 'A': /* roll up key */
case 'T': /* arrow on border */
roll(0, win);
break;
default:
wputc(win, 07);
break;
}
break;
case 'P':
case 'p': /* print the file */
wgoto(win, 0, 0);
print_it(win);
clear();
/* repaint the image */
wrastop(win, pic, 72, 0, 0, 0, 0, 0, 0, 576, 240, SRCSRC, DSTSRC, 0);
break;
case 'L':
case 'l': /* load another image */
wgoto(win, 0, 0);
wprintf(win, "\033[=0C");
wprintf(win, "Enter the new file name : ");
wgets(win, name);
wprintf(win, "\033[=1C");
goto start;
case 3:
case 'Q':
case 'q': /* quit */
clean_up(win);
wexit(0);
break;
default:
wputc(win, 07);
break;
}
}
}
/*
* The data file uses a straight forward compression technique. If the
* 'index' byte is greater than 127, then repeat the next character
* (257-index) times. If the 'index' byte is less than 127, then read
* the next (index+1) bytes.
*/
read_data(fp)
FILE *fp;
{
int count, repeat, c;
unsigned char byte;
/* skip the 640 byte header */
if (fseek(fp, 640L, 0))
return(1);
count = 0;
repeat = 0;
while ((c = fgetc(fp)) != EOF) {
/* ignore trash after row 720 */
if (row == 720)
return(0);
byte = c & 0xff;
if (count) { /* read the next 'count' bytes */
count--;
store_video(byte);
continue;
}
if (repeat) { /* repeat the byte */
while (repeat--)
store_video(byte);
repeat = 0;
continue;
}
if (byte > 127) { /* repeat factor */
repeat = 257 - byte;
if (repeat > 72)
return(1);
continue;
}
count = byte + 1; /* count factor */
if (count > 72)
return(1);
}
/* short file ? */
if (row < 720)
return(1);
return(0);
}
/*
* The image is stored in a two dimensional array of unsigned short
* integers 36 wide by 720 long. The 8 bit char to 16 bit short integer
* conversion is reversed (typical of Intel vs. Motorola chips). In
* addition, the byte order of the bit-mapped screen on the Macintosh is
* right to left (meaning the most significant bit appears on the screen
* to the left) and ours is left to right. The byte transposition
* table 'xp_table[]' is used to transpose the bit patterns (much faster
* than rotating bits 180 degrees).
*/
store_video(byte)
unsigned char byte;
{
static int previous;
if (hi_byte) {
/* xp_table[] rotates it 180 degrees */
#ifdef INVERSE
previous = 0xff - xp_table[byte];
#else INVERSE
previous = xp_table[byte];
#endif INVERSE
hi_byte = 0;
return;
}
hi_byte = 1;
/* reverse the byte order */
#ifdef INVERSE
pic[row][col] = ((0xff - xp_table[byte]) << 8) + previous;
#else INVERSE
pic[row][col] = (xp_table[byte] << 8) + previous;
#endif INVERSE
col++;
if (col == 36) {
row++;
col = 0;
}
return;
}
/*
* roll up or down 20 pixels
*/
roll(direction, win)
int direction;
short win;
{
unsigned short *npic;
if (direction) { /* down 20 */
next_row += 20;
if (next_row > 480) {
next_row = 480;
wputc(win, 07);
}
}
else { /* up 20 */
next_row -= 20;
if (next_row < 0) {
next_row = 0;
wputc(win, 07);
}
}
/* new pointer to pic[] array */
npic = &pic[next_row][0];
wrastop(win, npic, 72, 0, 0, 0, 0, 0, 0, 576, 240, SRCSRC, DSTSRC, 0);
return;
}
/*
* set up a borderless window
*/
clean_up(win)
short win;
{
WSTAT wbuf;
wprintf(win, "\033[=0C"); /* turn cursor back on */
clear();
wbuf.begy = 1;
wbuf.begx = 0;
wbuf.height = 24;
wbuf.width = 80;
wbuf.uflags = NBORDER;
wsetstat(win, &wbuf);
wgoto(win, 0, 0);
wdelete(win);
return;
}
/*
* get a string from a window, analogous to gets() except we do the
* echoing, editing, and control-c handling
*/
wgets(win, string)
short win;
char *string;
{
int c;
char *first;
first = string;
while ((c = wgetc(win)) != '\r') {
/* if control c */
if (c == 3) {
clean_up(win);
wexit(0);
}
/* if backspace */
if (c == 8) {
string--;
if (string < first)
string = first;
else
wputc(win, c);
continue;
}
/* provide the echo ourselves */
wputc(win, c);
*string++ = (c & 0177);
}
wprintf(win, "\r\n");
*string = '\0';
return;
}
/*
* Print the image on a dot matrix printer. The 'start' string sets the
* vertical line spacing to 8/72 inch, the 'middle' strings sends the
* code to print the next 576 characters as graphics, and the 'end' string
* returns the vertical line spacing to normal. On some printers, bit 0
* is at the top, others it's on the bottom.
*/
print_it(win)
short win;
{
FILE *lp;
int ptr_row, up_side_down;
char *start, *middle, *end, printer[10];
unsigned char *ptr_str, *get_str();
wprintf(win, "Choice of printers\n\n");
wprintf(win, "1) Epson FX\n");
wprintf(win, "2) Apple DMP/NEC 8023\n");
wprintf(win, "3) Gemini 10\n");
wprintf(win, "4) IBM Graphics Printer\n");
wprintf(win, "5) other\n\n");
again:
wprintf(win, "Enter choice [1-5] : ");
wgets(win, printer);
switch (*printer) {
case 0: /* carriage return alone */
return;
case '1': /* Epson */
start = "\033A\010";
middle = "\033*\004@\002";
end = "\0332";
up_side_down = 0;
break;
case '2': /* Apple DMP/NEC 8023 */
start = "\033T16";
middle = "\033G0576";
end = "\033B";
up_side_down = 1;
break;
case '3': /* Gemini 10 */
start = "\0333\020";
middle = "\033L@\002";
end = "\0332";
up_side_down = 0;
break;
case '4': /* IBM Graphics Printer */
start = "\033A\010";
middle = "\033L@\002";
end = "\0332";
up_side_down = 0;
break;
case '5': /* Other */
start = "";
middle = "";
end = "";
up_side_down = 0;
break;
default: /* oops! */
goto again;
}
/*
* Please note, a 'popen()' to the '/usr/bin/lp' command WILL NOT WORK
* since the device driver for the '/dev/lp' will do post-processing and
* CR-LF translations.
*/
if (!(lp = fopen("/dev/rawlp", "w"))) {
wprintf(win, "Can't open /dev/rawlp\n");
sleep(3);
clean_up(win);
wexit(1);
}
fputs(start, lp);
for (ptr_row = 0; ptr_row < 720; ptr_row += 8) {
/* get a 576 char raster */
ptr_str = get_str(ptr_row, up_side_down);
fputs(middle, lp);
/* spit out the raster */
fwrite(ptr_str, sizeof *ptr_str, 576, lp);
fputc('\n', lp);
}
fputs(end, lp);
fputc(014, lp);
pclose(lp);
return;
}
/*
* Convert that mess in the pic[] array into a printer raster of 576 chars.
* A byte sent to a printer makes a 8 pixel vertical line, however the same
* byte sent to the screen makes a 8 pixel horizontal line. Therefore we
* must 'rotate' the bit pattern of 8 rows of integers by 90 degrees to form
* a printer raster of 16 characters. (Can't use a translation table now,
* since the rotation actualy involves combining bits from different bytes)
*/
unsigned char *
get_str(ptr_row, up_side_down)
int ptr_row;
int up_side_down;
{
static unsigned char raster[576];
int ras_col, offset, ras_row, bit, mult;
unsigned char pat;
for (ras_col = 0; ras_col < 36; ras_col++) {
/* clear previous pattern */
for (bit = 0; bit < 16; bit++)
raster[(ras_col * 16) + bit] = 0;
/* for each stack of 8 */
for (offset = 0; offset < 8; offset++) {
ras_row = ptr_row + offset;
/* rotate bit pattern 90 degrees */
for (bit = 0; bit < 16; bit++) {
mult = 1 << bit;
#ifdef INVERSE
if ((0xffff - pic[ras_row][ras_col]) & mult) {
#else INVERSE
if (pic[ras_row][ras_col] & mult) {
#endif INVERSE
if (up_side_down)
pat = 1 << offset;
else
pat = 1 << (7 - offset);
raster[(ras_col * 16) + bit] |= pat;
}
}
}
}
return(raster);
}
More information about the Unix-pc.general
mailing list