home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / fbm / src / flpcx.c < prev    next >
C/C++ Source or Header  |  1990-06-24  |  14KB  |  459 lines

  1. /*****************************************************************
  2.  * flpcx.c: FBM Release 1.0 25-Feb-90 Michael Mauldin
  3.  *
  4.  * Copyright (C) 1989,1990 by Michael Mauldin.  Permission is granted
  5.  * to use this file in whole or in part for any purpose, educational,
  6.  * recreational or commercial, provided that this copyright notice
  7.  * is retained unchanged.  This software is available to all free of
  8.  * charge by anonymous FTP and in the UUNET archives.
  9.  *
  10.  * flpcx.c: 
  11.  *
  12.  * CONTENTS
  13.  *    write_pcx (image, stream)
  14.  *    read_pcx (image, stream, mstr, mlen)
  15.  *
  16.  * EDITLOG
  17.  *    LastEditDate = Mon Jun 25 00:17:11 1990 - Michael Mauldin
  18.  *    LastFileName = /usr2/mlm/src/misc/fbm/flpcx.c
  19.  *
  20.  * HISTORY
  21.  * 25-Jun-90  Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
  22.  *    Package for Release 1.0
  23.  *
  24.  * 03-Jan-90  Michael Mauldin (mlm) at Carnegie Mellon University
  25.  *    Added write_pcx, fixed bugs with read_pcx
  26.  *    Beta release (version 0.97) mlm@cs.cmu.edu
  27.  *
  28.  * 12-Nov-88  Michael Mauldin (mlm) at Carnegie-Mellon University
  29.  *    Created.
  30.  *****************************************************************/
  31.  
  32. # include <stdio.h>
  33. # include <math.h>
  34. # include <ctype.h>
  35. # include "fbm.h"
  36.  
  37. /****************************************************************
  38.  * pcx.h: Paintbrush file format header, as per "ZSoft Technical
  39.  *    Reference Manual for Publisher's Paintbrush, PC Paintbrush Plus,
  40.  *    PC Paintbrush and Frieze Graphics.", 1988,  ZSoft corporation,
  41.  *
  42.  *    450 Franklin Rd. Suite 100 / Marietta, GA  30067 / 404-428-0008
  43.  *
  44.  * HISTORY
  45.  * {1}     1-Sep-87  Michael L. Mauldin (mlm) at cognac
  46.  *     Created.
  47.  * 
  48.  ****************************************************************/
  49.  
  50. # define UBYTE    unsigned char    /*  8 bits unsigned        */
  51. # define WORD    short        /* 16 bits signed        */
  52.  
  53. typedef struct pcxstruct {
  54.   UBYTE    Manufacturer;        /* 10 == ZSoft PCX        */
  55.   UBYTE    Version;        /* Version Information        */
  56.                 /*    0 == ver 2.5        */
  57.                 /*    2 == ver 2.8 w/pallete    */
  58.                 /*    3 == 2.8 w/o pallete    */
  59.                 /*    5 == ver 3.0 w/pallete    */
  60.   UBYTE    Encoding;        /* 01 == PCX run-length encoding */
  61.   UBYTE    BitsPerPixel;        /* 8/number of pixels per byte    */
  62.   WORD    Window[4];        /* xmin, ymin, xmax, ymax    */
  63.   WORD    Hres;            /* Horizontal resolution    */
  64.   WORD    Vres;            /* Vertical resolution        */
  65.   UBYTE    Colormap[16][3];    /* Color Pallete, RGB in 0..255    */
  66.   UBYTE    Reserved;        /* Reserved            */
  67.   UBYTE NPlanes;        /* Number of Color Planes    */
  68.   WORD    BytesPerLine;        /* Number of bytes per scan line */
  69.   WORD    Palette;        /* 1 = color/BW, 2 = grayscale  */
  70.   UBYTE    Filler[58];        /* Pad header to 128 bytes    */
  71. } PCXHDR;
  72.  
  73. # define XMIN 0
  74. # define YMIN 1
  75. # define XMAX 2
  76. # define YMAX 3
  77.  
  78. # define CNTMSK 0xc0
  79. # define MAXCNT 0x3f
  80.  
  81. # define swapword(X) ((((X)&0xff) << 8) | (((X) & 0xff00) >> 8))
  82.  
  83. /****************************************************************
  84.  * write_pcx: Write PC Paintbrush format
  85.  ****************************************************************/
  86.  
  87. #ifndef lint
  88. static char *fbmid =
  89. "$FBM flpcx.c <1.0> 25-Jun-90  (C) 1989,1990 by Michael Mauldin, source \
  90. code available free from MLM@CS.CMU.EDU and from UUNET archives$";
  91. #endif
  92.  
  93. write_pcx (image, stream)
  94. FBM *image;
  95. FILE *stream;
  96. { register unsigned char *line = NULL, *bmp;
  97.   register int r, c, i, word, width, height;
  98.   int rowlen;
  99.   PCXHDR phdr;
  100.   
  101.   width = image->hdr.cols;
  102.   height = image->hdr.rows;
  103.  
  104.   if (image->hdr.bits != 1)
  105.   { fprintf (stderr, "write_pcx: can't handle %d bits per pixel\n", image->hdr.bits);
  106.     return (0);
  107.   }
  108.  
  109.   if (image->hdr.physbits != 8)
  110.   { fprintf (stderr, "write_pcx: can't handle %d bits per pixel\n", image->hdr.physbits);
  111.     return (0);
  112.   }
  113.  
  114.   rowlen = (width + 7) / 8;
  115.   line = (unsigned char *) malloc ((unsigned) rowlen);
  116.  
  117.   /* Initialize the PCX header */
  118.   phdr.Manufacturer = 10;    /* 10 == ZSoft PCX              */
  119.   phdr.Version = 3;        /* ver 2.8 with pallette        */
  120.   phdr.Encoding = 1;        /* 1 == PCX run-length encoding */
  121.   phdr.BitsPerPixel = 1;    /* 8/number of pixels per byte    */
  122.   phdr.Window[0] = 1;        /* xmin                         */
  123.   phdr.Window[1] = 1;        /* ymin                         */
  124.   phdr.Window[2] = width;    /* xmax                         */
  125.   phdr.Window[3] = height;    /* ymax                         */
  126.   phdr.Hres = 300;        /* Horizontal resolution (300 dpi) */
  127.   phdr.Vres = 300 * image->hdr.aspect; /* Vertical resolution   */
  128.  
  129.   /* Clear out the color map */
  130.   for (c=0; c<16; c++)
  131.     for (r=0; r<3; r++)
  132.       phdr.Colormap[c][r] = 0;
  133.  
  134.   phdr.Reserved = 0;        /* Reserved            */
  135.   phdr.NPlanes = 1;        /* Number of Color Planes    */
  136.   phdr.BytesPerLine = rowlen;    /* Number of bytes per scan line */
  137.   phdr.Palette = 0;        /* 0=bw, 1=color, 2==grey       */
  138.  
  139.   /* Clear filler */
  140.   for (c=0; c<58; c++) phdr.Filler[c] = 0;
  141.  
  142.   /* PCX uses Little Indian byte order, swap on SUNS, RTs, ... */
  143.   if (machine_byte_order () == BIG)
  144.   { phdr.Window[0] =     swapword (phdr.Window[0]);
  145.     phdr.Window[1] =     swapword (phdr.Window[1]);
  146.     phdr.Window[2] =     swapword (phdr.Window[2]);
  147.     phdr.Window[3] =     swapword (phdr.Window[3]);
  148.     phdr.Hres =          swapword (phdr.Hres);
  149.     phdr.Vres =          swapword (phdr.Vres);
  150.     phdr.BytesPerLine =  swapword (phdr.BytesPerLine);
  151.     phdr.Palette =       swapword (phdr.Palette);
  152.   }
  153.   
  154.   /* Write out header */
  155.   fwrite ((char *) &phdr, sizeof (phdr), 1, stream);
  156.  
  157.   /* For each scan line */
  158.   for (r=0; r<height; r++)
  159.   { 
  160.     /* bmp points to scan line in memory in FBM format */
  161.     bmp = &(image->bm[r * image->hdr.rowlen]);
  162.  
  163.     /* Pack bits into a row of 8 bits per byte, then call writepcxrow */
  164.     for (i=0; i<rowlen; i++)
  165.     { word = 0;
  166.       for (c=0; c<8; c++)
  167.       { word <<= 1;
  168.         word |= *bmp++ ? 1 : 0;
  169.       }
  170.       line[i] = word;
  171.     }
  172.     
  173.     writepcxrow (line, rowlen, stream);
  174.   }
  175.   
  176.   free ((char *) line);
  177.   return (1);
  178. }
  179.  
  180.  
  181. /****************************************************************
  182.  * Writepcxrow
  183.  ****************************************************************/
  184.  
  185. # define CNTMSK    0xc0
  186. # define MAXCNT 0x3f
  187.  
  188. writepcxrow (row, len, stream)
  189. UBYTE *row;
  190. FILE *stream;
  191. { register int cnt, byte;
  192.  
  193.   cnt=1;
  194.   byte = *row++;
  195.   len--;
  196.   
  197.   while (len > 0 || cnt > 0)
  198.   { if (len > 0 && cnt < MAXCNT && *row == byte)
  199.     { cnt++; row++; len--; }
  200.     else
  201.     { if (cnt > 1 || (byte & CNTMSK) == CNTMSK)
  202.       { fputc (CNTMSK | cnt, stream);
  203.     fputc (byte, stream);
  204.       }
  205.       else if (cnt == 1)
  206.       { fputc (byte, stream); }
  207.       
  208.       cnt=0;
  209.  
  210.       if (len > 0)
  211.       { byte = *row++; cnt++; len--; }
  212.     }
  213.   }
  214. }
  215.  
  216. /****************************************************************
  217.  * read_pcx: Read PC Paintbrush format
  218.  ****************************************************************/
  219.  
  220. read_pcx (image, rfile, mstr, mlen)
  221. FBM *image;
  222. FILE *rfile;
  223. char *mstr;
  224. int mlen;
  225. { PCXHDR phdr;
  226.   char *hp;
  227.   register unsigned char *bmp;
  228.   register int k, r, c, bit, byte, mask, width, height, rowlen;
  229.   int depth, ptype, color, enc, clrlen, totalbytes;
  230.   unsigned char *buf, *tail;
  231.  
  232.   /* Read PCX file header */
  233.   hp = (char *) &phdr;
  234.  
  235.   if (mlen > 0) strncpy (hp, mstr, mlen);
  236.  
  237.   if (! fread ((char *) hp+mlen, sizeof (phdr) - mlen, 1, rfile))
  238.   { perror ("read_fbm (header)"); return (0); }
  239.  
  240.   if (phdr.Manufacturer != PCX_MAGIC)
  241.   { fprintf (stderr,
  242.          "Error, file is not a PCX file, magic %02x is not 0a\n",
  243.           phdr.Manufacturer);
  244.     return (0);
  245.   }
  246.   
  247.   /* PCX uses Little Indian byte order, swap on SUNS, RTs, ... */
  248.   if (machine_byte_order () == BIG)
  249.   { phdr.Window[0] =     swapword (phdr.Window[0]);
  250.     phdr.Window[1] =     swapword (phdr.Window[1]);
  251.     phdr.Window[2] =     swapword (phdr.Window[2]);
  252.     phdr.Window[3] =     swapword (phdr.Window[3]);
  253.     phdr.Hres =          swapword (phdr.Hres);
  254.     phdr.Vres =          swapword (phdr.Vres);
  255.     phdr.BytesPerLine =  swapword (phdr.BytesPerLine);
  256.     phdr.Palette =  swapword (phdr.Palette);
  257.   }
  258.   
  259. # ifdef DEBUG
  260.   fprintf (stderr, "Manufacturer        %d\n", phdr.Manufacturer);
  261.   fprintf (stderr, "Version             %d\n", phdr.Version);
  262.   fprintf (stderr, "Encoding            %d\n", phdr.Encoding);
  263.   fprintf (stderr, "BitsPerPixel        %d\n", phdr.BitsPerPixel);
  264.   fprintf (stderr, "Window0             %d\n", phdr.Window[0]);
  265.   fprintf (stderr, "Window1             %d\n", phdr.Window[1]);
  266.   fprintf (stderr, "Window2             %d\n", phdr.Window[2]);
  267.   fprintf (stderr, "Window3             %d\n", phdr.Window[3]);
  268.   fprintf (stderr, "Hres                %d\n", phdr.Hres);
  269.   fprintf (stderr, "Vres                %d\n", phdr.Vres);
  270.   fprintf (stderr, "Reserved            %d\n", phdr.Reserved);
  271.   fprintf (stderr, "NPlanes             %d\n", phdr.NPlanes);
  272.   fprintf (stderr, "BytesPerLine        %d\n", phdr.BytesPerLine);
  273.   fprintf (stderr, "Palette             %d\n", phdr.Palette);
  274. # endif
  275.  
  276.   /* Now extract relevant features of PCX file header */
  277.   width =  phdr.Window[XMAX] - phdr.Window[XMIN] + 1;
  278.   height = phdr.Window[YMAX] - phdr.Window[YMIN] + 1;
  279.   depth =  phdr.NPlanes;
  280.   ptype =  phdr.Version;
  281.   color =  ((ptype == 2) || (ptype == 5)) &&
  282.        phdr.NPlanes > 1 &&
  283.        phdr.Palette != 2;
  284.   enc =    phdr.Encoding;
  285.  
  286.   if (phdr.BitsPerPixel != 1)
  287.   { fprintf (stderr, "%s %d bits per pixel with %d planes\n", 
  288.          "Error in PCX file, can't handle", 
  289.          phdr.BitsPerPixel, depth);
  290.     return (0);
  291.   }
  292.  
  293.   /* Initialize image header */
  294.   image->hdr.cols = width;
  295.   image->hdr.rows = height;
  296.   image->hdr.planes = 1;
  297.   image->hdr.bits = (color || depth > 1) ? 8 : 1;
  298.   image->hdr.physbits = 8;
  299.   image->hdr.rowlen = rowlen = 16 * ((width + 15) / 16);
  300.   image->hdr.plnlen = rowlen * height;
  301.   image->hdr.clrlen = clrlen = color ? (16 * 3) : 0;
  302.   image->hdr.aspect = 1.0;
  303.   image->hdr.title[0] = '\0';
  304.   image->hdr.credits[0] = '\0';
  305.  
  306.   /* Describe what we are doing */
  307.   fprintf (stderr, "Reading PCX file [%dx%d]", width, height);
  308.   if (phdr.BitsPerPixel > 1)
  309.     fprintf (stderr, ", %d bits per pixel", phdr.BitsPerPixel);
  310.   if (depth > 1)
  311.     fprintf (stderr, ", %d planes", depth);
  312.   if (clrlen > 0)
  313.     fprintf (stderr, ", %d colors", clrlen/3);
  314.   fprintf (stderr, "\n");
  315.  
  316.   /* Allocate space */
  317.   alloc_fbm (image);
  318.  
  319.   /* Read colormap if need be */
  320.   if (clrlen > 0)
  321.   { fprintf (stderr, "reading %d (really 16) colors\n", clrlen / 3);
  322.  
  323.     for (c=0; c<16; c++)
  324.     { image->cm[c]    = phdr.Colormap[c][0];
  325.       image->cm[c+16] = phdr.Colormap[c][1];
  326.       image->cm[c+32] = phdr.Colormap[c][2];
  327.     }
  328.   }
  329.  
  330.   /* Zero out the bits */
  331.   bmp = image->bm;
  332.   tail = bmp + image->hdr.plnlen;
  333.  
  334.   while (bmp < tail) { *bmp++ = 0; }
  335.   
  336.   /* Bytes per scan line */
  337.   totalbytes = depth * phdr.BytesPerLine;
  338.   buf = (unsigned char *) malloc ((unsigned) totalbytes);
  339.  
  340.   /* Now read bits */
  341.   for (r=0; r<height; r++)
  342.   { bmp = &(image->bm[r * rowlen]);
  343.   
  344.     /* Read a scan line */
  345.     if (pcxline_read (enc, buf, totalbytes, rfile) == 0)
  346.     { fprintf (stderr, "Premature EOF in row %d, totalbytes %d\n",
  347.            r, totalbytes);
  348.       free ((char *) buf);
  349.       return (1);
  350.     }
  351.     
  352. # ifdef MONDO_DEBUG
  353.     if (r == 211)
  354.     { register int col = 0;
  355.  
  356.       fprintf (stderr, "Row %d, %d bytes:", r, totalbytes);
  357.       for (c=0; c<totalbytes; c++)
  358.       { if (col%32 == 0 || c%(width/8) == 0) { fprintf (stderr, "\n%3d:", c); col = 0; }
  359.         if (col++ %8  == 0) fprintf (stderr, " ");
  360.         fprintf (stderr, "%02x", buf[c]);
  361.       }
  362.       fprintf (stderr, "\n");
  363.       
  364.       col = 0;
  365.       for (c=0; c<width; c++)
  366.       { byte = c/8;
  367.         mask = 0x80 >> (c%8);
  368.     bit = ((buf[byte            ] & mask) ? 1 : 0) | 
  369.           ((buf[byte+(width/8)  ] & mask) ? 2 : 0) | 
  370.           ((buf[byte+2*(width/8)] & mask) ? 4 : 0) | 
  371.           ((buf[byte+3*(width/8)] & mask) ? 8 : 0);
  372.         if (col%50 == 0) { fprintf (stderr, "\n%3d:", c); col=0; }
  373.         if (col++%10 == 0) { fprintf (stderr, " ", c); }
  374.     fprintf (stderr, "%1x", bit);
  375.       }
  376.       fprintf (stderr, "\n");
  377.     }
  378. # endif
  379.  
  380.     /* Decode scan line into row of image */
  381.     if (depth == 1)
  382.     { bmp = &(image->bm[r * rowlen]);
  383.  
  384.       for (c=0; c<width; c++)
  385.       { byte = c>>3;
  386.     mask = 0x80 >> (c&7);
  387.     *bmp++ = (buf[byte] & mask) ? WHITE : BLACK;
  388.       }
  389.     }
  390.     else
  391.     { for (k=0; k<depth; k++)
  392.       { bmp = &(image->bm[r * rowlen]);
  393.     bit = 1 << k;
  394.  
  395.       
  396.         for (c=0; c<width; c++)
  397.     { byte = ((c + k*width)>>3);
  398.           mask = 0x80 >> (c&7);
  399.  
  400.       *bmp++ |= (buf[byte] & mask) ? bit : 0;
  401.         }
  402.       }
  403.     }
  404.   }
  405.  
  406.   if (depth > 1)
  407.   { fprintf (stderr, "Read %d planes successfully\n", depth); }
  408.  
  409.   free ((char *) buf);
  410.  
  411.   return (1);
  412. }
  413.  
  414. /****************************************************************
  415.  * encget (pbyt, pcnt, fid)    Page 10 of ZSoft Manual
  416.  ****************************************************************/
  417.  
  418. encget (pbyt, pcnt, fid)
  419. int *pbyt;    /* Where to place data */
  420. int *pcnt;    /* Where to place count */
  421. FILE *fid;    /* Image file stream */
  422. { register int i;
  423.  
  424.   *pcnt = 1;        /* Safety play */
  425.   if (EOF == (i = getc (fid))) return (EOF);
  426.   if (CNTMSK == (CNTMSK & i))
  427.   { *pcnt = MAXCNT & i;
  428.     if (EOF == (i = getc (fid))) return (EOF);
  429.   }
  430.   *pbyt = i;
  431.   return (0);
  432. }
  433.  
  434. /****************************************************************
  435.  * pcxline_read
  436.  ****************************************************************/
  437. pcxline_read (enc, buf, total, fid)
  438. unsigned char *buf;    /* Output buffer */
  439. int total;        /* Bytes in one scan line */
  440. FILE *fid;        /* Input stream */
  441. { int data, count, len=0;
  442.  
  443.   if (enc != 1)
  444.   { return (fread ((char *) buf, 1, total, fid)); }
  445.  
  446.   while (len < total)
  447.   { if (EOF == encget (&data, &count, fid))
  448.       return (len);
  449.     while (count > 0) { *buf++ = data; len++; count--; }
  450.   }
  451.   
  452.   if (count > 0)
  453.   { fprintf (stderr, "%s, after %d bytes, lost %d bytes of %02x\n",
  454.          "Error in reading scan lines", total, count, data);
  455.   }
  456.  
  457.   return (len);
  458. }
  459.