[comp.sources.sun] v01i053: pc-paintbrush - convert pc-paintbrush to sunraster format

mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (07/21/89)

Submitted-by:    gfr@cobra.mitre.org (Glenn Roberts)
Posting-number: Volume 1, Issue 53
Archive-name: pc-paintbrush


[ I couldn't test this one out - but here it is.  Note that this
is not a 'shar' format posting. -CWM ]


The program below converts PC-paintbrush images to Sun
rasterfile format.  We've found this to be of some use
for creating images, logos, etc.  Please feel free to place
this program in the Sun-Spots archives.

- Glenn Roberts, The MITRE Corp., McLean VA (703) 883-6820
  gfr@cobra.mitre.org


=-=-=-=- cut here =-=-=-=-=-=
/*
**  pcx2ras -- Convert PC Paintbrush files to Sun rasterfile format
**
**  Version: 2.1
**
**  Usage:  pcx2ras [-d] [-e] [-t type] [input.pcx] [output.pr]
**
**  Options:
**
**	-d	Display the pixrect before outputting to file (user
**		must be in SunView).
**
**	-e	Shorthand for -t 2
**
**	-t type Specify the type of rasterfile to write:
**		0	Old format files compatible with Release 1.1.
**		1	Standard format.
**		2	Run-length encoding of bytes.
**		65535	To experiment with private encodings.
**
**  Authors:
**	Glenn F. Roberts, 703-883-6820 (gfr@cobra.mitre.org)
**	Frederick Kuhl,   703-883-7559 (fkuhl@amadeus.mitre.org)
**		MITRE Corporation
**		7525 Colshire Drive, McLean VA 22102
**
**  History:
**
**  Version 1.0,  11 Aug 87		Frederick Kuhl
**
**  This version handles only EGA images and it treats them as if
**  they were monochrome; specifically, it converts only the first
**  (red) plane of multiplane images and ignores the other planes.
**  Pixels are converted to pixels (and negated).  Coordinate systems
**  of Paintbrush and Sun are the same.  The rasterfile definition
**  requires that each scan line be extended to an integral multiple
**  of 16 bits.  But the number of scan lines is the same.
**
**  Version 2.0,  12 Aug 87		Glenn F. Roberts
**  
**  1)  Program now functions by converting paintbrush file into
**	Sun pixrect form.  This makes it easy to perform any
**	pixrect operation on the image.  Image can be displayed
**	using Sun's screenload program.
**  2)  Input can be either piped (stdin and stdout) or from
**	command line file names. 
**  3)  Color is now supported.  To obtain black and white image
**	pipe the output of this program through rasfilter8to1.
**
**  4)  Image can be previewed using -d switch.
**
**  Version 2.1,  13 Aug 87		Glenn F. Roberts
**
**	-t and -e switches added.
**
**  Version 2.1.1,  6 Jan 89		Glenn F. Roberts
**
**	added SWAB constant so can be compiled for 80386
**	(previously hard-wired for 68000).
*/


#include <stdio.h>
#include <suntool/sunview.h>
#include <suntool/canvas.h>

#define COLORMAP_SIZE 16

/* define SWAB here for 68000 machines */
/* #define SWAB */
char *malloc();

/* This is the header for .PCX files */
struct pcx_hdr_st {
   unsigned char manufacturer;		/* mfg. code (ignore)	*/
   unsigned char version;		/* version should be 5	*/
   unsigned char encoding;		/* should be 1		*/
   unsigned char bitsPerPix;		/* 1 for EGA images	*/
   short window [4];			/* xmin,ymin,xmax,ymax	*/
   short hres;				/* 640 for EGA		*/
   short vres;				/* 350 for EGA		*/
   unsigned char colormap [48];		/* color map		*/
   unsigned char reserved;		/* reserved		*/
   unsigned char nplanes;		/* 4 for EGA		*/
   short bytesPerLine;			/* this IS used!	*/
   short unused [30];			/* filler (to 128)	*/
} hdr;

int display, prtype;
FILE *fin, *fout;


