home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / displytl / xvpbm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  10.1 KB  |  461 lines

  1. /*
  2.  * xvpbm.c - load routine for 'pm' format pictures
  3.  *
  4.  * LoadPBM(fname, numcols)  -  loads a PBM, PGM, or PPM file
  5.  * WritePBM(fp,pic,w,h,r,g,b,numcols,style,raw,cmt)
  6.  */
  7.  
  8. /*
  9.  * Copyright 1989, 1990, 1991, 1992 by John Bradley and
  10.  *                       The University of Pennsylvania
  11.  *
  12.  * Permission to use, copy, and distribute for non-commercial purposes,
  13.  * is hereby granted without fee, providing that the above copyright
  14.  * notice appear in all copies and that both the copyright notice and this
  15.  * permission notice appear in supporting documentation.
  16.  *
  17.  * The software may be modified for your own purposes, but modified versions
  18.  * may not be distributed.
  19.  *
  20.  * This software is provided "as is" without any expressed or implied warranty.
  21.  *
  22.  * The author may be contacted via:
  23.  *    US Mail:   John Bradley
  24.  *               GRASP Lab, Room 301C
  25.  *               3401 Walnut St.
  26.  *               Philadelphia, PA  19104
  27.  *
  28.  *    Phone:     (215) 898-8813
  29.  *    EMail:     bradley@cis.upenn.edu
  30.  */
  31.  
  32.  
  33. #include "xvimage.h"
  34.  
  35.  
  36.  
  37. /* comments on error handling:
  38.    a truncated file is not considered a Major Error.  The file is loaded, the
  39.    rest of the pic is filled with 0's.
  40.  
  41.    a file with garbage characters in it is an unloadable file.  All allocated
  42.    stuff is tossed, and LoadPBM returns non-zero
  43.  
  44.    not being able to malloc is a Fatal Error.  The program is aborted. */
  45.  
  46.  
  47. #define TRUNCSTR "File appears to be truncated."
  48.  
  49. static int garbage;
  50. static long numgot, filesize;
  51.  
  52.  
  53. static int loadpbm(), loadpgm(), loadppm();
  54. static int getint(),  getbit(),  PBMerr();
  55.  
  56.  
  57. /*******************************************/
  58. int LoadPBM(fname,nc)
  59.      char *fname;
  60.      int   nc;
  61. /*******************************************/
  62. {
  63.   FILE  *fp;
  64.   int    c, c1;
  65.   int    w, h, maxv, rv;
  66.  
  67.   garbage = maxv = 0;
  68.  
  69.   /* open the stream, if necesary */
  70.   fp=fopen(fname,"r");
  71.   if (!fp) return 1;
  72.   
  73.   /* figure out the file size (for Informational Purposes Only) */
  74.   fseek(fp, 0L, 2);
  75.   filesize = ftell(fp);
  76.   fseek(fp, 0L, 0);
  77.  
  78.   /* read the first two bytes of the file to determine which format
  79.      this file is.  "P1" = ascii bitmap, "P2" = ascii greymap,
  80.      "P3" = ascii pixmap, "P4" = raw bitmap, "P5" = raw greymap,
  81.      "P6" = raw pixmap */
  82.  
  83.   c = getc(fp);  c1 = getc(fp);
  84.   if (c!='P' || c1<'1' || c1>'6') return(PBMerr("unknown format"));
  85.  
  86.   /* read in header information */
  87.   w = getint(fp);  h = getint(fp);
  88.  
  89.   /* if we're not reading a bitmap, read the 'max value' */
  90.   if ( !(c1=='1' || c1=='4')) {
  91.     maxv = getint(fp);
  92.     if (maxv < 1) garbage=1;    /* to avoid 'div by zero' probs */
  93.   }
  94.  
  95.  
  96.   if (garbage) {
  97.     if (fp!=stdin) fclose(fp);
  98.     return (PBMerr("Garbage characters in header."));
  99.   }
  100.  
  101.   rv = 0;
  102.  
  103.   /* call the appropriate subroutine to handle format-specific stuff */
  104.   if      (c1=='1' || c1=='4') rv = loadpbm(fp,w,h,       c1=='4' ? 1 : 0);
  105.   else if (c1=='2' || c1=='5') rv = loadpgm(fp,w,h, maxv, c1=='5' ? 1 : 0);
  106.   else if (c1=='3' || c1=='6') rv = loadppm(fp,w,h, maxv, c1=='6' ? 1 : 0, nc);
  107.  
  108.   if (fp!=stdin) fclose(fp);
  109.   return(rv);
  110. }  
  111.  
  112.  
  113.  
  114. /*******************************************/
  115. static int loadpbm(fp, w, h, raw)
  116. FILE *fp;
  117. int   w,h,raw;
  118. {
  119.   byte *pix;
  120.   int   i,j,bit;
  121.  
  122.  
  123.   sprintf(formatStr, "PBM, %s format.  (%ld bytes)", 
  124.       (raw) ? "raw" : "ascii", filesize);
  125.  
  126.   /* load up the XV global variables */
  127.   pic = (byte *) calloc(w*h,1);
  128.   if (!pic) FatalError("couldn't malloc 'pic'");
  129.  
  130.   pWIDE = w;  pHIGH = h;
  131.  
  132.   /* B/W bitmaps have a two entry colormap */
  133.   r[0] = g[0] = b[0] = 255;   /* 0 = white */
  134.   r[1] = g[1] = b[1] = 0;     /* 1 = black */
  135.  
  136.   if (!raw) {
  137.     numgot = 0;
  138.     for (i=0, pix=pic; i<h; i++) {
  139.       for (j=0; j<w; j++, pix++) *pix = getbit(fp);
  140.     }
  141.  
  142.     if (numgot != w*h) PBMerr(TRUNCSTR);
  143.     if (garbage) {
  144.       free(pic);
  145.       return(PBMerr("Garbage characters in image data."));
  146.     }
  147.   }
  148.  
  149.  
  150.   else {   /* read raw bits */
  151.     int trunc = 0, k = 0;
  152.  
  153.     for (i=0, pix=pic; i<h; i++) {
  154.       for (j=0,bit=0; j<w; j++, pix++, bit++) {
  155.  
  156.     bit &= 7;
  157.     if (!bit) {
  158.       k = getc(fp);
  159.       if (k==EOF) { trunc=1; k=0; }
  160.     }
  161.  
  162.     *pix = (k&0x80) ? 1 : 0;
  163.     k = k << 1;
  164.       }
  165.     }
  166.  
  167.     if (trunc) PBMerr(TRUNCSTR);
  168.   }
  169.  
  170.   return 0;
  171. }
  172.  
  173.  
  174. /*******************************************/
  175. static int loadpgm(fp, w, h, maxv, raw)
  176. FILE *fp;
  177. int   w,h,maxv,raw;
  178. {
  179.   byte *pix;
  180.   int   i,j,bitshift;
  181.  
  182.   sprintf(formatStr, "PGM, %s format.  (%ld bytes)", 
  183.       (raw) ? "raw" : "ascii", filesize);
  184.  
  185.   /* load up the XV global variables */
  186.   pic = (byte *) calloc(w*h,1);
  187.   if (!pic) FatalError("couldn't malloc 'pic'");
  188.  
  189.   pWIDE = w;  pHIGH = h;
  190.  
  191.   /* if maxv>255, keep dropping bits until it's reasonable */
  192.   bitshift = 0;
  193.   while (maxv>255) { maxv = maxv>>1;  bitshift++; }
  194.  
  195.   /* fill in a greyscale colormap where maxv maps to 255 */
  196.   for (i=0; i<=maxv; i++)
  197.     r[i] = g[i] = b[i] = (i*255)/maxv;
  198.  
  199.   if (!raw) {
  200.     numgot = 0;
  201.     for (i=0, pix=pic; i<h; i++) {
  202.       for (j=0; j<w; j++, pix++)
  203.     *pix = (getint(fp) >> bitshift);
  204.     }
  205.   }
  206.  
  207.   else numgot = fread(pic, 1, w*h, fp);   /* read raw data */
  208.  
  209.   if (numgot != w*h) PBMerr(TRUNCSTR);
  210.  
  211.   if (garbage) {
  212.     free(pic);
  213.     return (PBMerr("Garbage characters in image data."));
  214.   }
  215.  
  216.   return 0;
  217. }
  218.  
  219.  
  220. /*******************************************/
  221. static int loadppm(fp, w, h, maxv, raw, nc)
  222. FILE *fp;
  223. int   w,h,maxv,raw,nc;
  224. {
  225.   byte *pix, *pic24, scale[256];
  226.   int   i,j,bitshift;
  227.  
  228.   sprintf(formatStr, "PPM, %s format.  (%ld bytes)", 
  229.       (raw) ? "raw" : "ascii", filesize);
  230.  
  231.   /* allocate 24-bit image */
  232.   pic24 = (byte *) calloc(w*h*3,1);
  233.   if (!pic24) FatalError("couldn't malloc 'pic24'");
  234.  
  235.   /* if maxv>255, keep dropping bits until it's reasonable */
  236.   bitshift = 0;
  237.   while (maxv>255) { maxv = maxv>>1;  bitshift++; }
  238.  
  239.   if (!raw) {
  240.     numgot = 0;
  241.     for (i=0, pix=pic24; i<h; i++) {
  242.  
  243.       for (j=0; j<w*3; j++, pix++)
  244.     *pix = (getint(fp) >> bitshift);
  245.     }
  246.   }
  247.  
  248.   else numgot = fread(pic24, 1, w*h*3, fp);    /* read raw data */
  249.  
  250.   if (numgot != w*h*3) PBMerr(TRUNCSTR);
  251.  
  252.   if (garbage) {
  253.     free(pic24);
  254.     return(PBMerr("Garbage characters in image data."));
  255.   }
  256.  
  257.   /* have to scale all RGB values up (Conv24to8 expects RGB values to
  258.      range from 0-255 */
  259.  
  260.   if (maxv<255) { 
  261.     for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv;
  262.  
  263.     for (i=0, pix=pic24; i<h; i++) {
  264.       for (j=0; j<w*3; j++, pix++) *pix = scale[*pix];
  265.     }
  266.   }
  267.  
  268.   i = Conv24to8(pic24,w,h,nc);
  269.   free(pic24);
  270.   return i;
  271. }
  272.  
  273.  
  274.  
  275. /*******************************************/
  276. static int getint(fp)
  277. FILE *fp;
  278. {
  279.   int c, i;
  280.  
  281.   /* skip forward to start of next number */
  282.   c = getc(fp);
  283.   while (1) {
  284.     /* eat comments */
  285.     if (c=='#') {   /* if we're at a comment, read to end of line */
  286.       while (c != '\n' && c != EOF) c=getc(fp);
  287.     }
  288.  
  289.     if (c==EOF) return 0;
  290.     if (c>='0' && c<='9') break;   /* we've found what we were looking for */
  291.  
  292.     /* see if we are getting garbage (non-whitespace) */
  293.     if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=',') garbage=1;
  294.  
  295.     c = getc(fp);
  296.   }
  297.  
  298.  
  299.   /* we're at the start of a number, continue until we hit a non-number */
  300.   i = 0;
  301.   while (1) {
  302.     i = (i*10) + (c - '0');
  303.     c = getc(fp);
  304.     if (c==EOF) return i;
  305.     if (c<'0' || c>'9') break;
  306.   }
  307.  
  308.   numgot++;
  309.   return i;
  310. }
  311.  
  312.  
  313.  
  314. /*******************************************/
  315. static int getbit(fp)
  316. FILE *fp;
  317. {
  318.   int c;
  319.  
  320.   /* skip forward to start of next number */
  321.   c = getc(fp);
  322.   while (1) {
  323.     /* eat comments */
  324.     if (c=='#') {   /* if we're at a comment, read to end of line */
  325.       while (c != '\n' && c != EOF) c=getc(fp);
  326.     }
  327.  
  328.     if (c==EOF) return 0;
  329.     if (c=='0' || c=='1') break;   /* we've found what we were looking for */
  330.  
  331.     /* see if we are getting garbage (non-whitespace) */
  332.     if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=',') garbage=1;
  333.  
  334.     c = getc(fp);
  335.   }
  336.  
  337.  
  338.   numgot++;
  339.   return(c-'0');
  340. }
  341.  
  342.  
  343. /*******************************************/
  344. static int PBMerr(st)
  345. char *st;
  346. {
  347.   printf(st);
  348.   return 1;
  349. }
  350.  
  351.  
  352.  
  353.  
  354.  
  355. /*******************************************/
  356. int WritePBM(fp,pic,w,h,rmap,gmap,bmap,numcols,colorstyle,raw)
  357. FILE *fp;
  358. byte *pic;
  359. int   w,h;
  360. byte *rmap, *gmap, *bmap;
  361. int   numcols, colorstyle, raw;
  362. {
  363.   /* writes a PBM/PGM/PPM file to the already open stream
  364.      if (raw), writes as RAW bytes, otherwise writes as ASCII 
  365.      'colorstyle' single-handedly determines the type of file written
  366.      if colorstyle==0, (Full Color) a PPM file is written
  367.      if colorstyle==1, (Greyscale)  a PGM file is written
  368.      if colorstyle==2, (B/W stipple) a PBM file is written */
  369.  
  370.   int   magic;
  371.   byte *pix;
  372.   int   i,j,len;
  373.  
  374.   /* calc the appropriate magic number for this file type */
  375.   magic = 0;
  376.   if      (colorstyle==0) magic = 3;
  377.   else if (colorstyle==1) magic = 2;
  378.   else if (colorstyle==2) magic = 1;
  379.  
  380.   if (raw && magic) magic+=3;
  381.  
  382.   if (!magic) return(PBMerr("WritePBM: unknown file format"));
  383.  
  384.   /* write the header info */
  385.   fprintf(fp,"P%d\n",magic);
  386.   fprintf(fp,"# created by 'xv %s'\n", namelist[curname]);
  387.   fprintf(fp,"%d %d\n",w,h);
  388.   if (colorstyle!=2) fprintf(fp,"255\n");
  389.  
  390.   if (ferror(fp)) return -1;
  391.  
  392.   /* write the image data */
  393.  
  394.   if (colorstyle==0) {                  /* 24bit RGB, 3 bytes per pixel */
  395.     for (i=0, pix=pic, len=0; i<h; i++) {
  396.       for (j=0; j<w; j++,pix++) {
  397.     if (raw) {
  398.       putc(r[*pix],fp);  
  399.       putc(g[*pix],fp);  
  400.       putc(b[*pix],fp);
  401.     }
  402.     else {
  403.       fprintf(fp,"%3d %3d %3d ",r[*pix], g[*pix], b[*pix]);
  404.       len+=12;
  405.       if (len>58) { fprintf(fp,"\n");  len=0; }
  406.     }
  407.       }
  408.     }
  409.   }
  410.  
  411.   else if (colorstyle==1) {             /* 8-bit greyscale */
  412.     byte rgb[256];
  413.     for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
  414.     for (i=0, pix=pic, len=0; i<w*h; i++,pix++) {
  415.       if (raw) putc(rgb[*pix],fp);
  416.       else {
  417.     fprintf(fp,"%3d ",rgb[*pix]);
  418.     len += 4;
  419.     if (len>66) { fprintf(fp,"\n");  len=0; }
  420.       }
  421.     }
  422.   }
  423.  
  424.   else if (colorstyle==2) {             /* 1-bit B/W stipple */
  425.     int bit,k;
  426.     for (i=0, pix=pic, len=0; i<h; i++) {
  427.       for (j=0, bit=0, k=0; j<w; j++, pix++) {
  428.     if (raw) {
  429.       k = (k << 1) | *pix;
  430.       bit++;
  431.       if (bit==8) {
  432.         fputc(~k,fp);
  433.         bit = k = 0;
  434.       }
  435.     }
  436.     else {
  437.       if (*pix) fprintf(fp,"0 ");
  438.            else fprintf(fp,"1 ");
  439.       len+=2;
  440.       if (len>68) { fprintf(fp,"\n"); len=0; }
  441.     }
  442.       } /* j */
  443.       if (raw && bit) {
  444.     k = k << (8-bit);
  445.     fputc(~k,fp);
  446.       }
  447.     }
  448.   }
  449.  
  450.   if (ferror(fp)) return -1;
  451.  
  452.   return 0;
  453. }
  454.  
  455.  
  456.       
  457.       
  458.  
  459.  
  460.  
  461.