olson@mmm.UUCP (Al Olson) (02/05/86)
Howdy! I'm not sure what constitutes "sufficient response" to a posting, but I have hit my own personal limit. I have included the (shar) source for my MacPaint document to Sun raster file conversion programs following this message. I hope you find this software useful - I ask nothing in return other than you must never flame me for any other net posting :-) Seriously, some useage notes are in order. I will assume you have access to a Sun workstation. If this is the case, you will already have access to Sun's raster file description ( /usr/include/rasterfile.h ) If you do not have a Sun, then the raster file description is of no use anyway. There are five files that I have included following this message. These files are fairly staight-forward C code plus one makefile to build the two programs. These files are: mp2sr.c - Macpaint to Sun raster conversion program sr2mp.c - Sun raster to Macpaint conversion program unpackbits.c - Macintosh tool box routine for byte decompression packbits.c - Macintosh tool box routine for byte compression makefile - for your information The program mp2sr yields a sun raster file in standard format. This file can be displayed in a Shell Tool window or a Graphics Tool window with the program /usr/demo/show. (On our system I found a bug in show which incorrectly handled zero length color maps). Macpaint document are, by definition, 576 X 720 bits (8" X 10"). This is the size of the raster file generated. In order to get Sun raster files to the Mac you must first generate a raster file on the Sun. I used Sun's screendump program to capture the entire frame buffer and another (modified) demo program, /usr/demo/draw. I modified draw to read in raster files as well as create them. The draw program allowed me to crop any portion of the screen dump into a smaller raster file. The program sr2mp will take a Sun raster file of any size and crop/fill it to the size of a MacPaint document. This data is then compressed into a MacPaint file. One last important note. If you have the "macget" and "macput" programs for transfering Mac files to your unix system, you must use the "-d" option. (transfer data file) Don't use the "-u" option (unix mode) as it translates carriage return characters (very bad for data files). If you transfer a Sun raster file to a Mac, you must then reset the file type and creator of the file (via the FileInfo DA, or equivalent) to PNTG (painting) and MPNT (MacPaint), respectively. You may then open the file with MacPaint. Have fun! Alan R. Olson Software and Electronic Resource Center 3M Company --------<snip snip snip>-------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # mp2sr.c # packbits.c # sr2mp.c # unpackbits.c # makefile # This archive created: Wed Feb 5 07:58:12 1986 export PATH; PATH=/bin:$PATH if test -f 'mp2sr.c' then echo shar: will not over-write existing file "'mp2sr.c'" else cat << \SHAR_EOF > 'mp2sr.c' /*****************************************************************\ * * * mp2sr - Mac Paint to Sun Raster bitmap conversion. * * * * This program converts a MacPaint document obtained * * with the command: * * * * % macget -d file * * * * into a SUN raster image file. Conversion is performed * * by typing the command: * * * * % mp2sr file.data file.sun * * * * This file can then be displayed in the sun window * * environment via the demo program: * * * * % /usr/demo/show file.sun * * * \*****************************************************************/ #include <stdio.h> #include <sys/file.h> #include <suntool/tool_hs.h> /* MacPaint image parameters */ #define MACBLKSZ 512 /* number of bytes per Mac disk block */ #define MACWIDTH 72 /* width of MacPaint doc (bytes) */ #define MACHEIGHT 720 /* height of MacPaint doc (lines) */ /* global variables */ int mfd, sfd; /* input/output fds */ int line; /* MacPaint line number */ char *mac_file; /* input MacPaint filename */ char *sun_file; /* output Sun filename */ unsigned char mac_buffer[2 * MACBLKSZ]; /* input mac buffer */ unsigned char *in_ptr; /* mac buffer position */ unsigned char *out_ptr; /* sun bitmap position */ unsigned char sun_bitmap[MACHEIGHT * MACWIDTH]; /* output sun bitmap */ struct rasterfile header; /* sun bitmap header record */ /************************************************\ * * * main - open input and output files and unpack * * input file into output file. * * * \************************************************/ main(argc,argv) int argc; char *argv[]; { int i; /* usage is % mp2sr <input file> <output file> */ if (argc < 3) { printf("mp2sr: usage: mp2sr infile outfile\n"); exit(1); } /* open input and output files */ mac_file = argv[1]; /* get MacPaint file name */ sun_file = argv[2]; /* get Sun bitmap file name */ mfd = open(mac_file, O_RDONLY, 0644); sfd = creat(sun_file, 0644); /* read some input and set up buffer pointers */ read(mfd, mac_buffer, MACBLKSZ); /* skip MacPaint header */ read(mfd, mac_buffer, MACBLKSZ * 2);/* read 1st 2 data blocks */ in_ptr = &mac_buffer[0]; /* reset input pointer */ out_ptr = &sun_bitmap[0]; /* reset output pointer */ /* uncompress MacPaint file one line at a time */ for (line = 0; line < MACHEIGHT; line++) { if (!unpackbits(&in_ptr, &out_ptr, MACWIDTH)) { /* unpackbits was aligned - check for input buffer underflow */ if (in_ptr > &mac_buffer[MACBLKSZ]) { /* now in second half of input buffer - move this half and read new data into this half */ for (i = 0; i < MACBLKSZ; i++) { mac_buffer[i] = mac_buffer[i + MACBLKSZ]; } in_ptr -= MACBLKSZ; read(mfd, &mac_buffer[MACBLKSZ], MACBLKSZ); } } else { /* unpackbits was misaligned - terminate conversion */ printf("mp2sr: conversion terminated at line %d\n", line); break; /* terminate unpacking on error */ } } /* create sun raster file header */ header.ras_magic = RAS_MAGIC; header.ras_width = MACWIDTH * 8; header.ras_height = MACHEIGHT; header.ras_depth = 1; header.ras_length = MACWIDTH * MACHEIGHT; header.ras_type = RT_OLD; header.ras_maptype = RMT_NONE; header.ras_maplength = 0; /* write sun bitmap file */ write(sfd, &header, sizeof(struct rasterfile)); write(sfd, sun_bitmap, MACHEIGHT * MACWIDTH); /* close files and exit */ close(mfd); close(sfd); exit(0); } SHAR_EOF fi # end of overwriting check if test -f 'packbits.c' then echo shar: will not over-write existing file "'packbits.c'" else cat << \SHAR_EOF > 'packbits.c' /********************************************************************\ * * * packbits - a MacIntosh toolbox routine to compress * * data bytes by run length encoding. * * * * Packbits compresses data into the following run length * * encoding method: * * * * +------------+------------+-----~~-----+------------+ * * | run-length | variable length data field | * * +------------+------------+-----~~-----+------------+ * * <-- 1 byte --> * * * * The number of bytes contained in the data field depends on * * the value of the run length when viewed as a SIGNED 8 bit * * integer: * * * * run-length data field contents * * ---------- ------------------- * * >= 0 (run-length + 1) bytes of raw data to * * be copied directly to the output stream. * * < 0 a single byte of repeating data to be * * copied to the output stream (1 - run-length) * * times. * * * * Packbits will compress sequences of identical bytes numbering * * 3 or more. * * * * Inputs: * * src - the source buffer handle * * dst - the destination buffer handle * * bcnt - the number of input bytes * * * * Outputs: * * src - updated for next conversion * * dst - updated for next conversion * * * * Packbits returns the number of bytes copied to the output stream. * * * \********************************************************************/ int packbits(src, dst, bcnt) unsigned char **src; /* source buffer handle */ unsigned char **dst; /* dest buffer handle */ register int bcnt; /* byte count for input */ { register unsigned char *ip = *src; /* local source buffer ptr */ register unsigned char *op = *dst; /* local dest buffer ptr */ register unsigned char *orp; /* output record ptr */ register unsigned char *irp; /* input record ptr */ register int rlen; /* run length value */ int compress; /* flag to indicate compression mode */ int eor; /* end of record flag */ int ocnt; /* output byte count */ /* search input stream for repeating data fields and encode to the output stream until the desired number of input bytes have been processed */ while (bcnt > 0) { /* begin a new output record in the output stream */ compress = 0; irp = ip; orp = op; op += 1; rlen = 0; eor = 0; while ((!eor) && (rlen < bcnt)) { if (compress) { /* compress to output stream and look for non-repeating data fields */ rlen += 1; ip += 1; if (*ip != *irp) { /* end of repeating data - terminate compressed data record and restart in raw mode */ eor = 1; compress = 0; } } else { /* copy raw data to output stream and look for repeating data fields */ if ((*ip == *(ip+1)) && (*ip == *(ip+2))) { /* repeating data field found - terminate raw data record (if non-zero length) and restart in compressed mode */ if (rlen) eor = 1; compress = 1; } else { /* continue copying raw data to output stream */ *op++ = *ip++; rlen += 1; } } } /* output record ended - This occurs when eor is set (indicating the end of a repeating data field) or when the input stream is exhausted (current run length is equal to the remaining input byte count). If eor is set then compress indicates the next record type and cannot be altered. If eor is not set then compress indicates the current record type and can be altered since it is reset when a new line starts. The following logic implements following truth table: | new terminating eor compress | compress action ---------------+--------------------------------------- 0 0 | 1 * term raw output record 0 1 | 0 * term comp output record 1 0 | 0 term comp output record 1 1 | 1 term raw output record (*) - these values were chosen to allow the termination action decision to be simplified. since eor was not set, the new value of compress is unimportant - it is reset to 0 at the beginning of each line. */ compress = (compress ^ ~eor) & 1; /* compress now indicates the NEXT record type, the current is the opposite. Thus, the sense of this expression is reversed for the termination operation. */ if (compress) { /* terminate raw data record */ *orp = rlen - 1; } else { /* terminate compressed data record */ *op++ = *irp; *orp = 1 - rlen; } /* reduce remaining input byte count by current run length */ bcnt -= rlen; } /* update buffer handles and return output byte count */ ocnt = op - *dst; *src = ip; *dst = op; return(ocnt); } SHAR_EOF fi # end of overwriting check if test -f 'sr2mp.c' then echo shar: will not over-write existing file "'sr2mp.c'" else cat << \SHAR_EOF > 'sr2mp.c' /***********************************************************\ * * * sr2mp - Sun Raster bitmap to Mac Paint conversion. * * * * This program converts a SUN raster image file to * * a MacPaint document: * * * * % sr2mp file.sun file.data * * * \***********************************************************/ #include <stdio.h> #include <sys/file.h> #include <suntool/tool_hs.h> /* MacPaint image parameters */ #define MACBLKSZ 512 /* number of bytes per Mac disk block */ #define MACWIDTH 72 /* width of MacPaint doc (bytes) */ #define MACHEIGHT 720 /* height of MacPaint doc (lines) */ /* global variables */ int sfd, mfd; /* input/output fds */ int line; /* MacPaint line number */ char *sun_file; /* output Sun filename */ char *mac_file; /* input MacPaint filename */ unsigned char mac_buffer[MACBLKSZ+((MACWIDTH+1)*MACHEIGHT)]; /* output buffer */ unsigned char *in_ptr; /* sun buffer position */ unsigned char *out_ptr; /* mac buffer position */ unsigned char sun_buffer[MACHEIGHT * MACWIDTH]; /* input sun buffer */ struct rasterfile header; /* sun buffer header record */ int sun_width; /* width (bytes) of sun raster */ int min_width, min_length; /* minimum width, length for reading raster */ int out_size; /* output file size (bytes) */ /************************************************\ * * * main - open input and output files and pack * * input file into output file. * * * \************************************************/ main(argc,argv) int argc; char *argv[]; { int i; /* usage is % sr2mp <input file> <output file> */ if (argc < 3) { printf("sr2mp: usage: sr2mp infile outfile\n"); exit(1); } /* open input and output files */ sun_file = argv[1]; /* get Sun buffer file name */ mac_file = argv[2]; /* get MacPaint file name */ sfd = open(sun_file, O_RDONLY, 0644); mfd = creat(mac_file, 0644); /* read input and set up buffer pointers */ read(sfd, &header, sizeof(struct rasterfile)); /* read raster header */ sun_width = header.ras_length/header.ras_height; /* number of bytes per line */ if (header.ras_maplength > 0) read(sfd, mac_buffer, header.ras_maplength); /* ignore color map */ min_width = (MACWIDTH < sun_width) ? MACWIDTH : sun_width; min_length = (MACHEIGHT < header.ras_height) ? MACHEIGHT : header.ras_height; in_ptr = &sun_buffer[0]; /* reset input pointer */ for (line = 0; line < min_length; line++) { /* fill input buffer cropping to size of macpaint document */ read(sfd, in_ptr, min_width); /* read at most MACWIDTH bytes */ if (min_width < MACWIDTH) /* fill line with zeros */ for (i=0; i<(MACWIDTH-min_width); i++) *(in_ptr+min_width+i) = 0; else if (MACWIDTH < sun_width) /* read extra data into scratch buffer */ read(sfd, mac_buffer, (sun_width-MACWIDTH)); in_ptr += MACWIDTH; } if (min_length < MACHEIGHT) for (line = 0; line < (MACHEIGHT - min_length); line++) { for (i = 0; i < MACWIDTH; i++) *(in_ptr+i) = 0; in_ptr += MACWIDTH; } /* compress sun raster file one line at a time */ in_ptr = &sun_buffer[0]; /* reset input pointer */ out_ptr = &mac_buffer[0]; /* reset output pointer */ for (i = 0; i < MACBLKSZ; i++) *out_ptr++ = 0; /* null macpaint header */ out_size = MACBLKSZ; for (line = 0; line < MACHEIGHT; line++) out_size += packbits(&in_ptr, &out_ptr, MACWIDTH); /* write macpaint buffer to file */ write(mfd, mac_buffer, out_size); /* close files and exit */ close(sfd); close(mfd); exit(0); } SHAR_EOF fi # end of overwriting check if test -f 'unpackbits.c' then echo shar: will not over-write existing file "'unpackbits.c'" else cat << \SHAR_EOF > 'unpackbits.c' /*******************************************************************\ * * * unpackbits - a MacIntosh toolbox routine to uncompress * * bytes which were previously compressed by * * packbits. * * * * Unpackbits decodes data using the following run length * * encoding method: * * * * +------------+------------+-----~~-----+------------+ * * | run-length | variable length data field | * * +------------+------------+-----~~-----+------------+ * * <-- 1 byte --> * * * * The number of bytes contained in the data field depends on * * the value of the run length when viewed as a SIGNED 8 bit * * integer: * * * * run-length data field contents * * ---------- ------------------- * * >= 0 (run-length + 1) bytes of raw data to * * be copied directly to the output stream. * * < 0 a single byte of repeating data to be * * copied to the output stream (1 - run-length) * * times. * * * * Inputs: * * src - the source buffer handle * * dst - the destination buffer handle * * bcnt - the number of output bytes * * * * Outputs: * * src - updated for next conversion * * dst - updated for next conversion * * * * Returns: * * A 1 (true) is returned if the decompression * * was aligned. That is, if the number of bytes * * requested is exactly obtained by interpreting * * run length codes, then it is considered a suc- * * cessful unpack. unpackbits must be called with * * the same byte count which packbits used to * * compress the data. * * * \*******************************************************************/ int unpackbits(src, dst, bcnt) unsigned char **src; /* source buffer handle */ unsigned char **dst; /* dest buffer handle */ register int bcnt; /* byte count for output */ { register unsigned char *ip = *src; /* local source buffer ptr */ register unsigned char *op = *dst; /* local dest buffer ptr */ register int rlen; /* run length value */ register int i; /* index variable */ register int tcnt; /* transfer byte count */ /* read run length from input steam and decode until the desired number of output bytes have been transfered */ while (bcnt > 0) { /* read run length from input stream as an integer */ rlen = *(char *)ip++; if (rlen < 0) { /* negative run lengths indicate that a repeating pattern is to be transfered to the output stream. The next byte of input is the pattern to be repeated. The run length is the negative of the transfer count, minus 1. */ tcnt = 1 - rlen; for (i = 0; i < tcnt; i++) *op++ = *ip; ip++; } else { /* positive run lengths indicate that a stream of raw data is to be copied from the input to the output stream. The run length is the number of bytes to copy, minus 1. */ tcnt = rlen + 1; for (i = 0; i < tcnt; i++) *op++ = *ip++; } /* update remaining byte count */ bcnt -= tcnt; } /* unpack complete - update buffer handles and return bcnt */ *src = ip; *dst = op; return(bcnt); } SHAR_EOF fi # end of overwriting check if test -f 'makefile' then echo shar: will not over-write existing file "'makefile'" else cat << \SHAR_EOF > 'makefile' # # @(#)Makefile 1.4 85/04/21 SMI # CMDS = mp2sr zoom sr2mp CFILES = mp2sr.c zoom.c sr2mp.c packbits.c unpackbits.c LIBS = -lsuntool -lsunwindow -lpixrect CFLAGS = -g LDFLAGS = -g cmds: $(CMDS) mp2sr: mp2sr.o unpackbits.o cc $(LDFLAGS) mp2sr.o unpackbits.o -o mp2sr chmod 755 mp2sr zoom: zoom.o cc $(LDFLAGS) zoom.o -o zoom chmod 755 mp2sr sr2mp: sr2mp.o packbits.o cc $(LDFLAGS) sr2mp.o packbits.o -o sr2mp chmod 755 sr2mp clean: rm *.o core $(CMDS) SHAR_EOF fi # end of overwriting check # End of shell archive exit 0 -- Alan Olson ihnp4!mmm!olson