[net.sources] MacPaint to Sun raster conversion programs

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