home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
-
- /*
- * cpctopbm
- * convert "Complete PC" messages to PBM format.
- * This has only been tested on Complete PC Fax files, though.
- * with some work it could also work with other Complete PC files
- * (e.g. formats 2 and 3, "Complete Hand Scanner" and "Complete PC Scanner"
- * formats) but I don't have any of those to test out.
- *
- * Steve Hayman
- * sahayman@cs.indiana.edu
- * 90/10/10
- */
-
- /*
- * see the README file for a description of the header and
- * file format
- */
-
- struct cpc_header {
- unsigned char magic[4];
- short hour, min, sec;
- short month, day, wday, year;
-
- char reserved_1[ 77 - 18 + 1 ];
- char resolution;
- char picture_start;
-
- char reserved_2[ 99 - 80 + 1];
- };
-
- struct cpc_header header;
- int debug = 0;
- int verbose = 0;
- char *Pname;
- int linecount = 0;
-
- #define FAXBLACK 0
- #define FAXWHITE 1
-
- #define FAXWIDTH 1728
-
- int pbm_format = 4;
- int fix_aspect = 1;
-
-
-
- #define EOL 0x69
- #define WHITELINE 0x7f
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- int c;
- extern int optind, opterr;
- extern char *optarg;
- int errflg = 0;
-
- char *filename;
- FILE *fax;
-
- char tmpname[32];
- FILE *tmp;
-
-
- Pname = argv[0];
-
- while ((c = getopt(argc, argv, "dvap:")) != EOF) {
- switch (c) {
- case 'a':
- fix_aspect = 0;
- break;
- case 'd':
- debug++;
- break;
- case 'p':
- pbm_format = atoi(optarg);
- break;
- case 'v':
- verbose++;
- break;
- default:
- errflg++;
- }
- }
-
-
- if ( optind == argc ) {
- fax = stdin;
- filename = "stdin";
- } else if ( optind == argc - 1 ) {
-
- filename = argv[optind];
- if ( (fax = fopen(filename, "r")) == NULL ) {
- fprintf(stderr, "%s: Can't open ");
- perror(filename);
- exit(1);
- }
- } else {
- errflg++;
- }
-
- if (errflg) {
- fprintf (stderr, "%s: Usage: %s [-p pbm-format] [-a] [-v] [-d] [cfax-file]\n", Pname, Pname);
- exit(2);
- }
-
- init_runlength_table();
-
- /*
- * Read the header.
- */
-
- if ( fread((char *)&header, sizeof(header), 1, fax) != 1 ) {
- fprintf(stderr, "%s: could not read header\n", Pname);
- exit(1);
- }
-
- /*
- * Magic number must be 80 01 40 02.
- */
-
-
- if ( header.magic[0] != 0x80
- || header.magic[1] != 0x01
- || header.magic[2] != 0x40
- || header.magic[3] != 0x02 ) {
-
- fprintf(stderr, "%s: file '%s' format not recognized\n",
- Pname, filename);
- exit(1);
- }
-
- if ( verbose ) {
- fprintf(stderr, "File: %s\nReceived: %d/%d/%d %d:%02d:%02d\n",
- filename,
- header.year, header.month, header.day,
- header.hour, header.min, header.sec );
- fprintf(stderr, "Resolution: %s\n",
- header.resolution == 0 ? "100x200" : "200x200" );
- }
- /*
- * Open scratch file.
- * We'll rewind this later and schlep it to stdout.
- */
-
- strcpy(tmpname, "/tmp/pbm.XXXXXX");
- mktemp(tmpname);
-
- if ( (tmp = fopen(tmpname, "w+")) == NULL ) {
- fprintf(stderr, "%s: can't create temp file ", Pname);
- perror(tmpname);
- exit(1);
- }
-
- /*
- * Slimy manouevre to make sure tmp file goes away when
- * program exits
- */
- unlink(tmpname);
-
- /*
- * Gobble one more EOL
- */
- if ( getc(fax) != EOL ) {
- fprintf(stderr,"%s: file format error, 'EOL' after header missing\n");
- exit(1);
- }
- /*
- * Now read and write the rest.
- */
-
- cfaxtopbm(fax, tmp);
-
- /*
- * OK, rewind, fill in correct values of header,
- * schlep it to stdout
- */
-
- fseek(tmp, 0L, 0);
-
- /*
- * Now write the header to stdout
- * Compensate for the four bogus EOL's at the end of the file.
- */
-
- /*
- * Add a few useful comments to the pbm header, since they're
- * in the fax header anyway.
- */
-
- printf( "P%d\n", pbm_format);
- printf( "# Converted from CPC-format fax file '%s'\n", filename);
- printf( "# received: %d %d %d %d:%02d:%02d\n",
- header.year, header.month, header.day,
- header.hour, header.min, header.sec );
-
- linecount -= 4;
- if ( header.resolution == 0 && fix_aspect ) {
- linecount -= 4; /* we've been counting them twice */
- }
- printf("%d %d\n", FAXWIDTH, linecount);
- /*
- * Now copy the tmp file.
- */
-
- while ( (c = getc(tmp)) != EOF ) {
- putchar(c);
- }
-
-
- if ( verbose ) {
- fprintf(stderr, "%d lines\n", linecount);
- }
- exit(0);
- }
-
- /*
- * RunLength[i] is the length of a run of pixels encoded by the
- * byte value 'i'.
- */
-
- int RunLength[128];
-
- init_runlength_table()
- {
- int i;
-
- for ( i = 1; i <= 64; i++ )
- RunLength[i] = i - 1;
-
- for ( i = 65; i <= 104; i++ ) {
- RunLength[i] = (i - 64) * 64;
- }
- }
-
-
- int pixel = FAXWHITE;
-
- cfaxtopbm(fax, out)
- FILE *fax;
- FILE *out;
- {
-
- int c;
- int rl;
-
- int eol_count = 0;
-
- /*
- * pbm header
- */
-
- while ( (c = getc(fax)) != EOF ) {
-
- /*
- * Five EOL's mark the end of the data even though
- * this might not be the end of the file.
- */
-
- if ( c == EOL ) {
- if ( ++eol_count == 5 ) {
- /*
- * Done.
- */
- return;
- }
- } else eol_count = 0;
-
- switch ( c ) {
- case EOL:
- EndOfLine(out);
- if ( debug ) fprintf(stderr, "End of line\n");
-
- break;
- case WHITELINE:
- RunLenOut( FAXWIDTH, FAXWHITE );
- if ( debug ) fprintf(stderr, "White line\n");
- EndOfLine(out);
- break;
- default:
-
- if ( c >= 128 && c <= 255 ) {
- /*
- * byte encoded value.
- * 1-bits indicate 'white'
- */
-
- if ( debug ) fprintf(stderr, "Byte encoded: 0x%x\n", c);
- ByteEncoded(c);
-
- /*
- * "A pixel token is always followed by a single-byte token
- * of matching color (matches the last bit)"
- */
-
- pixel = c & 1;
- } else if ( c >= 1 && c <= 104 ) {
-
- rl = RunLength[c];
- if ( c > 64 ) {
- rl += RunLength[ getc(fax) ];
- }
-
- if ( debug ) fprintf(stderr,"RunLen(%d, %d)\n", rl, pixel);
- RunLenOut( rl, pixel );
- pixel = 1 - pixel;
- }
-
- break;
-
- }
- }
-
-
- }
-
- /*
- * The idea here is that we gradually accumulate an entire scanline of bits,
- * and then actually write it out via EndOfLine()
- */
-
- int byte = 0;
- int bitnum = 7;
- char line[FAXWIDTH / 8]; /* array of bits */
-
- EndOfLine(out)
- FILE *out;
- {
- int i;
- pixel = FAXWHITE;
- WriteLine(out);
- ++linecount;
-
- /*
- * If we're fixing the aspect ratio and this image was
- * originally 100x200 resolution, write the line twice
- * so that the resulting PBM file is squarish.
- */
- if ( header.resolution == 0 && fix_aspect ) {
- ++linecount;
- WriteLine(out);
- }
- if ( debug ) {
- if ( linecount % 10 == 0 )
- fprintf(stderr, "%d\n", linecount);
- }
- byte = 0;
- bitnum = 0;
-
- for ( i = 0; i < sizeof(line); i++ )
- line[i] = 0;
-
- }
-
- /*
- * Decode all the bits in a byte encoded value, and set some pixels
- */
- ByteEncoded(c)
- register int c;
- {
- register int bitpos;
-
- for ( bitpos = 6; bitpos >= 0; bitpos-- ) {
- Pixout( (c & (1 << bitpos)) >> bitpos );
- }
- }
-
-
-
- /*
- * PBM type 1 files aren't supposed to have long lines so we
- * truncate them periodically.
- */
- #define MAXPBMWIDTH 60
-
- /*
- * write out the current scanline line[] in the appropriate format.
- */
- WriteLine(out)
- FILE *out;
- {
- int byte;
- int bit;
- int linewidth = 0;
- if ( pbm_format == 1 ) {
-
- for ( byte = 0; byte < sizeof(line); byte++ ) {
- for ( bit = 7; bit >= 0; bit-- ) {
- if ( line[byte] & ( 1<<bit) ) {
- putc( '1',out);
- } else {
- putc('0',out);
- }
- putc(' ',out );
- linewidth += 2;
- if ( linewidth > MAXPBMWIDTH ) {
- putc('\n',out);
- linewidth = 0;
- }
- }
- }
- } else {
-
- /*
- * just output the raw bits.
- */
- fwrite( line, sizeof(line), 1, out);
- }
- }
-
- /*
- * output the next pixel (actually just set the appropriate bit in the
- * line array
- */
- Pixout( c )
- register int c;
- {
-
- if ( c == FAXBLACK ) {
- line[byte] |= ( 1<<bitnum );
- }
- if ( --bitnum < 0 ) {
- bitnum = 7;
- byte++;
- }
- }
-
-
-
- /*
- * output a run length worth of pixels
- */
- RunLenOut( rl, p )
- register int rl;
- register int p;
- {
- while ( rl-- )
- Pixout(p);
- }
-