main (argc, argv)
int argc;
char *argv[];
{
   int i;
   struct pixrect *picture, *pcx_load();
   Frame frame;
   Canvas canvas;
   Pixwin *pw;
   colormap_t prcolormap;
   unsigned char red[COLORMAP_SIZE];
   unsigned char green[COLORMAP_SIZE];
   unsigned char blue[COLORMAP_SIZE];

   /* set defaults for user-controlled arguments */
   prtype  = RT_STANDARD;
   display = FALSE;
   fin     = stdin;
   fout    = stdout;

   /* parse any command line arguments */
   parse_arguments(argc, argv);

   /* load pixrect from paintbrush file */
   picture = pcx_load(fin, &hdr);
   fprintf(stderr, "\nImage loaded... width = %d, height = %d\n",
		picture->pr_size.x, picture->pr_size.y);

   /* create corresponding Sun color maps */
   for (i=0; i<COLORMAP_SIZE; i++) {
      red[i]   = hdr.colormap[i*3];
      green[i] = hdr.colormap[i*3+1];
      blue[i]  = hdr.colormap[i*3+2];
   }
   prcolormap.type   = RMT_EQUAL_RGB;
   prcolormap.length = COLORMAP_SIZE;
   prcolormap.map[0] = red;
   prcolormap.map[1] = green;
   prcolormap.map[2] = blue;

   /* if requested, show image to user, then wait for user to 'quit' */
   if (display) {
      frame = window_create(NULL, FRAME,
                WIN_WIDTH,		picture->pr_size.x+10,
                WIN_HEIGHT,		picture->pr_size.y+25,
		FRAME_LABEL,		"Paintbrush",
		0);
      canvas = window_create(frame, CANVAS,
      		CANVAS_RETAINED,	FALSE,
      		CANVAS_AUTO_EXPAND,	TRUE,
      		CANVAS_AUTO_SHRINK,	TRUE,
                CANVAS_WIDTH,           picture->pr_size.x,
                CANVAS_HEIGHT,          picture->pr_size.y,
       		0);
      pw = canvas_pixwin(canvas);
      pw_setcmsname(pw, "paint");
      pw_putcolormap(pw, 0, COLORMAP_SIZE, red, green, blue);
      window_set(canvas,
      		CANVAS_RETAINED,	 TRUE,
      		0);

      pw_rop(pw, 0, 0, picture->pr_size.x, picture->pr_size.y, PIX_SRC, 
		picture, 0, 0);
      window_main_loop(frame);
   }

   /* now write the pixrect output */
   pr_dump(picture, fout, &prcolormap, prtype, prtype==RT_BYTE_ENCODED);

   /* return normally */
   exit(0);
}


/* parse_arguments -- parse command-line arguments (file names
** and switches).
*/
parse_arguments(argc, argv)
int argc;
char *argv[];
{
   int nfiles;

   nfiles = 0;
   while (--argc > 0) {
      ++argv;
      if ((*argv)[0] == '-')
         /* process switches */
         switch ((*argv)[1]) {
            case 'd':
               display = TRUE;
               break;
            case 'e':
               prtype  = RT_BYTE_ENCODED;
               break;
            case 't':
               prtype  = atoi(*++argv);
               --argc;
               break;
         }
      else
         /* process file names */
         switch (nfiles) {
            case 0:
	       if ((fin = fopen(*argv, "r")) == NULL) {
		  fprintf(stderr, "Error opening input file\n");
		  exit(1);
	       }
	       nfiles++;
	       break;
            case 1:
	       if ((fout = fopen(*argv, "w")) == NULL) {
		  fprintf(stderr, "Error opening output file\n");
		  exit(1);
	       }
	       nfiles++;
	       break;
	 }
   }
}


/* pcx_load -- Load paintbrush file into memory pixrect
** (similar to SunView pr_load() routine).
*/
struct pixrect *pcx_load(input, hdr)
FILE *input;
struct pcx_hdr_st *hdr;
{
   int width, height, depth, byte, col, row, i;
   int value;
   struct pixrect *pr;
   char *buff0, *buff1, *buff2, *buff3;
   char byte0, byte1, byte2, byte3;

   /* first load the paintbrush header */
   pcx_load_header(input, hdr);
   width  = hdr->window[2] - hdr->window[0] + 1;
   height = hdr->window[3] - hdr->window[1] + 1;
   depth  = 8;

