home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / MM1 / CMDS / pcxview_mm1.lzh / PCXVIEW / pcxdecode.c < prev    next >
C/C++ Source or Header  |  1997-04-18  |  8KB  |  280 lines

  1. #include    <stdio.h>
  2.  
  3. #define PCX_MAGIC   0x0a
  4. #define PCX_256_COLORS  0x0c
  5.  
  6. #define MAXCOLORS       256
  7. #define MAXPLANES   4
  8.  
  9. extern errno, iflag, hflag;
  10. extern short ncolors;
  11. extern unsigned char colormap[256][3];
  12.  
  13. char *vers[] = {"2.5", "?", "2.8 with palette", "2.8 without palette", "?", "3.0"};
  14.  
  15. struct {
  16.     char Manufacturer;
  17.     char Version;
  18.     char Encoding;
  19.     char BitsPerPixel;
  20.     short Xmin, Ymin, Xmax, Ymax;
  21.     short HorizontalRes, VerticalRes;
  22.     char Colormap[16][3];
  23.     char Reserved;
  24.     char Planes;
  25.     short BytesPerLine;
  26.     short PaletteInfo;
  27.     char Filler[58];
  28. } head;
  29.  
  30. FILE *ifp;
  31. int Version, i, y;
  32. short Xmin, Ymin, Xmax, Ymax;
  33. int Width, Height, Planes, BitsPerPixel;
  34. short BytesPerLine;
  35. unsigned char *pcximage, *pcxplanes, *pcxpixels, *pixels;
  36.  
  37. pcx_read(ifname)
  38. char *ifname;
  39. {
  40.    short HorizontalRes, VerticalRes, PaletteInfo;
  41.    
  42.    if ( iflag )
  43.       ifp = stdin;
  44.    else
  45.       ifp = fopen(ifname, "r");
  46.    if (ifp == NULL)
  47.       exit(_errmsg(errno, "cannot open %s\n", ifname));
  48.  
  49.    /* read the PCX header */
  50.    if ( fread(&head, sizeof(head), 1, ifp) == 0 )
  51.       exit(_errmsg(errno, "cannot read header of %s\n", ifname));
  52.  
  53.    if (head.Manufacturer != PCX_MAGIC)
  54.       exit(_errmsg(errno, "%s is not a PCX file\n", ifname));
  55.  
  56.    Version = head.Version;      /* get version #           */
  57.  
  58.    if (head.Encoding != 1)       /* check for PCX run length encoding   */
  59.       exit(_errmsg(errno, "%s has unknown encoding scheme\n", ifname));
  60.  
  61.    BitsPerPixel = head.BitsPerPixel;
  62.    Xmin = swab(head.Xmin);
  63.    Ymin = swab(head.Ymin);
  64.    Xmax = swab(head.Xmax);
  65.    Ymax = swab(head.Ymax);
  66.  
  67.    Width = (Xmax - Xmin) + 1;
  68.    Height = (Ymax - Ymin) + 1;
  69.  
  70.    /* get the 16-color color map */
  71.    ncolors = 16;
  72.    memcpy(colormap, head.Colormap, 16*3);
  73.  
  74.    if (BitsPerPixel == 1
  75.        && colormap[0][0] == 0 && colormap[0][1] == 0 && colormap[0][2] == 0
  76.        && colormap[1][0] == 0 && colormap[1][1] == 0 && colormap[1][2] == 0)
  77.       colormap[1][0] = colormap[1][1] = colormap[1][2] = 255;
  78.  
  79.    Planes = head.Planes;       /* # of color planes     */
  80.    BytesPerLine = swab(head.BytesPerLine); /* # of bytes per line   */
  81.    HorizontalRes = swab(head.HorizontalRes);
  82.    VerticalRes = swab(head.VerticalRes);
  83.    PaletteInfo = swab(head.PaletteInfo);
  84.  
  85.    if (hflag) {
  86.       fprintf(stderr, "\nFile: %s\n", ifname);
  87.       fprintf(stderr, "Version: %d (%s)\n", Version, vers[Version]);
  88.       fprintf(stderr, "Encoding: %d (RLE)\n", head.Encoding);
  89.       fprintf(stderr, "BitsPerPixel: %d\n", BitsPerPixel);
  90.       fprintf(stderr, "Xmin x Ymin = %d x %d\n", Xmin, Ymin);
  91.       fprintf(stderr, "Xmax x Ymax = %d x %d\n", Xmax, Ymax);
  92.       fprintf(stderr, "Width x Height = %d x %d\n", Width, Height);
  93.       fprintf(stderr, "HorizontalRes x VerticalRes = %d x %d\n",
  94.                        HorizontalRes, VerticalRes);
  95.       fprintf(stderr, "Planes: %d\n", head.Planes);
  96.       fprintf(stderr, "BytesPerLine: %d\n", BytesPerLine);
  97.       fprintf(stderr, "PaletteInfo: %d %s\n", PaletteInfo,
  98.           PaletteInfo == 1 ? "(color/BW)" : PaletteInfo == 2 ? "(grayscale)" : "");
  99.       fprintf(stderr, "Actual number of colors = %d\n", 1 << BitsPerPixel);
  100.    }
  101.  
  102.    /* check that we can handle this image format */
  103.    switch (BitsPerPixel) {
  104.       case 1:
  105.          if (Planes > MAXPLANES)
  106.             exit(_errmsg(errno, "can't handle image with more than 4 planes\n"));
  107.          break;
  108.  
  109.       case 2:
  110.       case 4:
  111.       case 8:
  112.          if (Planes == 1)
  113.             break;
  114.       default:
  115.          exit(_errmsg(errno, "can't handle %d bits per pixel image with %d planes\n",
  116.                       BitsPerPixel, Planes));
  117.    }
  118.  
  119.    if ( hflag ) {
  120.       fclose(ifp);
  121.       return;
  122.    }
  123.    
  124.    /* read the pcx format image */
  125.    pcximage = (unsigned char *) malloc(BytesPerLine * Planes * Height);
  126.    if ( pcximage == NULL )
  127.       exit(_errmsg(errno, "cannot allocate image\n"));
  128.  
  129.    memset(pcximage, 0, BytesPerLine * Planes * Height);
  130.    read_pcx_image(pcximage);
  131.  
  132.    /* 256 color images have their color map at the end of the file preceeded
  133.     * by a magic byte */
  134.    if (BitsPerPixel == 8) {
  135.       int c;
  136.       ncolors = 256;
  137.       do
  138.          c = getc(ifp);
  139.       while ( c != PCX_256_COLORS && c!= EOF);
  140.  
  141.       if ( ferror(ifp) || feof(ifp) ) {
  142.          fprintf(stderr, "warning: error reading color map: using grayscale\n");
  143.          for ( c = 0; c < 256; c++ )
  144.              colormap[c][0] = colormap[c][1] = colormap[c][2] = i;
  145.       } else 
  146.          if ( fread(colormap, MAXCOLORS*3, 1, ifp) == 0 )
  147.             exit(_errmsg(errno, "cannot read appended color map\n"));
  148.    }
  149.  
  150.    pixels = (unsigned char *) malloc(Width * Height);
  151.    if (pixels == NULL)
  152.       exit(_errmsg(errno, "cannot allocate array\n"));
  153.  
  154.    pcxpixels = pixels;
  155.  
  156.    /* convert the image */
  157.    for (y = 0; y < Height; y++) {
  158.       pcxplanes = pcximage + (y * BytesPerLine * Planes);
  159.  
  160.       if (Planes == 1)
  161.          pcx_unpack_pixels(pcxpixels, pcxplanes);
  162.       else
  163.          pcx_planes_to_pixels(pcxpixels, pcxplanes);
  164.       pcxpixels += Width;
  165.    }
  166.    free(pcximage);
  167.    fclose(ifp);
  168. }
  169.  
  170. read_pcx_image(pcximage)                        /* -> pcximage */
  171. register unsigned char *pcximage;
  172. {
  173.    register int c, nbytes, count;
  174.  
  175.    nbytes = BytesPerLine * Planes * Height;
  176.  
  177.    while (nbytes > 0) {
  178.       c = getc(ifp);
  179.       if (c == EOF)
  180.          exit(_errmsg(errno, "unexpected end of file\n"));
  181.  
  182.       if ((c & 0xc0) != 0xc0) {
  183.          *pcximage++ = c;
  184.          --nbytes;
  185.          continue;
  186.       }
  187.       count = c & 0x3f;
  188.       c = getc(ifp);
  189.       if (c == EOF)
  190.          exit(_errmsg(errno, "unexpected end of file\n"));
  191.  
  192.       if (count > nbytes)
  193.          exit(_errmsg(errno,
  194.              "repeat count spans end of image, count = %d, nbytes = %d\n",
  195.               count, nbytes));
  196.  
  197.       nbytes -= count;
  198.       while (--count >= 0)
  199.          *pcximage++ = c;
  200.    }
  201. }
  202.  
  203. /*
  204.  * convert multi-plane format into 1 pixel per byte
  205.  */
  206. pcx_planes_to_pixels(pixels, bitplanes) /* pcximage -> pixels */
  207. unsigned char *pixels;
  208. register unsigned char *bitplanes;
  209. {
  210.    int i, npixels;
  211.    register unsigned char *p;
  212.    short bytes = BytesPerLine;
  213.    register unsigned char bits, pixbit, mask;
  214.    register short j;
  215.  
  216.    if (Planes > MAXPLANES)
  217.       exit(_errmsg(errno, "can't handle more than 4 planes\n"));
  218.    if (BitsPerPixel != 1)
  219.       exit(_errmsg(errno, "can't handle more than 1 bit per pixel\n"));
  220.  
  221.    /* clear the pixel buffer */
  222.    npixels = (bytes * 8) / BitsPerPixel;
  223.    p = pixels;
  224.    while (--npixels >= 0)
  225.       *p++ = 0;
  226.  
  227.    /* do the format conversion */
  228.    for (i = 0; i < Planes; i++) {
  229.  
  230.       p = pixels;
  231.       pixbit = (1 << i);
  232.  
  233.       j = bytes;
  234.       while ( --j >= 0 ) {
  235.          bits = *bitplanes++;
  236.          for (mask = 0x80; mask != 0; mask >>= 1, p++) {
  237.             if (bits & mask)
  238.                *p |= (pixbit << 4);
  239.             mask >>= 1;    
  240.             if (bits & mask)
  241.                *p |= pixbit;
  242.          }
  243.       }
  244.    }
  245. }
  246.  
  247. /*
  248.  * convert packed pixel format into 1 pixel per byte
  249.  */
  250. pcx_unpack_pixels(pixels, bitplanes)    /* pcximage -> pixels */
  251. register unsigned char *pixels;
  252. register unsigned char *bitplanes;
  253. {
  254.    register unsigned char bits;
  255.    register short bytes = BytesPerLine;
  256.  
  257.    switch ( BitsPerPixel ) {
  258.    case 8:
  259.    case 4:
  260.       while (--bytes >= 0)
  261.          *pixels++ = *bitplanes++;
  262.       break;
  263.    case 2:
  264.       while (--bytes >= 0) {
  265.          bits = *bitplanes++;
  266.          *pixels++ = ((bits & 0xc0) >> 2) | (bits & 0x30);
  267.          *pixels++ = ((bits & 0x30) << 2) | (bits & 0x03);
  268.       }
  269.       break;
  270.    case 1:
  271.       while (--bytes >= 0) {
  272.          bits = *bitplanes++;
  273.          *pixels++ = ((bits & 0x80) >> 3) | ((bits & 0x40) >> 6);
  274.          *pixels++ = ((bits & 0x20) >> 1) | ((bits & 0x10) >> 4);
  275.          *pixels++ = ((bits & 0x08) << 1) | ((bits & 0x04) >> 2);
  276.          *pixels++ = ((bits & 0x02) << 3) | (bits & 0x01);
  277.       }
  278.    }
  279. }
  280.