home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xv310a / xvpcx.c < prev    next >
C/C++ Source or Header  |  1995-06-12  |  16KB  |  388 lines

  1. /*
  2.  * xvpcx.c - load routine for PCX format pictures
  3.  *
  4.  * LoadPCX(fname, pinfo)  -  loads a PCX file
  5.  */
  6.  
  7. #include "copyright.h"
  8.  
  9. /*
  10.  * the following code has been derived from code written by
  11.  *  Eckhard Rueggeberg  (Eckhard.Rueggeberg@ts.go.dlr.de)
  12.  */
  13.  
  14.  
  15. #include "xv.h"
  16.  
  17. /* offsets into PCX header */
  18. #define PCX_ID      0
  19. #define PCX_VER     1
  20. #define PCX_ENC     2
  21. #define PCX_BPP     3
  22. #define PCX_XMINL   4
  23. #define PCX_XMINH   5
  24. #define PCX_YMINL   6
  25. #define PCX_YMINH   7
  26. #define PCX_XMAXL   8
  27. #define PCX_XMAXH   9
  28. #define PCX_YMAXL   10
  29. #define PCX_YMAXH   11
  30.                           /* hres (12,13) and vres (14,15) not used */
  31. #define PCX_CMAP    16    /* start of 16*3 colormap data */
  32. #define PCX_PLANES  65 
  33. #define PCX_BPRL    66
  34. #define PCX_BPRH    67
  35.  
  36. #define PCX_MAPSTART 0x0c    /* Start of appended colormap    */
  37.  
  38.  
  39. static int  pcxLoadImage8  PARM((char *, FILE *, PICINFO *, byte *));
  40. static int  pcxLoadImage24 PARM((char *, FILE *, PICINFO *, byte *));
  41. static void pcxLoadRaster  PARM((FILE *, byte *, int, byte *, int, int));
  42. static int  pcxError       PARM((char *, char *));
  43.  
  44.  
  45.  
  46. /*******************************************/
  47. int LoadPCX(fname, pinfo)
  48.      char    *fname;
  49.      PICINFO *pinfo;
  50. /*******************************************/
  51. {
  52.   FILE  *fp;
  53.   long   filesize;
  54.   char  *bname, *errstr;
  55.   byte   hdr[128], *image;
  56.   int    i, colors, gray, fullcolor;
  57.  
  58.   pinfo->type = PIC8;
  59.   pinfo->pic     = (byte *) NULL;
  60.   pinfo->comment = (char *) NULL;
  61.  
  62.   bname = BaseName(fname);
  63.  
  64.   /* open the stream */
  65.   fp = xv_fopen(fname,"r");
  66.   if (!fp) return (pcxError(bname, "unable to open file"));
  67.   
  68.  
  69.   /* figure out the file size */
  70.   fseek(fp, 0L, 2);
  71.   filesize = ftell(fp);
  72.   fseek(fp, 0L, 0);
  73.  
  74.  
  75.   /* read the PCX header */
  76.   fread(hdr, (size_t) 128, (size_t) 1, fp);
  77.   if (ferror(fp) || feof(fp)) {
  78.     fclose(fp);
  79.     return pcxError(bname, "EOF reached in PCX header.\n");
  80.   }
  81.  
  82.   if (hdr[PCX_ID] != 0x0a || hdr[PCX_VER] > 5) {
  83.     fclose(fp);
  84.     return pcxError(bname,"unrecognized magic number");
  85.   }
  86.  
  87.   pinfo->w = (hdr[PCX_XMAXL] + ((int) hdr[PCX_XMAXH]<<8)) 
  88.            - (hdr[PCX_XMINL] + ((int) hdr[PCX_XMINH]<<8));
  89.  
  90.   pinfo->h = (hdr[PCX_YMAXL] + ((int) hdr[PCX_YMAXH]<<8)) 
  91.            - (hdr[PCX_YMINL] + ((int) hdr[PCX_YMINH]<<8));
  92.  
  93.   pinfo->w++;  pinfo->h++;
  94.  
  95.   colors = 1 << (hdr[PCX_BPP] * hdr[PCX_PLANES]);
  96.   fullcolor = (hdr[PCX_BPP] == 8 && hdr[PCX_PLANES] == 3);
  97.  
  98.   if (DEBUG) {
  99.     fprintf(stderr,"PCX: %dx%d image, version=%d, encoding=%d\n", 
  100.         pinfo->w, pinfo->h, hdr[PCX_VER], hdr[PCX_ENC]);
  101.     fprintf(stderr,"   BitsPerPixel=%d, planes=%d, BytePerRow=%d, colors=%d\n",
  102.         hdr[PCX_BPP], hdr[PCX_PLANES], 
  103.         hdr[PCX_BPRL] + ((int) hdr[PCX_BPRH]<<8),
  104.         colors);
  105.   }
  106.  
  107.   if (colors>256 && !fullcolor) {
  108.     fclose(fp);
  109.     return pcxError(bname,"No more than 256 colors allowed in PCX file.");
  110.   }
  111.  
  112.   if (hdr[PCX_ENC] != 1) {
  113.     fclose(fp);
  114.     return pcxError(bname,"Unsupported PCX encoding format.");
  115.   }
  116.  
  117.   /* load the image, the image function fills in pinfo->pic */
  118.   if (!fullcolor) {
  119.     if (!pcxLoadImage8(bname, fp, pinfo, hdr)) {
  120.       fclose(fp);
  121.       return 0;
  122.     }
  123.   }
  124.   else {
  125.     if (!pcxLoadImage24(bname, fp, pinfo, hdr)) {
  126.       fclose(fp);
  127.       return 0;
  128.     }
  129.   }
  130.  
  131.  
  132.   if (ferror(fp) | feof(fp))    /* just a warning */
  133.     pcxError(bname, "PCX file appears to be truncated.");
  134.  
  135.   if (colors>16 && !fullcolor) {       /* handle trailing colormap */
  136.     while (1) {
  137.       i=getc(fp);
  138.       if (i==PCX_MAPSTART || i==EOF) break;
  139.     }
  140.  
  141.     for (i=0; i<colors; i++) {
  142.       pinfo->r[i] = getc(fp);
  143.       pinfo->g[i] = getc(fp);
  144.       pinfo->b[i] = getc(fp);
  145.     }
  146.  
  147.     if (ferror(fp) || feof(fp)) {
  148.       pcxError(bname,"Error reading PCX colormap.  Using grayscale.");
  149.       for (i=0; i<256; i++) pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
  150.     }
  151.   }
  152.   else if (colors<=16) {   /* internal colormap */
  153.     for (i=0; i<colors; i++) {
  154.       pinfo->r[i] = hdr[PCX_CMAP + i*3];
  155.       pinfo->g[i] = hdr[PCX_CMAP + i*3 + 1];
  156.       pinfo->b[i] = hdr[PCX_CMAP + i*3 + 2];
  157.     }
  158.   }
  159.  
  160.   if (colors == 2) {    /* b&w */
  161.     if (MONO(pinfo->r[0], pinfo->g[0], pinfo->b[0]) ==
  162.     MONO(pinfo->r[1], pinfo->g[1], pinfo->b[1])) {
  163.       /* create cmap */
  164.       pinfo->r[0] = pinfo->g[0] = pinfo->b[0] = 255;
  165.       pinfo->r[1] = pinfo->g[1] = pinfo->b[1] = 0;
  166.       if (DEBUG) fprintf(stderr,"PCX: no cmap:  using 0=white,1=black\n");
  167.     }
  168.   }
  169.  
  170.  
  171.   fclose(fp);
  172.  
  173.  
  174.  
  175.   /* finally, convert into XV internal format */
  176.  
  177.  
  178.   pinfo->type    = fullcolor ? PIC24 : PIC8;
  179.   pinfo->frmType = -1;    /* no default format to save in */
  180.  
  181.   /* check for grayscaleitude */
  182.   gray = 0;
  183.   if (!fullcolor) {
  184.     for (i=0; i<colors; i++) {
  185.       if ((pinfo->r[i] != pinfo->g[i]) || (pinfo->r[i] != pinfo->b[i])) break;
  186.     }
  187.     gray = (i==colors) ? 1 : 0;
  188.   }
  189.  
  190.  
  191.   if (colors > 2 || (colors==2 && !gray)) {  /* grayscale or PseudoColor */
  192.     pinfo->colType = (gray) ? F_GREYSCALE : F_FULLCOLOR;
  193.     sprintf(pinfo->fullInfo, 
  194.         "%s PCX, %d plane%s, %d bit%s per pixel.  (%ld bytes)", 
  195.         (gray) ? "Greyscale" : "Color", 
  196.         hdr[PCX_PLANES], (hdr[PCX_PLANES]==1) ? "" : "s",
  197.         hdr[PCX_BPP],    (hdr[PCX_BPP]==1) ? "" : "s",
  198.         filesize);
  199.   }
  200.   else {
  201.     pinfo->colType = F_BWDITHER;
  202.     sprintf(pinfo->fullInfo, "B&W PCX.  (%ld bytes)", filesize);
  203.   }
  204.  
  205.   sprintf(pinfo->shrtInfo, "%dx%d PCX.", pinfo->w, pinfo->h);
  206.   pinfo->normw = pinfo->w;   pinfo->normh = pinfo->h;
  207.  
  208.   return 1;
  209. }
  210.  
  211.  
  212.  
  213. /*****************************/
  214. static int pcxLoadImage8(fname, fp, pinfo, hdr)
  215.      char    *fname;
  216.      FILE    *fp;
  217.      PICINFO *pinfo;
  218.      byte    *hdr;
  219. {
  220.   /* load an image with at most 8 bits per pixel */
  221.   
  222.   byte *image;
  223.   
  224.   /* note:  overallocation to make life easier... */
  225.   image = (byte *) malloc((size_t) (pinfo->h + 1) * pinfo->w + 16);
  226.   if (!image) FatalError("Can't alloc 'image' in pcxLoadImage8()");
  227.   
  228.   xvbzero((char *) image, (size_t) ((pinfo->h+1) * pinfo->w + 16));
  229.   
  230.   switch (hdr[PCX_BPP]) {
  231.   case 1:   pcxLoadRaster(fp, image, 1, hdr, pinfo->w, pinfo->h);   break;
  232.   case 8:   pcxLoadRaster(fp, image, 8, hdr, pinfo->w, pinfo->h);   break;
  233.   default:
  234.     pcxError(fname, "Unsupported # of bits per plane.");
  235.     free(image);
  236.     return (0);
  237.   }
  238.  
  239.   pinfo->pic = image;
  240.   return 1;
  241. }
  242.  
  243.  
  244. /*****************************/
  245. static int pcxLoadImage24(fname, fp, pinfo, hdr)
  246.      char *fname;
  247.      FILE *fp;
  248.      PICINFO *pinfo;
  249.      byte *hdr;
  250. {
  251.   byte *pix, *pic24, scale[256];
  252.   int   c, i, j, w, h, maxv, cnt, planes, bperlin, nbytes;
  253.   
  254.   w = pinfo->w;  h = pinfo->h;
  255.   
  256.   planes = (int) hdr[PCX_PLANES];
  257.   bperlin = hdr[PCX_BPRL] + ((int) hdr[PCX_BPRH]<<8);
  258.   
  259.   /* allocate 24-bit image */
  260.   pic24 = (byte *) malloc((size_t) w*h*planes);
  261.   if (!pic24) FatalError("couldn't malloc 'pic24'");
  262.   
  263.   xvbzero((char *) pic24, (size_t) w*h*planes);
  264.   
  265.   maxv = 0;
  266.   pix = pinfo->pic = pic24;
  267.   i = 0;      /* planes, in this while loop */
  268.   j = 0;      /* bytes per line, in this while loop */
  269.   nbytes = bperlin*h*planes;
  270.  
  271.   while (nbytes > 0 && (c = getc(fp)) != EOF) {
  272.     if ((c & 0xC0) == 0xC0) {   /* have a rep. count */
  273.       cnt = c & 0x3F;
  274.       c = getc(fp);
  275.       if (c == EOF) { getc(fp); break; }
  276.     }
  277.     else cnt = 1;
  278.     
  279.     if (c > maxv)  maxv = c;
  280.     
  281.     while (cnt-- > 0) {
  282.       if (j < w) {
  283.     *pix = c;
  284.     pix += planes;
  285.       }
  286.       j++;
  287.       nbytes--;
  288.       if (j == bperlin) {
  289.     j = 0;
  290.     if (++i < planes) {
  291.       pix -= (w*planes)-1;  /* next plane on this line */
  292.     }
  293.     else {
  294.       pix -= (planes-1);    /* start of next line, first plane */
  295.       i = 0;
  296.     }
  297.       }
  298.     }
  299.   }
  300.   
  301.   
  302.   /* scale all RGB to range 0-255, if they aren't */
  303.  
  304.   if (maxv<255) { 
  305.     for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv;
  306.     
  307.     for (i=0, pix=pic24; i<h; i++) {
  308.       if ((i&0x3f)==0) WaitCursor();
  309.       for (j=0; j<w*planes; j++, pix++) *pix = scale[*pix];
  310.     }
  311.   }
  312.   
  313.   return 1;
  314. }
  315.  
  316.  
  317.  
  318. /*****************************/
  319. static void pcxLoadRaster(fp, image, depth, hdr, w,h)
  320.      FILE    *fp;
  321.      byte    *image, *hdr;
  322.      int      depth,w,h;
  323. {
  324.   /* supported:  8 bits per pixel, 1 plane, or 1 bit per pixel, 1-8 planes */
  325.  
  326.   int row, bcnt, bperlin, pad;
  327.   int i, j, b, cnt, mask, plane, pmask;
  328.   byte *oldimage;
  329.  
  330.   bperlin = hdr[PCX_BPRL] + ((int) hdr[PCX_BPRH]<<8);
  331.   if (depth == 1) pad = (bperlin * 8) - w;
  332.              else pad = bperlin - w;
  333.  
  334.   row = bcnt = 0;
  335.  
  336.   plane = 0;  pmask = 1;  oldimage = image;
  337.  
  338.   while ( (b=getc(fp)) != EOF) {
  339.     if ((b & 0xC0) == 0xC0) {   /* have a rep. count */
  340.       cnt = b & 0x3F;
  341.       b = getc(fp);
  342.       if (b == EOF) { getc(fp); return; }
  343.     }
  344.     else cnt = 1;
  345.     
  346.     for (i=0; i<cnt; i++) {
  347.       if (depth == 1) {
  348.     for (j=0, mask=0x80; j<8; j++) {
  349.       *image++ |= ((b & mask) ? pmask : 0);
  350.       mask = mask >> 1;
  351.     }
  352.       }
  353.       else *image++ = (byte) b;
  354.       
  355.       bcnt++;
  356.     
  357.       if (bcnt == bperlin) {     /* end of a line reached */
  358.     bcnt = 0;
  359.     plane++;  
  360.  
  361.     if (plane >= (int) hdr[PCX_PLANES]) {   /* moved to next row */
  362.       plane = 0;
  363.       image -= pad;
  364.       oldimage = image;
  365.       row++;
  366.       if (row >= h) return;   /* done */
  367.     }
  368.     else {   /* next plane, same row */
  369.       image = oldimage;
  370.     }    
  371.  
  372.     pmask = 1 << plane;
  373.       }
  374.     }
  375.   }
  376. }    
  377.  
  378.  
  379.  
  380. /*******************************************/
  381. static int pcxError(fname,st)
  382.      char *fname, *st;
  383. {
  384.   SetISTR(ISTR_WARNING,"%s:  %s", fname, st);
  385.   return 0;
  386. }
  387.