home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2314 / cpctopbm.c next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  7.8 KB  |  443 lines

  1. #include <stdio.h>
  2.  
  3. /*
  4.  * cpctopbm
  5.  * convert "Complete PC" messages to PBM format.
  6.  * This has only been tested on Complete PC Fax files, though.
  7.  * with some work it could also work with other Complete PC files
  8.  * (e.g. formats 2 and 3, "Complete Hand Scanner" and "Complete PC Scanner"
  9.  *  formats) but I don't have any of those to test out.
  10.  *
  11.  * Steve Hayman
  12.  * sahayman@cs.indiana.edu
  13.  * 90/10/10
  14.  */
  15.  
  16. /*
  17.  * see the README file for a description of the header and
  18.  * file format
  19.  */
  20.  
  21. struct cpc_header {
  22.     unsigned char magic[4];
  23.     short hour, min, sec;
  24.     short month, day, wday, year;
  25.  
  26.     char reserved_1[ 77 - 18 + 1 ];
  27.     char resolution;
  28.     char picture_start;
  29.  
  30.     char reserved_2[ 99 - 80 + 1];
  31. };
  32.     
  33. struct cpc_header header;
  34. int debug = 0;
  35. int verbose = 0;
  36. char *Pname;
  37. int linecount = 0;
  38.  
  39. #define FAXBLACK 0
  40. #define FAXWHITE 1
  41.  
  42. #define FAXWIDTH 1728
  43.  
  44. int pbm_format = 4;
  45. int fix_aspect = 1;
  46.  
  47.  
  48.  
  49. #define EOL 0x69
  50. #define WHITELINE    0x7f
  51.  
  52. main (argc, argv)
  53. int argc;
  54. char **argv;
  55. {
  56.     int c;
  57.     extern int optind, opterr;
  58.     extern char *optarg;
  59.     int errflg = 0;
  60.  
  61.     char *filename;
  62.     FILE *fax;
  63.  
  64.     char tmpname[32];
  65.     FILE *tmp;
  66.  
  67.  
  68.     Pname = argv[0];
  69.  
  70.     while ((c = getopt(argc, argv, "dvap:")) != EOF) {
  71.     switch (c) {
  72.     case 'a':
  73.         fix_aspect = 0;
  74.         break;
  75.     case 'd':
  76.         debug++;
  77.          break;
  78.     case 'p':
  79.         pbm_format = atoi(optarg);
  80.         break;
  81.     case 'v':
  82.         verbose++;
  83.         break;
  84.     default:
  85.          errflg++;
  86.     }
  87.     }
  88.  
  89.  
  90.     if ( optind == argc ) {
  91.     fax = stdin;
  92.     filename = "stdin";
  93.     } else if ( optind == argc - 1 )  {
  94.  
  95.     filename = argv[optind];
  96.     if ( (fax = fopen(filename, "r")) == NULL ) {
  97.         fprintf(stderr, "%s: Can't open ");
  98.         perror(filename);
  99.         exit(1);
  100.     }
  101.     } else {
  102.     errflg++;
  103.     }
  104.  
  105.     if (errflg) {
  106.     fprintf (stderr, "%s: Usage: %s [-p pbm-format] [-a] [-v] [-d] [cfax-file]\n", Pname, Pname);
  107.     exit(2);
  108.     }
  109.  
  110.     init_runlength_table();
  111.  
  112.     /*
  113.      * Read the header.
  114.      */
  115.  
  116.     if ( fread((char *)&header, sizeof(header), 1, fax) != 1 ) {
  117.     fprintf(stderr, "%s: could not read header\n", Pname);
  118.     exit(1);
  119.     }
  120.  
  121.     /*
  122.      * Magic number must be 80 01 40 02.
  123.      */
  124.     
  125.  
  126.     if ( header.magic[0] != 0x80
  127.      ||  header.magic[1] != 0x01
  128.      ||  header.magic[2] != 0x40
  129.      ||  header.magic[3] != 0x02 ) {
  130.     
  131.     fprintf(stderr, "%s: file '%s' format not recognized\n", 
  132.         Pname, filename);
  133.     exit(1);
  134.     }
  135.  
  136.     if ( verbose ) {
  137.     fprintf(stderr, "File: %s\nReceived: %d/%d/%d %d:%02d:%02d\n",
  138.         filename,
  139.         header.year, header.month, header.day,
  140.         header.hour, header.min, header.sec );
  141.     fprintf(stderr, "Resolution: %s\n",
  142.         header.resolution == 0 ? "100x200" : "200x200" );
  143.     }
  144.     /*
  145.      * Open scratch file.
  146.      * We'll rewind this later and schlep it to stdout.
  147.      */
  148.  
  149.     strcpy(tmpname, "/tmp/pbm.XXXXXX");
  150.     mktemp(tmpname);
  151.  
  152.     if ( (tmp = fopen(tmpname, "w+")) == NULL ) {
  153.     fprintf(stderr, "%s: can't create temp file ", Pname);
  154.     perror(tmpname);
  155.     exit(1);
  156.     }
  157.  
  158.     /*
  159.      * Slimy manouevre to make sure tmp file goes away when
  160.      * program exits
  161.      */
  162.     unlink(tmpname);
  163.  
  164.     /*
  165.      * Gobble one more EOL
  166.      */
  167.     if ( getc(fax) != EOL ) {
  168.     fprintf(stderr,"%s: file format error, 'EOL' after header missing\n");
  169.     exit(1);
  170.     }
  171.     /*
  172.      * Now read and write the rest.
  173.      */
  174.  
  175.     cfaxtopbm(fax, tmp);
  176.  
  177.     /*
  178.      * OK, rewind, fill in correct values of header,
  179.      * schlep it to stdout
  180.      */
  181.  
  182.     fseek(tmp, 0L, 0);
  183.  
  184.     /*
  185.      * Now write the header to stdout
  186.      * Compensate for the four bogus EOL's at the end of the file.
  187.      */
  188.     
  189.     /*
  190.      * Add a few useful comments to the pbm header, since they're
  191.      * in the fax header anyway.
  192.      */
  193.     
  194.     printf( "P%d\n", pbm_format);
  195.     printf( "# Converted from CPC-format fax file '%s'\n", filename);
  196.     printf( "# received: %d %d %d  %d:%02d:%02d\n",
  197.         header.year, header.month, header.day,
  198.         header.hour, header.min, header.sec );
  199.  
  200.     linecount -= 4;
  201.     if ( header.resolution == 0 && fix_aspect ) {
  202.     linecount -= 4; /* we've been counting them twice */
  203.     }
  204.     printf("%d %d\n", FAXWIDTH, linecount);
  205.     /*
  206.      * Now copy the tmp file.
  207.      */
  208.  
  209.     while ( (c = getc(tmp)) != EOF ) {
  210.     putchar(c);
  211.     }
  212.  
  213.  
  214.     if ( verbose ) {
  215.     fprintf(stderr, "%d lines\n", linecount);
  216.     }
  217.     exit(0);
  218. }
  219.  
  220. /*
  221.  * RunLength[i] is the length of a run of pixels encoded by the
  222.  * byte value 'i'.
  223.  */
  224.  
  225. int RunLength[128];
  226.  
  227. init_runlength_table()
  228. {
  229.     int i;
  230.  
  231.     for ( i = 1; i <= 64; i++ )
  232.     RunLength[i] = i - 1;
  233.     
  234.     for ( i = 65; i <= 104; i++ ) {
  235.     RunLength[i] = (i - 64) * 64;
  236.     }
  237. }
  238.     
  239.  
  240. int pixel = FAXWHITE;
  241.  
  242. cfaxtopbm(fax, out)
  243. FILE *fax;
  244. FILE *out;
  245. {
  246.  
  247.     int c;
  248.     int rl;
  249.  
  250.     int eol_count = 0;
  251.  
  252.     /*
  253.      * pbm header
  254.      */
  255.  
  256.     while ( (c = getc(fax)) != EOF ) {
  257.  
  258.     /*
  259.      * Five EOL's mark the end of the data even though
  260.      * this might not be the end of the file.
  261.      */
  262.  
  263.     if ( c == EOL ) {
  264.         if ( ++eol_count == 5 ) {
  265.         /*
  266.          * Done.
  267.          */
  268.         return;
  269.         }
  270.     } else eol_count = 0;
  271.  
  272.     switch ( c ) {
  273.     case EOL:
  274.         EndOfLine(out);
  275.         if ( debug ) fprintf(stderr, "End of line\n");
  276.         
  277.         break;
  278.     case WHITELINE:
  279.         RunLenOut( FAXWIDTH, FAXWHITE );
  280.         if ( debug ) fprintf(stderr, "White line\n");
  281.         EndOfLine(out);
  282.         break;
  283.     default:
  284.  
  285.         if ( c >= 128 && c <= 255 ) {
  286.         /*
  287.          * byte encoded value.
  288.          * 1-bits indicate 'white'
  289.          */
  290.  
  291.         if ( debug ) fprintf(stderr, "Byte encoded: 0x%x\n", c);
  292.         ByteEncoded(c);
  293.  
  294.         /*
  295.          * "A pixel token is always followed by a single-byte token
  296.          *  of matching color (matches the last bit)"
  297.          */
  298.         
  299.         pixel = c & 1;
  300.         } else if ( c >= 1 && c <= 104 ) {
  301.         
  302.         rl = RunLength[c];
  303.         if ( c > 64 ) {
  304.             rl += RunLength[ getc(fax) ];
  305.         }
  306.  
  307.         if ( debug ) fprintf(stderr,"RunLen(%d, %d)\n", rl, pixel);
  308.         RunLenOut( rl, pixel );
  309.         pixel = 1 - pixel;
  310.         }
  311.  
  312.         break;
  313.         
  314.     }
  315.     }
  316.     
  317.  
  318. }
  319.  
  320. /*
  321.  * The idea here is that we gradually accumulate an entire scanline of bits,
  322.  * and then actually write it out via EndOfLine()
  323.  */
  324.  
  325. int byte = 0;
  326. int bitnum = 7;
  327. char line[FAXWIDTH / 8];    /* array of bits */
  328.  
  329. EndOfLine(out)
  330. FILE *out;
  331. {
  332.     int i;
  333.     pixel = FAXWHITE;
  334.     WriteLine(out);
  335.     ++linecount;
  336.  
  337.     /*
  338.      * If we're fixing the aspect ratio and this image was
  339.      * originally 100x200 resolution, write the line twice
  340.      * so that the resulting PBM file is squarish.
  341.      */
  342.     if ( header.resolution == 0 && fix_aspect ) {
  343.     ++linecount;
  344.     WriteLine(out);
  345.     }
  346.     if ( debug ) {
  347.     if ( linecount % 10 == 0 ) 
  348.         fprintf(stderr, "%d\n", linecount);
  349.     }
  350.     byte = 0;
  351.     bitnum = 0;
  352.  
  353.     for ( i = 0; i < sizeof(line); i++ )
  354.     line[i] = 0;
  355.  
  356. }
  357.  
  358. /*
  359.  * Decode all the bits in a byte encoded value, and set some pixels
  360.  */
  361. ByteEncoded(c)
  362. register int c;
  363. {
  364.     register int bitpos;
  365.  
  366.     for ( bitpos = 6; bitpos >= 0; bitpos-- ) {
  367.     Pixout( (c & (1 << bitpos)) >> bitpos );
  368.     }
  369. }
  370.  
  371.  
  372.  
  373. /*
  374.  * PBM type 1 files aren't supposed to have long lines so we
  375.  * truncate them periodically.
  376.  */
  377. #define MAXPBMWIDTH 60
  378.  
  379. /*
  380.  * write out the current scanline line[] in the appropriate format.
  381.  */
  382. WriteLine(out)
  383. FILE *out;
  384. {
  385.     int byte;
  386.     int bit;
  387.     int linewidth = 0;
  388.     if ( pbm_format == 1 ) {
  389.  
  390.     for ( byte = 0; byte < sizeof(line); byte++ ) {
  391.         for ( bit = 7; bit >= 0; bit-- ) {
  392.         if ( line[byte] & ( 1<<bit) ) {
  393.             putc( '1',out);
  394.         } else {
  395.             putc('0',out);
  396.         }
  397.         putc(' ',out );
  398.         linewidth += 2;
  399.         if ( linewidth > MAXPBMWIDTH ) {
  400.             putc('\n',out);
  401.             linewidth = 0;
  402.         }
  403.         }
  404.     }
  405.     } else {
  406.     
  407.     /*
  408.      * just output the raw bits.
  409.      */
  410.     fwrite( line, sizeof(line), 1, out);
  411.     }
  412. }
  413.  
  414. /*
  415.  * output the next pixel (actually just set the appropriate bit in the
  416.  * line array
  417.  */
  418. Pixout( c ) 
  419. register int c;
  420. {
  421.  
  422.     if ( c == FAXBLACK ) {
  423.     line[byte] |= ( 1<<bitnum );
  424.     }
  425.     if ( --bitnum < 0 ) {
  426.     bitnum = 7;
  427.     byte++;
  428.     }
  429. }
  430.  
  431.  
  432.  
  433. /*
  434.  * output a run length worth of pixels
  435.  */
  436. RunLenOut( rl, p )
  437. register int rl;
  438. register int p;
  439. {
  440.     while ( rl-- ) 
  441.     Pixout(p);
  442. }
  443.