   /* create a memory pixrect to store the image */
   pr = mem_create(width, height, depth);

   /* allocate line buffers for 4 planes */
   buff0 = malloc (hdr->bytesPerLine);
   buff1 = malloc (hdr->bytesPerLine);
   buff2 = malloc (hdr->bytesPerLine);
   buff3 = malloc (hdr->bytesPerLine);

   /* process each PCX scan line */
   fprintf(stderr, "\nConverting image ...");
   for (row = 0; row < height; row++) {
      get_line(input, buff0, hdr->bytesPerLine);
      get_line(input, buff1, hdr->bytesPerLine);
      get_line(input, buff2, hdr->bytesPerLine);
      get_line(input, buff3, hdr->bytesPerLine);
      for (byte=0; byte<hdr->bytesPerLine; byte++) {
         byte0 = buff0[byte];
         byte1 = buff1[byte];
         byte2 = buff2[byte];
         byte3 = buff3[byte];
         for (col=byte*8+7, i=7; i>=0; i--) {
            value = ((byte3 & 0x01) << 3) +
            	    ((byte2 & 0x01) << 2) +
            	    ((byte1 & 0x01) << 1) +
            	    (byte0 & 0x01);
            if (col < width)
               pr_put(pr, col--, row, value);
            byte0 >>= 1;
            byte1 >>= 1;
            byte2 >>= 1;
            byte3 >>= 1;
         }
      }
   }
   free(buff0);
   free(buff1);
   free(buff2);
   free(buff3);
   return pr;
}


/* get_line -- Get a scan line from paintbrush file
*/
get_line(input, buffer, len)
FILE *input;
char *buffer;
int len;
{
   int i, aByte;

   for (i=0; i<len; ++i) {
      if ((aByte = encgetc(input)) == EOF) {
         fprintf(stderr, "Unexpected EOF\n");
         exit (1);
      }
      *buffer++ = aByte;
   }
}


/* pcx_load_header -- Load header from a paintbrush file
** (similar to SunView pr_load_header() routine).
*/
pcx_load_header(input, hdr)
FILE *input;
struct pcx_hdr_st *hdr;
{
   fread (hdr, sizeof(struct pcx_hdr_st), 1, input);

#ifdef SWAB
   /* byte order is reversed between 8088 and 68000: */
   swab (hdr->window, hdr->window, 8);
   swab (&hdr->hres, &hdr->hres, 2);
   swab (&hdr->vres, &hdr->vres, 2);
   swab (&hdr->bytesPerLine, &hdr->bytesPerLine, 2);
#endif

   fprintf (stderr,"\n*** Header Information:\n\n");
   fprintf (stderr,"mfg. code:           %d\n",	hdr->manufacturer);
   fprintf (stderr,"version:             %d\n",	hdr->version);
   fprintf (stderr,"encoding:            %d\n",	hdr->encoding);
   fprintf (stderr,"bits per pixel:      %d\n",	hdr->bitsPerPix);
   fprintf (stderr,"window:              %d %d %d %d\n", hdr->window[0],
						hdr->window[1],
						hdr->window[2],
						hdr->window[3]);
   fprintf (stderr,"horiz. resolution:   %d\n",	hdr->hres);
   fprintf (stderr,"vert. resolution:    %d\n",	hdr->vres);
   fprintf (stderr,"number of planes:    %d\n",	hdr->nplanes);
   fprintf (stderr,"bytes per line:      %d\n",	hdr->bytesPerLine);
}


/* encgetc -- Return next encoded picture byte from input
** crack the run-length encoding
*/
encgetc (input)
FILE *input;
{
   static int theByte, count = 0;
   int next;

   if (count > 0) {
      --count;
      return theByte;
   } else {
      if ((next=getc(input)) == EOF)
         return EOF;
      if ((next & 0xC0) == 0xC0) {
         count = ((int)next & 0x003F) - 1;
         if ((next=getc(input)) == EOF) {
            fprintf (stderr, "read failed\n");
            exit (1);
         }
         theByte = next;
         return theByte;
      } else
         return next;
   }
}